External exception is thrown in function when using DLL's from not application folder - delphi

I have a problem which I do not understand. I am using a DLL in my application. This DLL requires other DLL's and I have all of them. If I put the libraries in my appliction folder everything works fine.
However, having a bunch of DLLs in application folder looks quite ugly so I wanted to move them to application\lib subfolder.
After this change now I am getting External Exception when I try to use some of its functions.
I've only changed one line of code:
The original code
DLLHandle := LoadLibrary(Pchar(ExtractFilePath(ParamStr(0)) + 'External.dll'))
The code after change
DLLHandle := LoadLibrary(Pchar(ExtractFilePath(ParamStr(0)) + 'lib\External.dll'))
In both cases DLLHandle have a handle after loading the library. I am also not getting any error after calling GetProcAddress( DLLHandle, '_SomeFunction#8')
No exceptions, and return value of GetLastError is always 0.
Do you have any idea what could be wrong?
Thanks.

Life is far easier if you keep the DLLs in the same folder as the executable. That's the first folder searched when libraries are loaded. To move all the DLLs into a sub folder of the executable directory requires cooperation from all DLLs.
Most likely you have secondary DLL dependencies that are not cooperating. So exe loads A fine, but then A fails to load B. You can debug this further with Dependency Walker running in profile mode. It's quite possible that a secondary DLL is being loaded with implicit linking and that this throws and exception. Whatever the cause, Depenency Walker will lead you to the problem.
Whilst you can modify the PATH variable this is generally not advisable. If you do choose to go down this route then don't modify system wide, just modify the executable process environment at runtime before the first LoadLibrary. This is tenable so long as all your DLL linking is explicit using GetProcAddress.
All accepted wisdom recommends that you put your DLLs in the same folder as your executable. I would echo this recommendation. If you did this then you would be able to use implicit linking which would greatly simplify your code.
Yet another option may be to abandon DLLs and link everything straight into your executable. Unless you have a plugin type architecture, a single big exe is by far the simplest approach.

The other DLL's that need to be loaded must be on the system path for Windows to find them. Your application can find the External.dll as you explicitly define the path. Try adding the lib folder to your system path.

Related

How to force a dll to load from current directory

I have copied a newer version of GdiPlus.dll to my projects directory.
However windows always loads it form
"C:\WINDOWS\WinSxS\x86_Microsoft.Windows.GdiPlus_6595b64144ccf1df_1.0.6002.23084_x-ww_f3f35550\GdiPlus.dll"
I'm on XP.
To exert complete control over DLL loading, pass the full path of the DLL to LoadLibrary.
This is viable if you use runtime linking. For load time linking you are reliant on the DLL search order. The first thing searched is the directory from where the exe loaded. That said, it is plausible that for an OS component like GDI+ it is plausible that the system will use the SxS DLL no matter what.
Your question title says "current directory" but you never want to rely on the value of the current directory when linking DLLs. The current directory's value is unpredictable.
Finally, GDI+ is a system component and I think it doubtful that providing your own GDI+ DLL is a wise move. It is quite possibly illegal too since redistribution of GDI+ is not permitted. Perhaps you are choosing the wrong solution to your problem.
you can use this declaration to set the directory of dll to a defined path.
function SetDllDirectory(lpPathName:PWideChar): Bool; stdcall; external 'kernel32.dll' name 'SetDllDirectoryW';
remember to change the path after working with your dll.

debug delphi application / DLL called inside a thread

problem description :
..... ( this code is executed inside a thread.execute
...
if fileexists(myFile) then
begin
// call functions inside a DLL
...
dll_process_data ( .....) ;
....
end;
..... (clean up )
write_clean_data_fct(...)
..... //
... // AV happens here inside kernel.dll , no further information
If the file is not found the complete routine / multithreaded algos is executed without any problem; If i add the additional files some data is processed inside a dll, this is also done without trouble.
Somewhere after the write_clean_data_fct the AV happens now. INside the dll I open a file read data and do data processing with these data.
Q: what might be the reasin and how to debugg this issue ??
Can#t post more lines of code because the complete code sequence is ~ 15.000 LOC.
You can debug the DLL like this:
Open the DLL project in your IDE.
Make sure the host is going to load the DLL from the same path as your DLL project's output directory.
Set a break point on the function you wish to debug.
From the menu select Run | Host application and specify the host executable.
Run.
You should now be able to debug code in the DLL. In modern versions of Delphi, you should also be able to step into the DLL code when debugging the host executable. This requires you to have built the DLL with debug information, and for the host executable to load the DLL from the DLL project's output path.
Your actual problem sounds a little tricky. The access violation perhaps occurs long after the erroneous code executes. To debug that, you might first identify the code that raises the exception. Which part of that code has a pointer that could be invalid? Then track back to anything in the DLL that could have modified that pointer.
If static analysis does not help then you can add debugging tools. You'll want:
Range checking enabled to detect obvious buffer overruns.
Full FastMM debug to detect heap corruptions, access after free etc.
madExcept to give detailed diagnostics and stack traces for the actual exception.
You'll want these tools in all modules.

Collection of DLL's in another Designated Folder?

First of all, please forgive me for not knowing the proper terminology, I'm sure there's a very common technical name for this which I could simply Google for help - but I can't find help if I don't know the term to begin with.
I'm building a modular system in Delphi 7. There are a few applications and a bunch of DLL's. All the applications share these DLL's, as well as some of the DLL's use other DLL's. The DLL's are currently saved in the same location as the application. I would instead like to put all these DLL's in a sub-folder (elsewhere from the EXE's) but of course Delphi won't know how to find them.
Is there a way I can direct my Delphi Apps to look in a certain directory for DLL's? It can't be using Contstants, because there will be an option to specify where the DLL's are stored.
These DLL's are just a plain collection of StdCall functions in each, nothing special.
EDIT:
To explain the reason why I want to keep the DLL's in their own folder: This system I'm building considers these DLL's as add-ons. By default, the system might not even have any add-ons. On the other hand, it will also allow various vendors to build other DLL's and include them as add-ons. Then each application requiring these Add-ons will be directed to the folder where to find them.
The application its self will have its own DLL's which will be in the same directory as the applications. But the Vendors' DLL's I would like to keep separate.
As mentioned in the answers below, my best bet would be to implement the DLL Import method, because A) I can specify a path for each DLL it's importing, B) I can better control the use of each DLL (Does it need to be loaded or not?) and C) Each DLL can technically be in separate folders by themselves (Vendors might want to build their own folder structure). This system is still very pre-mature but I plan to make further flexibility with it.
If you are dynamically loading the DLLs in your code, you can store them whereever you want since you have to pass the full path to LoadLibrary/Ex() anyway. If you are statically linking to the DLLs instead, then you can use SetDllDirectory() to designate an additional path to include in the OS's DLL search path.
You can do this with PATH but I recommend you don't. It's a brutal and inflexible approach. And of course you need to change the system wide PATH for it to have any effect at executable load time.
You can load your DLLs explicitly with LoadLibrary and GetProcAddress. That's no fun if there are a lot of imports but it can be a good option otherwise. And remember that if you go down this route, every single DLL must switch to explicit linking.
There is something called DLL Redirection but MS don't recommend you use that. They recommend that you use side-by-side components. Having said that, the Visual Studio team moved away from side-by-side components with the MSVC runtime in VS2010 because of the pain that side-by-side had caused in previous release.
So, in spite of all the options, I really believe that the best solution is to put all the DLLs in the same directory as the executable. If you can get over the folder looking untidy then it will make life much simpler. It is a trivial no effort solution to the problem.
Update
The update to your question provides the extra information that these DLLs are optional add-ons. In this case you simply have no alternative but to use explicit linking with LoadLibrary and GetProcAddress.
I would highly recommend that you leave the DLL's in the same folder as the applications.
If you really want to go down the road of putting the DLL's in a separate folder then you need to know whether you can load the DLL's with the LoadLibrary API which allows the specification of the path too. However, if the DLL's are statically loaded then it is Windows that performs the search. The Windows search first looks in the application folder then searches the Windows PATH. Also, as Delphi 7 only creates 32 bit applications this can get messy under Windows 64 bit.
On Windows, there is a "DLL search order". One of those search paths is The directory from which the application loaded, which is why it works to have them in the same folder as the EXE.
If you are statically linked to the DLLs, they must be loaded when the EXE is loaded into memory. This is before your first line of code is executed. So, you're relying on the DLLs being in one of the search paths. In this case, you're stuck with setting the path, and you must set it prior to the program loading.
If you are dynamically linking to the DLLs, then you can use LoadLibrary/LoadLibraryEx to load the DLLs at run time, in your code. Using those functions, you must specify the path to the DLL, so the DLLs could be anywhere. In this case, I feel that it's valid to put the DLLs in a separate folder to keep things tidy. As long as you don't put the DLLs into a shared location like the Windows System32 folder, you'll avoid a lot of headaches.
A temporarly solution is:
You can set your DLL path in your application's Shortcut (in "Start in" box).

Delphi debug a wrong unit

This is an odd behaviour by my D2006 as it happens sometimes only. I have a project I want to debug. The file I want to debug is named 'Main.pas'. I have another unrelated project with the same Unit name and sometimes the Debug prompt me the wrong Main file instead of the Main unit from the current project. This have happened to me with other files with the same name. I can't debug then as the debug keys don't work (they just don't do anything). Do you have experienced the same problem? How can I fix it?
Thanks.
Do you use relative paths?
If yes, I found out it helps to set the working directory to my projects directory y loading a file from my projects dir using File->Open. The navigating and loading apparantly sets the working dir, fixing the case where you THINK you are using paths relative to your project, but delphi interprets them relative to the working dir of the IDE.
Close all other tabs first though, to avoid mistakes. Since the delphi compiler is a dll, it interacts deeply with the IDE, and probably has access to which files are opened. (it can compile unsaved files!)
If not, it might a freak occurance, but still have the same origin. Developing a habit to first close other files (right click on tab->close all other), and fixate the working dir (with the load unit via file-Open workaround) might help.
I've the feeling the BDS series of IDEs seem to suffer from this more than the classic ones, but the problem existed in the classic ones too. Could be as simple as using more fancy opendialog options in BDS, increasing the chance on working dir change.
update Also only opening projects when no other projects are open helps. So always click the old project before opening the new, and don't click a project in the windows explorer if the IDE is open with another project loaded.
Delphi XE still suffers from this
I have run into that too, and now I tend to give files unique names, like instead of Main.pas, it might be ProjectNameMain.pas
Check your Library paths and Browsing paths in the Environment Options
Take a look at the output and DCU directories of the project. You're probably picking up an old DCU from a shared DCU directory. Clear out the DCUs and re-build.

Delphi 2007 and {$IFDEF...} directive, fails to see our conditional

We have the following in our codebase, in a component file:
{$IFDEF ADO}
FDatabase : TADODatabase;
{$ELSE}
FDatabase : TODBCDatabase;
{$ENDIF}
The reason is that for various legacy applications, one or the other type of database connection and set of classes is to be used.
However, while configuring a new machine, it seems that our conditionals aren't taken into account. In the project settings, it says "ADO;DEBUG", and yet it compiles the above code with the odbc type instead.
The odd thing is that it isn't consistent. Two different units built as part of the same project uses separate settings. In other words, in one place our conditional is visible, in another it is not.
The file that compiles wrong does not have any {$UNDEF or similar directives, nor does it include any files.
What am I missing here?
Solved (ugh): Right, Delphi is just being boneheaded, or whatnot.
We found these:
I get “F1026 File not found”, OR some compiler options are not passed to the compiler from the IDE.
Configuration='Debug' Platform='BNB'
Which both mention the "Platform=BNB" setting. By enabling the diagnostic output, we see that exact value. So we try to override it per the articles, no luck, still BNB. Then we go to the project settings, turns out it can be overriden there as well, so we do that too, still no luck.
Turns out the Delphi installer, or whatnot, has added a "Platform=BNB" environment variable on operating system level, removing that, restarting Delphi, and all is well.
Well, as well as can be expected. We still have to use Delphi though.
You should always make a "build all" when you change those conditions.
It could be that one unit is actually not re-compiled. Check the following:
Is the .pas file included into the project?
Is there another file (.pas or .dcu) with the same name in the search path? It's possible the IDE sees a different file than the compiler.
Is the file actually compiled? Compare the timestamps of the .pas and the .dcu file.
Do you compile for another platform? Some compiler options are not passed unless the platform is "AnyCPU".
Whenever I encounter problems like this I brute-force delete every .dcu file in my project and component folders just in case the "Build all" doesn't remove all stale .dcus. The following recompile either solves the problem or reveals if any wrong .dcu was used.

Resources