I loaded multiple dlls using LoadLibrary in the NSIS script as part of my project. Because the other dlls are references of the main dll. After that how to call the function using GetProcAddress? Because i have loaded multiple DLLs.
Below is my code snippet:
!include LogicLib.nsh
Section
SetOutPath $InstDir
File testutil.dll
System::Call 'KERNEL32::LoadLibrary(t "$InstDir\Testutil.dll")p.r8 ?e'
System::Call 'KERNEL32::LoadLibrary(t "$InstDir\TestControls.dll")p.r8 ?e'
System::Call 'KERNEL32::LoadLibrary(t "$InstDir\TestDevice.dll")p.r8 ?e'
System::Call 'KERNEL32::LoadLibrary(t "$InstDir\loadtestdll.dll")p.r8 ?e'
Pop $7
${If} $8 P<> 0
MessageBox MB_OK 'Successfully loaded "$InstDir\testutil.dll" @ $8'
System::Call 'KERNEL32::GetProcAddress(pr8, m "IsTherePower")p.r9 ?e'
Pop $7
${If} $9 P<> 0
MessageBox MB_OK 'Successfully found "IsTherePower" @ $9'
${Else}
MessageBox MB_ICONSTOP 'Unable to find "IsTherePower", error $7'
${EndIf}
System::Call 'KERNEL32::FreeLibrary(pr8)'
${Else}
MessageBox MB_ICONSTOP 'Unable to load "$InstDir\testutil.dll", error $7'
${EndIf}
When I run this script, it is loading the DLL successfully. But It is not loading the function. Could you please help me to resolve the issue?
When I run this script, it is loading the DLL successfully.
You are checking the wrong HMODULE in your posted example! You are just checking if pdcdll.dll loaded correctly, not the .DLL you want to check.
Ideally you should have a fair bit of experience with Win32 when using the System plug-in.
LoadLibrary
will load dependent .DLLs for you, you don't have to do it manually in most cases. One potential issue is that NSIS activates some extra hardening protections to avoid loading hijacking-.DLLs and this could prevent a .DLL from loading its dependencies.
I will give you a complete example here that loads each .DLL manually but you should not do this normally, just load the .DLL you need and let Windows resolve the rest for you.
!include LogicLib.nsh
Section
SetOutPath $InstDir
File drvutil.dll
File UPSControls.dll
File UPSDevice.dll
File pdcdll.dll
System::Call 'KERNEL32::AddDllDirectory(w "$InstDir")' ; Tell Windows we trust all .DLLs in this directory
System::Call 'KERNEL32::LoadLibrary(t "$InstDir\pdcdll.dll")p.r8'
${IfThen} $8 P= 0 ${|} MessageBox MB_ICONSTOP "DEBUG: Failed to load pdcdll.dll" ${|}
System::Call 'KERNEL32::LoadLibrary(t "$InstDir\UPSDevice.dll")p.r8'
${IfThen} $8 P= 0 ${|} MessageBox MB_ICONSTOP "DEBUG: Failed to load UPSDevice.dll" ${|}
System::Call 'KERNEL32::LoadLibrary(t "$InstDir\UPSControls.dll")p.r8'
${IfThen} $8 P= 0 ${|} MessageBox MB_ICONSTOP "DEBUG: Failed to load UPSControls.dll" ${|}
System::Call 'KERNEL32::LoadLibrary(t "$InstDir\drvutil.dll")p.r8 ?e'
Pop $7 ; Get ?e result
${IfThen} $8 P= 0 ${|} MessageBox MB_ICONSTOP "Failed to load drvutil.dll, error $7" ${|}
${If} $8 P<> 0
System::Call 'KERNEL32::GetProcAddress(pr8, m "IsUPSPresent")p.r9 ?e'
Pop $7 ; Get ?e result
${IfThen} $9 P= 0 ${|} MessageBox MB_ICONSTOP "Failed to find the exported function, error $7. Inspect the .DLL with Dependency Walker to make sure the function is exported with the correct un-decorated name!" ${|}
${EndIf}
SectionEnd
If you get the "Failed to load drvutil.dll" message then you need to look at the .DLLs dependencies etc.
If you get the "Failed to find the exported function" message then you have not exported the function correctly. The function name should not be decorated. Dependency Walker will show you the exported function name. If you are unable to remove the decoration then you can pass the decorated name directly to GetProcAddress
but then you need to keep in mind that the name is probably not the same if you compile as 64-bit or if you change to another compiler vendor.
It should look like this: