DllMain on Windos platform is NEVER hooked up. This problem happens when:
1). the DLL is dynamically loaded using WIN32 LoadLibrary, as well as
2). the DLL is statically loaded.
The DLL code is here:
namespace IslandDll;
uses rtl;
[SymbolName('__elements_dll_main')]
method DllMain(aModule: rtl.HMODULE; aReason: rtl.DWORD; aReserved: ^Void): Boolean;
begin
OutputDebugString('I am now inside DllMain, Buddy!');
case aReason of
DLL_PROCESS_ATTACH: ;
DLL_PROCESS_DETACH: ;
DLL_THREAD_ATTACH : ;
DLL_THREAD_DETACH : ;
end;
exit true;
end;
[SymbolName('Sum'), DLLExport, CallingConvention(CallingConvention.Stdcall)]
method Sum(a, b: Integer): Integer;
begin
OutputDebugString('I am now inside Sum, Buddy!');
exit (a + b);
end;
end.
The testing projects are attached below, which include both the dynamic DLL loading case, and the static DLL loading case.
Again, Carlo will know more about how this works. But as I understand DllMain is something Windows knows to call automatically on its own as the dll is loaded, right? as such, I’d expect the __elements_dll_main symbol name is probably wrong? Also, you probably need a DllExport attribute as well, for the symbol to become public…
As I recall it was @ck who suggested __elements_dll_main in another post. But yes, without DllExport it won’t be public. You need to add DllExport (or Export). [DllExport(‘__elements_dll_main’)] should also work, if you don’t want to use two attributes.
Yeah, I know. I’m not sure what the mechanics here are. MS’s docs state
DllMain is a placeholder for the library-defined function name. You must specify the actual name you use when you build your DLL. For more information, see the documentation included with your development tools.
so I guess maybe there’s some compiler/linker magic involved to map __elements_dll_main to what Windows actually needs to locate this entry point…
I’ll check with @ck and make sure we doc this properly, Tuesday.
I think the “Compiler Magic” is here, IslandRTL/WindowsHelpers.pas, line 1175-1184
method DllMainCRTStartup(aModule: rtl.HMODULE; aReason: rtl.DWORD; aReserved: ^Void): Boolean;
begin
var lMain: ^DllMainType := @_dllmain; // Hook up here to lMain.
ExternalCalls.fModuleHandle := aModule;
if lMain^ = nil then exit true; // lMain^ always = 0, meaning the user defined DllMain will not be called!!!
exit lMain^(aModule, aReason, aReserved);
end;
Then at line 317-322, _dllmain is declared as a public variable.
[SymbolName('__elements_dll_main'), &Weak]
method DllMain(aModule: rtl.HMODULE; aReason: rtl.DWORD; aReserved: ^Void): Boolean; external;
// This is needed by anything msvc compiled; it's the offset in fs for the tls array
var
_dllmain: DllMainType := @DllMain;public;
Most likely the BUG is a compiler bug, that doesn’t assign a method pointer pointer below:
At line 322 , _dllmain: DllMainType := @DllMain; public; // <== At this point, _dllmain is initialized to @DllMain, which is defined in the user code. The compiler is supposed to get the user-implemented method address, but it FAILS to do so.
Hence, in the following DllMainCRTStartUp, which is the standard DLL entry point expected by Windows, var lMain: ^DllMainType := @_dllmain;, lMain^ would be always be nil. Therefore user defined DllMain is never entered.
method DllMainCRTStartup(aModule: rtl.HMODULE; aReason: rtl.DWORD; aReserved: ^Void): Boolean;
begin
var lMain: ^DllMainType := @_dllmain;
ExternalCalls.fModuleHandle := aModule;
if lMain^ = nil then exit true;
exit lMain^(aModule, aReason, aReserved);
end;
Thank you. If not for dllmain but just for a global function, can I use the same trick? That is, I ‘d like to have a function declared external in one unit file but implemented in another unit?
You don’t really need this cross units? The elements compiler doesn’t care about the order of functions. (Unless I misunderstand your request). Etiher way yes, you can use this trick to tricky the compiler.
Used doesn’t really do anything here but normally it forces the linker to link it in. Statically initialize means it hardcodes the value instead of using a static ctor (limits the options ofc)