- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I need to break a library of functions into a number of separate dlls.
How do I call a dll from within a dll?
Can I do it within the same solution?
Do I need to specify a library for the linker?
Current attempt:
!DEC$ ATTRIBUTES DLLEXPORT::G_Trend
!DEC$ ATTRIBUTES ALIAS:'G_Trend' :: G_Trend
!DEC$ ATTRIBUTES DLLIMPORT, ALIAS: 'G_Filter' ::G_Filter
( blah, blah, blah)
Call G_Filter(pdlen, lg, psh, lnc, tmp1)
gives the error
>G_Trend.obj : error LNK2019: unresolved external symbol __imp_G_Filter referenced in function G_Trend
2>Debug\G_Trend.dll : fatal error LNK1120: 1 unresolved externals
The G_Filter function compiles and works great.( Tested by calling with netlink in mathematica)
G_Filter and G_Trend are in different projects under the same solution.
Thanks
Frank
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
the sample code "DLL" - file DynamicLoad.f90 - installed with the compiler may be helpful - it shows hows to load a DLL and access the functions in it.
David
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
There's no problem calling one DLL from another - it's done all the time. Assuming you want to resolve this at link time, just link the DLL to the export library of the other DLL(s), exactly as you would for linking an executable to DLLs.
David's suggestion is a more complex approach for dynamic loading - it doesn't sound as if you need that.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for the help.
I decided to try David's method first as it looks like it could be useful in the future.
The current problem is that .net can't find the dll.
The error message is " A .NET exception occurred: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. at Wolfram.NETLink.DynamicDLLNamespace.DLLWrapper1.G_Trend(Int32& , Double[] , Double[] )."
I don't think the error is in the way I am call the dll.
So what am I doing in this code that prevents it from being called?
subroutine G_Trend(pdlen, pdata, acc)
use kernel32 ! Declares Windows API routines
use, intrinsic :: iso_c_binding
IMPLICIT NONE
!DEC$ ATTRIBUTES DLLEXPORT::G_Trend
!DEC$ ATTRIBUTES ALIAS:'G_Trend' :: G_Trend
abstract interface
subroutine G_Filter_void(pdlen0, lag0, lead0, pdata0, fdata0)
integer(4), intent(IN) :: pdlen0
integer(4), intent(IN) :: lag0
integer(4), intent(IN) :: lead0
real(8), dimension(pdlen0), intent(IN) :: pdata0
real(8), dimension(pdlen0), intent(INOUT) :: fdata0
end subroutine G_Filter_void
end interface
procedure(G_Filter_void), pointer :: G_Filter
integer(C_INTPTR_T) :: p_G_Filter
integer(HANDLE) :: dll_handle
integer(BOOL) :: free_status
integer(4), intent(IN) :: pdlen
real(8), dimension(pdlen), intent(IN) :: pdata
real(8), dimension(pdlen), intent(INOUT) :: acc
integer(4) :: lg, psh
real(8), dimension(pdlen) :: lnc
real(8), dimension(pdlen) :: ldc
real(8), dimension(pdlen) :: tmp1
dll_handle = LoadLibrary (lpLibFileName="G_Filter.dll"//C_NULL_CHAR)
p_G_Filter = GetProcAddress (hModule=dll_handle, lpProcName="G_Filter"//C_NULL_CHAR)
call C_F_PROCPOINTER (TRANSFER(p_G_Filter, C_NULL_FUNPTR), G_Filter)
lnc = DLOG(pdata)
tmp1 = 0.0
acc = 0.0
lg = 1
psh = 0
Call G_Filter(pdlen, lg, psh, lnc, tmp1)
free_status = FreeLibrary (hLibModule=dll_handle)
return
end subroutine G_Trend
Again, Thanks for the help. If I can't make this work, I'll try Steve's suggestion.
Frank
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Your code looked fine to me, I added a G_Filter dll and a main program to invoke G_Trend and put in a couple of write statements to check that everything was going OK, and it all seemed to work. Output:
dll_handle = 140729806094336 GetLastError() = 0 p_G_Filter = 140729806098432 GetLastError() = 0 Called G_Filter
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Frank_M wrote:
...
The current problem is that .net can't find the dll.
The error message is " A .NET exception occurred: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. at Wolfram.NETLink.DynamicDLLNamespace.DLLWrapper1.G_Trend(Int32& , Double[] , Double[] )."
I don't think the error is in the way I am call the dll.
So what am I doing in this code that prevents it from being called?
...
Can you show the relevant sections of your .NET code i.e., where you prototype the G_Trend procedure and where you call it?
Why do say, "The current problem is that .net can't find the dll"? Have you confirmed you're getting a zero value for the dll_handle in G_Trend? If you think the execution is making it ok to G_trend and something is amiss therein, then here're some suggestions:
- Following your call to LoadLibrary procedure, you should check for the dll_handle return value and only proceed if it is not zero. If it is zero, then it is confirmation the DLL was not found or it could not be loaded.
- For the "not found" situation, check your PATH and ensure the DLL is indeed present in the path
- For the "could not loaded" possibility, run your DLL through a dependency check utility such as DependencyWalker (www.dependencywalker.com) and see what other DLLs are required by the one in question and whether they are all available on the path.
- If dll_handle is non-zero (usually greater than zero), then check p_G_Filter return value from GetProcAddress and again only proceed to the next step if it is not zero. If it is zero, then check whether the G_Filter procedure is exported correctly from the DLL.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The dll is called using netlink in Mathematica.
Here is the code:
Needs["NETLink`"] ReinstallNET["Force32Bit" -> True]; libName = "C:\\Users\\FrankM\\Documents\\Visual Studio\2012\\Projects\\G_Trend\\G_Trend\\Debug\\G_Trend.dll"; FileExistsQ[libName] >True TestSubroutine = DefineDLLFunction["G_Trend", libName, "void", {"int*", "Double[]", "Double[]"}] >Function[Null,If[NETLink`DLL`Private`checkArgCount["G_Trend", {##1}, 3], Wolfram`NETLink`DynamicDLLNamespace`DLLWrapper1`GUTrend[##1],$Failed], {HoldAll}] Clear; Clear[date]; {date, c} = Transpose[FinancialData["GE", "Jan. 1, 2013"]]; pdlen = Length ; fdata = MakeNETObject[Evaluate[Table[0.0, {pdlen}]]]; TestSubroutine[pdlen, c, fdata] >NET::netexcptn: A .NET exception occurred: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. at Wolfram.NETLink.DynamicDLLNamespace.DLLWrapper1.G_Trend(Int32& , Double[] , Double[] ). $Failed out = NETObjectToExpression[fdata];
Given Repeat Offender's test (Thank You, I should have thought of that) the error must be in the calling.
The above code worked for calling the dll G_Filter.
Needs["NETLink`"] ReinstallNET["Force32Bit" -> True];(*or InstallNET["Force32Bit"\[Rule]True]*) libName = "C:\\Users\\FrankM\\Documents\\Visual Studio\2012\\Projects\\G_Filter\\G_Filter\\Debug\\G_Filter.dll"; FileExistsQ[libName] >True TestSubroutine = DefineDLLFunction["G_Filter", libName, "void", {"int*", "int*", "int*", "Double[]", "Double[]"}] >Function[Null,If[NETLink`DLL`Private`checkArgCount["G_Filter", {##1}, 5], Wolfram`NETLink`DynamicDLLNamespace`DLLWrapper1`GUFilter[##1],$Failed], {HoldAll}] Clear; Clear[date]; {date, c} = Transpose[FinancialData["IBM", "Jan. 1, 2013"]]; pdlen = Length ; lag = 5; push = 5; pdata = c; fdata = MakeNETObject[Evaluate[Table[0.0, {pdlen}]]]; TestSubroutine[pdlen, lag, push, pdata, fdata] out = NETObjectToExpression[fdata];
There is a copy of G_Filter.dll in the G_Trend/Debug directory, so I would think windows would be able to find it.
Thanks guys. I'll first study and run Repeat Offenders Test using the actual G_Filter, then look into that Dependency Walker.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Microsoft's .NET languages give a misleading "DLL not found" error when the problem is that a dependent DLL is not found. Dependency Walker is definitely helpful in this case.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The interface to G_Filter in your Fortran example and that in your Mathematica example are inconsistent. In Mathematica you are forcing it to use a 32-bit dll (via ReinstallNET) where STDCALL is kind of an oddball calling convention which happens to be the default and then using this default in DefineDLLFunction. Your Fortran example doesn't specify a calling convention so unless a command-line switch is applied it won't be using STDCALL. I have modified my example so it will refuse to compile in 64-bit mode and set up subroutine G_Trend and its interface in program P so that the STDCALL calling convention will be used. Output when compiled with 32-bit ifort was similar to that seen in Quote #5.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Oh, and I should mention: if you are still having problems, do everything over exclusively in 64-bit mode so as to take STDCALL out of the equation. Once you get it running in 64-bit mode, then try to change over to 32-bit STDCALL. This will localize interfacing issues in smaller chunks.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
After including a console in G_Trend and adding write statements, windows cannot find G_Filter.dll with the complete path specified.
!works dll_handle = LoadLibrary (lpLibFileName="C:\Users\FrankM\Documents\Visual Studio 2012\Projects\G_Trend\G_Trend\Debug\G_Filter.dll"//C_NULL_CHAR) !Fails dll_handle = LoadLibrary (lpLibFileName="G_Filter.dll"//C_NULL_CHAR)
Is there an elegant solution beyond hard code?
In other news, Mathematica NetLink was not able to find G_Trend with Attribute set to StdCall or C. It likes the default unspecified C in 32bit.
Once again, big thank you to everyone for all the help, especially Repeat Offender for the samples.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Frank_M wrote:
After including a console in G_Trend and adding write statements, windows cannot find G_Filter.dll with the complete path specified.
!works dll_handle = LoadLibrary (lpLibFileName="C:\Users\FrankM\Documents\Visual Studio 2012\Projects\G_Trend\G_Trend\Debug\G_Filter.dll"//C_NULL_CHAR) !Fails dll_handle = LoadLibrary (lpLibFileName="G_Filter.dll"//C_NULL_CHAR)Is there an elegant solution beyond hard code?
..
See https://msdn.microsoft.com/en-us/library/7d83bc18.aspx for how Windows locates DLLs. If there is a particular folder in Mathematica for "user" DLLs where you can place G_Filter.dll? Or can you create a new folder for your DLLs and add it your PATH environment?

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page