OpenLibrary & windows\System32 directory

Windows specific forum
Motu
Enthusiast
Enthusiast
Posts: 160
Joined: Tue Oct 19, 2004 12:24 pm

OpenLibrary & windows\System32 directory

Post by Motu »

I had a strange bug concerning Librarys and it was taking a long time until I found the problem.

Code: Select all

; Dll Function
ProcedureDLL XXL()
 MessageRequester("Old","",0)
EndProcedure
Do the following steps:

1. Compile the DLL procedure to a DLL called Message.dll
2. copy this file to the Windows\System32 directory
3. Replays the word "Old" with "New"
4. compile a second dll also called message.dll

Now write this program in the folder of the DLL (not the system32 directory of course!)

Code: Select all

; Program
Lib = OpenLibrary(#PB_Any,"Message.dll")
CallFunction(Lib,"XXL")
CloseLibrary(Lib)
compile the program and see: It will display "old". But it should not. Openlibrary should at first open the library from the program folder, not from the system32 folder.
Now create a .exe from the program code and run it. "new". Something seemse to be wrong here (either in PB or in Windows was to handle Dll calling).
ABBKlaus
Addict
Addict
Posts: 1143
Joined: Sat Apr 10, 2004 1:20 pm
Location: Germany

Post by ABBKlaus »

did you compile your test program to an exe or did you just hit comile from the ide :?:

Dynamic-Link Library Search Order
http://msdn2.microsoft.com/en-us/library/ms682586.aspx
Motu
Enthusiast
Enthusiast
Posts: 160
Joined: Tue Oct 19, 2004 12:24 pm

Post by Motu »

I did both (as written in the text) and both lead to different results.

your link simple says that this bahavior is wrong as well:

1. The directory from which the application loaded.

2. The current directory. <- Here even the simple compiled version should go to

3. The system directory. Use the GetSystemDirectory function to get the path of this directory.
freak
PureBasic Team
PureBasic Team
Posts: 5948
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Post by freak »

Its all up to the OS. PB just calls LoadLibrary() and thats it.
quidquid Latine dictum sit altum videtur
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Re: OpenLibrary & windows\System32 directory

Post by PB »

> Lib = OpenLibrary(#PB_Any,"Message.dll")

Just avoid the problem totally by putting the DLL in your app's folder and
calling it from there. This is how I'd do the above:

Code: Select all

myappdir$="C:\Blah\Blah\Blah\"
Lib = OpenLibrary(#PB_Any,myappdir$+"Message.dll")
Problem solved. You're the coder. Tell your app where to find it, instead of
letting Windows do it. IMO.
User avatar
tinman
PureBasic Expert
PureBasic Expert
Posts: 1102
Joined: Sat Apr 26, 2003 4:56 pm
Location: Level 5 of Robot Hell
Contact:

Post by tinman »

Motu wrote:I did both (as written in the text) and both lead to different results.
When you compile from the ide you usually get an executable created in the "Compilers" directory. So the directory for (1) would be e.g. "C:\Program Files\PureBasic\Compilers".

The compiler runs your executable (I think) so the current directory (2) would also be the "Compilers" directory. That is why when you run from the IDE your application does not find the "new" DLL.

I don't know if this has changed with PB 4.1, I guess it has because it is Vista compatible and you probably cannot write to the "Compilers" directory any more. In that case, it will be using your temporary directory. But the result is the same, the DLL will not be there.

(Maybe the DLL would appear there if you also run that source code from the IDE?)
If you paint your butt blue and glue the hole shut you just themed your ass but lost the functionality.
(WinXPhSP3 PB5.20b14)
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Re: OpenLibrary & windows\System32 directory

Post by Trond »

Try this to see where the exe is and what the current directory is:

Code: Select all

Debug GetCurrentDirectory()
Debug GetPathPart(ProgramFilename())
If the loaded dll actually IS from the windows directory it probably isn't in those directories.
Motu
Enthusiast
Enthusiast
Posts: 160
Joined: Tue Oct 19, 2004 12:24 pm

Post by Motu »

Thanks for all your replys :)

@Trond & tinman GetCurrentDirectory() returns the path that the application code is in, so that cannot be the problem.

@PB I know that is is a solution, anyway, for the problem I have this does not work. I call functions from the oggvorbisfile.dll. The dll it's self is calling the two dlls ogg.dll and vorbis.dll. But when they exist inside the system32 folder as well, these versions are loaded as well (and they may not be of the same version then the one that I need).

I guess I found the problem:

Windows XP and Windows 2000 SP4: Safe DLL search mode is disabled by default. To enable this feature, create the SafeDllSearchMode registry value and set it to 1.

If SafeDllSearchMode is enabled, the search order is as follows:

The directory from which the application loaded.
The system directory. Use the GetSystemDirectory function to get the path of this directory.
The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
The current directory.
The directories that are listed in the PATH environment variable. Note that this does not include the per-application path specified by the App Paths registry key.

If SafeDllSearchMode is disabled, the search order is as follows:

The directory from which the application loaded.
The current directory.
The system directory. Use the GetSystemDirectory function to get the path of this directory.
The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
The directories that are listed in the PATH environment variable. Note that this does not include the per-application path specified by the App Paths registry key.

So maybe the SafeDLLSearchMode is enabled somehow on my computer...

a workaround that works is to set the "Create temp exe in source dir" flag - but

PLEASE!!! PB TEAM move this option to the compiler option screen. You have to set it for all(!) include file and if you forget one you get strange errors when compiling from this include file...
User avatar
tinman
PureBasic Expert
PureBasic Expert
Posts: 1102
Joined: Sat Apr 26, 2003 4:56 pm
Location: Level 5 of Robot Hell
Contact:

Post by tinman »

Motu wrote:So maybe the SafeDLLSearchMode is enabled somehow on my computer...
It's enabled by default in XP SP2, so that's perhaps why.
If you paint your butt blue and glue the hole shut you just themed your ass but lost the functionality.
(WinXPhSP3 PB5.20b14)
Motu
Enthusiast
Enthusiast
Posts: 160
Joined: Tue Oct 19, 2004 12:24 pm

Post by Motu »

Okay, thanks for the information @tinman.

there is a function call "SetDllDirectory" found in the Kernel32.dll
http://msdn2.microsoft.com/en-us/library/ms686203.aspx

with this little trick everyone else having this problem can solve it :)

Code: Select all

 Lib_Kernel32 = OpenLibrary(#PB_Any,"Kernel32.dll")
 *SetDllDirectoryA = GetFunction(Lib_Kernel32,"SetDllDirectoryA")
 If *SetDllDirectoryA <> 0
  String.s = GetCurrentDirectory()
  CallFunctionFast(*SetDllDirectoryA,@String)
 EndIf
CloseLibrary(Lib_Kernel32)
Motu
Enthusiast
Enthusiast
Posts: 160
Joined: Tue Oct 19, 2004 12:24 pm

Uhh - no

Post by Motu »

painfully it does not solve the problem. Anyone has a idea why?
User avatar
tinman
PureBasic Expert
PureBasic Expert
Posts: 1102
Joined: Sat Apr 26, 2003 4:56 pm
Location: Level 5 of Robot Hell
Contact:

Re: Uhh - no

Post by tinman »

Motu wrote:painfully it does not solve the problem. Anyone has a idea why?
Seems like your code should work. Have you tried checking the value of GetLastError() after calling the function?

Edit: this code works for me. I used SetDllDirectoryW because I use unicode by default:

Code: Select all

Lib_Kernel32 = OpenLibrary(#PB_Any,"Kernel32.dll") 
*SetDllDirectory = GetFunction(Lib_Kernel32,"SetDllDirectoryW") 
 If *SetDllDirectory <> 0 
  String.s = GetCurrentDirectory() 
  Debug String
  result = CallFunctionFast(*SetDllDirectory,@String) 
  If result =0
    Debug Str(GetLastError_())
  EndIf
EndIf 
CloseLibrary(Lib_Kernel32)

If OpenLibrary(0, "dll_path.dll")
    CallFunction(0, "foo")
    CloseLibrary(0)
Else
    Debug "Could not find DLL"
EndIf
If you paint your butt blue and glue the hole shut you just themed your ass but lost the functionality.
(WinXPhSP3 PB5.20b14)
ABBKlaus
Addict
Addict
Posts: 1143
Joined: Sat Apr 10, 2004 1:20 pm
Location: Germany

Post by ABBKlaus »

you could have set to an invalid path ?

Code: Select all

Lib_Kernel32 = OpenLibrary(#PB_Any,"Kernel32.dll") 
If Lib_Kernel32
  CompilerIf #PB_Compiler_Unicode
    *GetDllDirectory = GetFunction(Lib_Kernel32,"GetDllDirectoryW")
    *SetDllDirectory = GetFunction(Lib_Kernel32,"SetDllDirectoryW")
  CompilerElse
    *GetDllDirectory = GetFunction(Lib_Kernel32,"GetDllDirectoryA")
    *SetDllDirectory = GetFunction(Lib_Kernel32,"SetDllDirectoryA")
  CompilerEndIf
  If *SetDllDirectory
    String.s = GetCurrentDirectory();+"makethepathinvalid"
    Debug String 
    result = CallFunctionFast(*SetDllDirectory,@String) 
    If result =0 
      Debug Str(GetLastError_()) ; note : an invalid path does not show up as error !
    EndIf 
  EndIf
  If *GetDllDirectory
    String.s=Space(#MAX_PATH)
    result = CallFunctionFast(*GetDllDirectory,#MAX_PATH,@String) 
    If result =0 
      Debug Str(GetLastError_()) 
    Else
      Debug String
    EndIf 
  EndIf
  CloseLibrary(Lib_Kernel32) 
EndIf

libname$="foo.dll"

Lib=OpenLibrary(#PB_Any,libname$)
If Lib
  String=Space(#MAX_PATH)
  hModule=GetModuleHandle_(libname$)
  If GetModuleFileName_(hModule,@String,#MAX_PATH)
    Debug String
  Else
    Debug Str(GetLastError_())
  EndIf
Else
  Debug "Lib not found"
EndIf
Post Reply