- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi everybody,
I have a dll that is compiled withFORTRAN11, when it is loaded from C# program (not during debug, the problem is afterinstall the programs )C# program correctly load the DLL without any path and only by namebecauseboth of them are in the same directory.
but during the run ofFORTRANDLL, current path in the DLL is not same as position of that DLL is there and I can not load another file from the FORTRANDLL.
Is there any function to find the correct path (the directory of DLL), I cheked the "getcwd" and it gives the another path that is wrongcurrentpath.
Ihanks
Link Copied
13 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello
A dll is searched first in the directory than contains the executable that wants to load it. So if your DLL is in the same directory it will be found.
But the getcwd function retrieves the current working directory that can be different from the DLL location directory.
If you want to retrieve the path of the DLL, you can use the GetModuleFileName API function that will return the full path of the DLL.
A dll is searched first in the directory than contains the executable that wants to load it. So if your DLL is in the same directory it will be found.
But the getcwd function retrieves the current working directory that can be different from the DLL location directory.
If you want to retrieve the path of the DLL, you can use the GetModuleFileName API function that will return the full path of the DLL.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks I checked theGetModuleFileName it is OK.
Usedfwin
CHARACTER*1024 ::
DLLPath
DLLPath = ''
N = GetModuleFileName(0, DLLPath, len(DLLPath))
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
GetModuleFileName with 0 handle returns the path to the executable that started the current process.
Current directory (getcwd) can be pretty much any directory, as set up by the program shortcut, or changed by the user in the UI.
OPEN statement, however, by default opens the file in the current directory.
In order to a) open the file in the same directory as the exe and b) not to change the current directory (which is generally a bad practice to do from code), find the first path and open file there explicitly:
Current directory (getcwd) can be pretty much any directory, as set up by the program shortcut, or changed by the user in the UI.
OPEN statement, however, by default opens the file in the current directory.
In order to a) open the file in the same directory as the exe and b) not to change the current directory (which is generally a bad practice to do from code), find the first path and open file there explicitly:
[fortran]CHARACTER(MAX_PATH) :: DLLPath integer:: dirLen DLLPath = '' N = GetModuleFileName(0, DLLPath, len(DLLPath)) !Strip the path up to the trailing backslash: dirLen = index(Dllpath, "", .true.) DLLPath = DLLPath(1:dirLen) OPEN(42, file=TRIM(DLLPath)//"MyFile.txt") ...[/fortran]
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jugoslav,
once a DLL has been opened, is it possible to find out the directory it was loaded from?
As you say, GetModuleFileName returns the Executable (Excel) in my case. I would like to know which DLL(s) are actually being loaded at runtime, in part to check that the correct version of the code is in use.
Thanks,
David
once a DLL has been opened, is it possible to find out the directory it was loaded from?
As you say, GetModuleFileName returns the Executable (Excel) in my case. I would like to know which DLL(s) are actually being loaded at runtime, in part to check that the correct version of the code is in use.
Thanks,
David
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Quoting David White
Jugoslav,
once a DLL has been opened, is it possible to find out the directory it was loaded from?
once a DLL has been opened, is it possible to find out the directory it was loaded from?
Yes, if you give GetModuleFileName a correct handle (HMODULE/HINSTANCE). There are two ways to do it:
- By writing a DllMain and storing its hinstDll argument into a common/module variable, and
- The following should also work. The slight drawback is that you must know your .dll name in advance (thus, won't reliably work in .e.g. a .lib):
[fortran]integer(HANDLE):: hDll character(MAX_PATH):: path hDll = GetModuleHandle("MyDll.dll"//char(0)) len = GetModuleFileName(hDll, path, len(path)) !Returns the full path now[/fortran]
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
[fortran]MODULE DLLUtils USE IFWINTY IMPLICIT NONE PRIVATE PUBLIC :: GetThisDLLsFileName INTERFACE FUNCTION GetModuleHandleEx(dwFlags, lpModuleName, phModule) !DEC$ ATTRIBUTES DEFAULT, STDCALL, DECORATE, ALIAS:'GetModuleHandleExA' :: GetModuleHandleEx USE ISO_C_BINDING, ONLY: C_FUNPTR USE IFWINTY IMPLICIT NONE INTEGER(DWORD), INTENT(IN), VALUE :: dwFlags TYPE(C_FUNPTR), INTENT(IN), VALUE :: lpModuleName INTEGER(HANDLE), INTENT(OUT) :: phModule !DEC$ ATTRIBUTES REFERENCE :: phModule INTEGER(BOOL) :: GetModuleHandleEx END FUNCTION GetModuleHandleEx END INTERFACE INTEGER(DWORD), PARAMETER :: GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS & = 4_DWORD CONTAINS SUBROUTINE GetThisDLLsFileName(filename) !DEC$ ATTRIBUTES DLLEXPORT :: GetThisDLLsFileName USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_FUNLOC USE IFWIN !---- CHARACTER(:), INTENT(OUT), ALLOCATABLE :: filename !---- INTEGER(BOOL) :: rc INTEGER(HANDLE) :: my_handle INTEGER(DWORD) :: buf_len INTEGER(DWORD) :: str_len !**** rc = GetModuleHandleEx( & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, & C_FUNLOC(AnExportedProcedure), & my_handle ) ! should test rc, but I'm lazy... buf_len = 256_DWORD DO ALLOCATE(CHARACTER(buf_len) :: filename) str_len = GetModuleFilename(my_handle, filename, buf_len) IF (str_len < buf_len) THEN ! choppity by reallocation filename = filename(1:str_len) RETURN END IF ! buffer too small, double and try again... buf_len = buf_len * 2 DEALLOCATE(filename) END DO END SUBROUTINE GetThisDLLsFileName SUBROUTINE AnExportedProcedure() BIND(C) !DEC$ ATTRIBUTES DLLEXPORT :: AnExportedProcedure END SUBROUTINE END MODULE DLLUtils [/fortran]
and to test...
[fortran]PROGRAM DLLUtilsTest USE DLLUtils IMPLICIT NONE !--- CHARACTER(:), ALLOCATABLE :: dll_name !**** ! ifort bug requires this to be allocated on entry?? ALLOCATE(CHARACTER(1) :: dll_name) CALL GetThisDLLsFileName(dll_name) PRINT "(A)", dll_name END PROGRAM DLLUtilsTest[/fortran]
might need /assume:realloc_lhs to work.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Aother solution would be to add a DllMain routine to your project. This routine is called each time the DLL is loaded and attached to a process or a thread. The routine has the handle of the dll as the first argument so you can retrieve the path of the dll from the GetModuleFileName API function.
This the way I proceed frequently:
Then in the main unit, you can retrieve the handle and call the GetModuleFileName API function, in the example below it is used to retrieve the full dll path in order to access the dll resources and particularly the dll version information:
Note that "GetVersionInfoString" is a function I have created to retrieve the version information from the DLL resources thus it is not part of the Windows API.
Regards,
Phil.
This the way I proceed frequently:
[fxfortran] integer(4) function DllMain(hInst, ul_reason_being_called, lpReserved) !DEC$ IF DEFINED(_X86_) !DEC$ ATTRIBUTES STDCALL, ALIAS : '_DllMain@12' :: DllMain !DEC$ ELSE !DEC$ ATTRIBUTES STDCALL, ALIAS : 'DllMain' :: DllMain !DEC$ ENDIF use DFWINA integer(4) hInst integer(4) ul_reason_being_called integer(4) lpReserved C integer(4) hDLL common /DLL_Handle/ hDLL C hDLL = hInst C ul_reason_being_called = ul_reason_being_called lpReserved = lpReserved C DllMain = 1 return C end [/fxfortran]
Then in the main unit, you can retrieve the handle and call the GetModuleFileName API function, in the example below it is used to retrieve the full dll path in order to access the dll resources and particularly the dll version information:
[fxfortran]C integer(4) hDLL common /DLL_Handle/ hDLL C character(len=256) DLL_Name, VERS_INFO C integer(4) n C n = GetModuleFileName(hDLL, DLL_Name, sizeof(DLL_Name)) if (n /= 0) then call GetVersionInfoString(DLL_Name, VERS_INFO) else VERS_INFO = 'N/A' end if [/fxfortran]
Note that "GetVersionInfoString" is a function I have created to retrieve the version information from the DLL resources thus it is not part of the Windows API.
Regards,
Phil.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Phil,
Tried your method in my situation where I am loading a DLL from Excel via VBA. Like the other methods I have tried, this still returns the name of the exe (Excel) in DLL_Name, rather than the DLL.
David
Tried your method in my situation where I am loading a DLL from Excel via VBA. Like the other methods I have tried, this still returns the name of the exe (Excel) in DLL_Name, rather than the DLL.
David
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
David.
I am surprised that it doesn't work because I have tried the same thing, i.e. a Fortran dll declared in VBA to use some exported routines (in my example I was using IMSL routines to perform cubic spline interpolation in Excel). In my Fortran dll I have added the Dllmain function as above and when I call the GetModuleFileName using the "hInst" handle passed by argument in DllMain the results is the full path to the dll so I don't understand what is going wrong in your case.
Regards,
Phil.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Here's how I've been doing it:
ghinstance=GetModuleHandle("EnergyPlusDLL.dll"C)
ret = GetModuleFileName (INT(ghInstance), szFullPath, len(szFullPath))
I am currently challenged, however, to get the Version info from 64 bit compiles, so if the above works for you I would be grateful for any assistance in working out the version info.
Linda
ghinstance=GetModuleHandle("EnergyPlusDLL.dll"C)
ret = GetModuleFileName (INT(ghInstance), szFullPath, len(szFullPath))
I am currently challenged, however, to get the Version info from 64 bit compiles, so if the above works for you I would be grateful for any assistance in working out the version info.
Linda
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Linda,
Here is the GetFileVersionInfo source code. I hope it will work in 64 bit (I do compile only 32 bit executables):
[fortran] subroutine GetVersionInfoString(EXE_Name, VERSION_INFO) use DFWIN implicit none character(len=*), intent(in) :: EXE_Name character(len=*), intent(out) :: VERSION_INFO ! Retrieving the version information from an executable or dll integer(4) Hndl integer(4) nBytes integer(4) rc character(len=256) StringInfo character(len=10) CharSet integer(4) uVersionLen, uTranslationLen integer(4) lpstrVffInfo integer(4) hMem integer(4) i character(len=256) lpversion integer(1) lpTranslation(256) integer(4) lplpTranslation, lplpVersion pointer(lplpTranslation, lpTranslation) pointer(lplpVersion, lpversion) nBytes = GetFileVersionInfoSize(EXE_Name, loc(Hndl)) if (nBytes /= 0) then ! Allocating the required memory bloc hMem = GlobalAlloc(GMEM_MOVEABLE, int(nBytes)) lpstrVffInfo = GlobalLock(hMem) ! Retrieving the information bloc rc = GetFileVersionInfo(EXE_Name, Hndl, nBytes, lpstrVffInfo) ! Retrieving the code page StringInfo = "\VarFileInfo\Translation"C rc = VerQueryValue(lpstrVffInfo, StringInfo, lplpTranslation, loc(uTranslationLen)) ! Retrieving the version information string write(CharSet,'(4z2.2)') lpTranslation(2),lpTranslation(1),lpTranslation(4),lpTranslation(3) StringInfo = '\StringFileInfo'//trim(CharSet)//'\FileVersion'C rc = VerQueryValue(lpstrVffInfo, StringInfo, lplpVersion, loc(uVersionLen)) ! Decoding if (rc /= 0) then rc = lstrcpy(VERSION_INFO, lpVersion) uVersionLen = min(uVersionLen,index(VERSION_INFO,char(0))) do i=uVersionLen,len(VERSION_INFO) VERSION_INFO(i:i) = ' ' end do else VERSION_INFO = 'N/A' end if ! Freeing the allocated memory bloc rc = GlobalUnlock(hMem) rc = GlobalFree(hMem) else ! Version information unavailable or not found VERSION_INFO = 'N/A' end if return end [/fortran]
Regards,
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you, Phill -- I will give this a try.
Linda
Linda
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The handles (hMem, etc.) should be declared INTEGER(HANDLE). The "lp" variables should be INTEGER(LPVOID).

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