I saw a Delphi (Object Pascal) code that force unloads any module (dll) that is loaded inside my software. Then with base in this code, I'm wanting and needing of something similar now in C++ (Dev C++).
Someone can help me please?
Here is Delphi code that I saw:
procedure ForceRemove(const ModuleName: string);
var
hMod: HMODULE;
begin
hMod := GetModuleHandle(PChar(ModuleName));
if hMod=0 then
exit;
repeat
until not FreeLibrary(hMod);
end;
The functions
HMODULE GetModuleHandle(LPCTSTR modulename)
BOOL FreeLibrary(HMODULE)
are functions of the Windows API. It can be called from any language that supports programming against the Windows API, as C++
Only recommendation: Remove the loop (the repeat until not ...) in your sample above. It should be replaced by code that interprets the return value of the call to FreeLibrary, documentation here: https://msdn.microsoft.com/en-us/library/windows/desktop/ms683152(v=vs.85).aspx
The DLL will be unloaded from memory (that is to say, the address space of the executing process), as soon as its per-process reference count goes zero; you cannot force unloading a DLL globally by repeatedly executing FreeLibrary() if another process still holds a reference.
EDIT: included a direct translation of OP's sample into a C++ snippet:
void ForceRemove(LPCTSTR ModuleName)
{
HMODULE hMod;
hMod = ::GetModuleHandle(ModuleName);
if(hMod==0)
return;
/* DISCLAIMER potentially infinite loop
* not advisable in production code,
* included by request of the OP to
* match his original */
while(::FreeLibrary(hMod));
}
Related
I have to write a DLL in Delphi XE7. I want to use TParallel.For in the DLL. The DLL is loaded into a C++ application, where everything works. However, when the application terminates, or a call to FreeLibrary is made, the application hangs. If I remove all the TParallel.For loops and replace them with standard loops, the application exits normally.
The TParallel.For loops are very simple:
TParallel.For(0, inImage.Height -1,
Procedure(ty : integer)
begin
SomeProcedure(ty);
end);
If I create a Delphi application with exactly the same code, everything works perfectly.
After doing a lot of research and debugging, it looks like there is a deadlock which is preventing the C++ application from exiting when FreeLibrary is called, but I can't find where the problem is in TParallel.
Just to summarise the situation:
The TParallel.For loops all complete and produce the correct results.
The exact same TParallel.For code in a Delphi .exe works correctly.
The DLL is loaded and the functions are called and perform correctly from within the C++ application.
The C++ application will exit correctly if there are no TParallel.For loops.
The C++ application will hang if there are TParallel.For loops.
I am guessing that there is a deadlock which occurs when FreeLibrary is called.
If I use the OTL threading library, everything works as it should.
My questions are:
Has anyone else experienced this behaviour?
What is a good debugging strategy to find a deadlock in this situation?
Any advice is greatly appreciated.
UPDATE
OK, so if you want Minimal, Complete and Verifiable example, here you go (thank you Stephen Ball):
library ADelphiDLL;
uses
System.SysUtils, System.Classes, Threading, SyncObjs;
function IsPrime (N: Integer): Boolean;
var
Test: Integer;
begin
IsPrime := True;
for Test := 2 to N - 1 do
if (N mod Test) = 0 then
begin
IsPrime := False;
break; {jump out of the for loop}
end;
end;
function Prime(Max : integer) : boolean;
var
tot : integer;
begin
tot := 0;
TParallel.For(1, Max, procedure (I: Integer)
begin
if IsPrime (I) then
TInterlocked.Increment (Tot);
end);
return true;
end;
exports Prime;
begin
IsMultiThread := True;
end.
in C++:
#include "stdafx.h"
typedef bool(__stdcall *primesf)(int);
void main()
{
HINSTANCE hGetDLL = LoadLibrary(L"ADelphiDLL.dll");
primesf primes = (primesf)GetProcAddress(hGetProcIDDLL, "Primes");
bool result = primes(100);
FreeLibrary(hGetDLL);// <-- Hangs here forever
}
In response to the very "helpful" comments, "there is a defect in the code " and "debug it yourself", thank you, that is what I have been doing for a too long a time. So, if there is no help forthcoming here, I will try and get permission to switch to OTL, which does work in the DLL in question.
UPDATE 2
OTL works exactly as expected. So, yes, there is a "defect in the code". I give up. I will recommend abandoning Delphi altogether and then we can move everything over to C++ and C#. That has to be a much better short (and long term) solution.
I have seen an issue similar to this, although i was using Delphi 10.0 Seattle, and a Delphi EXE loading a Delphi DLL.
Anyway, the solution that I came up with is the following:
In your Delphi DLL, first create your own thread pool.
Use the overloaded version of TParallel.For that takes a thread pool object as its last parameter, and provide your own thread pool object.
Before unloading your Delphi DLL, make sure to free your thread pool object.
This approach solved the problem for me.
TParallel.For documentation:
http://docwiki.embarcadero.com/Libraries/Berlin/en/System.Threading.TParallel.For
Example pseudo-code:
MyPool: TThreadPool;
MyPool := TThreadPool.Create;
TParallel.For(1, Max, procedure (I: Integer)
begin
if IsPrime (I) then
TInterlocked.Increment (Tot);
end,
MyPool
);
MyPool.Free;
I'm trying to provide my own entry point to a visual c++ executable using the linker switch "/entry". The associated Microsoft documentation goes into some detail about how to manually initialise the c runtime in a dll, but I can't grasp how to initialise it in my exe. The best I've got is that I need to call _CRT_init, but I don't know if that's a function or a macro, or where it might be defined, and Visual Studio (and msbuild) don't recognise the identifier, so no hints there.
The rationale here is that I'm attempting to unit test, with Google Test, an executable, and it won't link because main() clashes. The two approaches mentioned in the GTest FAQ aren't really generalisable and would require considerable rework to about 30 legacy executables to implement. Renaming each unit test application's main() seems like a super-easy approach, if only I could initialise the c runtime.
So I searched through the C Runtime source this afternoon, and the answer is "no". You cannot provide your own executable entry point not named main if you want to use the C Runtime. Quite aside from _CRT_INIT() being the an initialisation function for a dll (mainCRTStartup() is one of the initialisation functions for executables), mainCRTStartup() and its like call main() by name.
You could initialize the CRT in a standalone wrapper module which has
main; obj1
Rename the main of all existing exe modules to xx_main; obj2, obj3.... objn
Link obj1 (main) with (obj2, obj3.... objn).
To test a foo.cc file, you need to compile and link it into your unit
test program
What's the issue with this scheme ?
Though not specifically documented, it is possible to initialize the CRT in an executable in the same way it can be done in a DLL.
EXTERN_C BOOL WINAPI _CRT_INIT( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved );
// ThreadProc for CreateRemoteThread, a possible use case.
DWORD WINAPI ArbitraryAlternateEntryPoint( LPVOID )
{
_CRT_INIT( GetModuleHandle( NULL ), DLL_PROCESS_ATTACH, NULL );
// CRT functions can be used here.
_CRT_INIT( GetModuleHandle( NULL ), DLL_PROCESS_DETACH, NULL );
return 0;
}
The documentation suggests that _CRT_INIT should be called for each new thread in addition to the initial call, but in practice this is not necessary.
I'm can't use the function of a dll in delphi. I'm having some problems with the conversions of types.
This is the function I want to call the Delphi DLL:
function SyncFunc(var Type:string; var MaxUsers:integer; var ErrCode :Word):boolean;
C++ code:
unsigned char(WINAPI *SyncFunc)(PCHAR Type, INT *MaxUsers, WORD *ErrCode);
HMODULE hLib;
BOOL Res = FALSE;
WORD ErrCode = 0;
INT MaxUsers = 0;
CHAR Type[256];
hLib = LoadLibrary("delphi.dll");
Res = SyncFunc(Type, &MaxUsers, &ErrCode);
Someone please help.
P.S. similar question here C++ consuming delphi DLL (but my function uses string, not WideString)
function SyncFunc(var Type:string; var MaxUsers:integer; var ErrCode :Word):boolean;
There are two problems facing you here:
string is a native Delphi type that can only be created and consumed by Embarcadero tools. Further more, since it uses the Delphi runtime heap, ShareMem or similar must be used.
The function uses the default register calling convention which again is only available using Embarcadero tools.
The obvious way forward is to fix the DLL and arrange for it to use standard platform interop types and calling conventions. You might use BSTR (WideString in Delphi) for strings, and stdcall as the calling convention.
If you cannot change the DLL then your only hope is to write an adapter DLL using the same compiler as was used to compile this errant DLL. But that can only work if the errant DLL was compiled using a shared memory manager. If that is not the case then your task is next to impossible.
OK, so I have a situation in which I call LoadLibrary on a DLL that I wrote. This call to LoadLibrary returns error #998, or ERROR_NOACCESS "Invalid access to memory location."
The DLL in question uses MFC in one configuration, and not in another; only the MFC configuration has this problem. It used to work, but I have no idea what I changed: I'd actually moved on to the non-MFC version and been tinkering quite a lot with that and I have no idea what I could have done that affected the MFC version.
I don't know a lot about DLLs. The original loading code was actually given to me, and I haven't changed it. Below is that code:
// submodule loading
#ifndef MFC
// Project uses standard windows libraries, define an entry point for the DLL to handle loading/unloading
BOOL WINAPI DllMain(HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved)
{
_MESSAGE("DllMain called.");
switch(dwReason)
{
case DLL_PROCESS_ATTACH: // dll loaded
hModule = (HMODULE)hDllHandle; // store module handle
_MESSAGE("Attaching Submodule ...");
break;
case DLL_PROCESS_DETACH: // dll unloaded
_MESSAGE("Detaching Submodule ...");
break;
}
return true;
}
#else
// Project uses MFC, we define here an instance of CWinApp to make this a 'well-formed' DLL
class CSubmoduleApp : public CWinApp
{
public:
virtual BOOL InitInstance()
{// dll loaded
hModule = m_hInstance; // store module handle
_MESSAGE("Attaching Submodule ...");
return true;
}
virtual int ExitInstance()
{// dll unloaded
_MESSAGE("Detaching Submodule ...");
return CWinApp::ExitInstance();
}
} gApp;
#endif
Obviously, MFC is defined in the MFC configuration, and not otherwise.
I doubt this is enough information to solve this problem; I realize that. What I'm actually hoping to learn is where to look for problems that might cause this error. I'll be happy to supply any information you need — once I know it's needed.
Thanks for any tips.
OK, this question was answered by a friend of mine (no idea if he has a StackOverflow account; not going to pester him with answering it twice).
The deal is that I had a global object, the class of which had a constructor that called a function that depended upon another global object (ironically enough, the function in question was _MESSAGE, but by the time DllMain or InitInstance gets called, that function works fine). C++ doesn't allow you to specify the order in which globals get initialized, so when this global's constructor got run (when the computer attempted to load the DLL), it caused a memory error by attempting to use another global that hadn't been created yet.
So... that's the answer. A really specific case, but I guess if anyone else finds they're getting 998 errors and need to know what sorts of problems to check, this is something to look for: make sure all your globals are independent!
I'm programing on C++, I'm using Visual Studio 2008, Windows XP, and I have the following problem:
My application, that is a DLL that can be used from Python, loads an external dll, uses the required methods, and then unloads this external Dll.
It's working properly, but after more than 1000 cycles the method "LoadLibraryA" returns a NULL reference.
The main steps are:
HINSTANCE h = NULL;
h = LoadLibraryA(dllfile.c_str());
DWORD dw = GetLastError();
The error got is:
ERROR_DLL_INIT_FAILED
1114 (0x45A) A dynamic link library (DLL) initialization routine failed.
The Dll is unloaded by using the following:
FreeLibrary(mDLL);
mDLL = NULL;
Where mDLL is defined like this:
HINSTANCE mDLL;
First alternative tried:
Just load the Dll only once, and unloaded it when the application ends. This fix the problem but introduces a new one.
When the application ends, instead of first executing the DllMain method of my applicaion, wich unloads the external DLL, is executing first the DllMain method of the other Dll. This cause the following error because my application is trying to unload a Dll that was unload by itself previously.
"Unhandled exception at 0x04a00d07 (DllName.DLL) in Python.exe: 0xC0000005: Access violation reading location 0x0000006b".
Any suggestion will be welcomed.
Thanks in advance.
Regards.
Make sure that initialization code of the loaded/unloaded library doesn't leak memory. Many libraries expect to be loaded only once and not always clean up their resources properly.
E.g. in C++ file at the top level one can declare and initialize a variable like this:
AClass *a = new AClass(1,2,3);
The code would be executed when library is loaded automatically. Yet, now, it is impossible to free the hanging instance as library doesn't know precisely when/how it is going to be unloaded. In the case one can either replace "AClass *a" with "AClass a" or write your own DllMain for the library and free resources on DLL_PROCESS_DETACH.
If you have no control over the library's code, then it might make sense to create a cache of loaded libraries and simply never unload them. It is very hard to imagine that there would be unlimited number of libraries to overload such cache.