Call to a C DLL gives DLL not loaded, while same VBA/Excel script works fine.

Started by jwteunisse, March 19, 2016, 04:03:40 AM

Previous topic - Next topic

jwteunisse

In January, 22nd I posted a question in the Subject Script Exchange/Code samples with the title: 'Winbatch script sending and receiving MQTT messages'.
Until now I did not receive any remarks or suggestions, so I decided to develop a sample DLL in C using Code::Blocks/MinGW as IDE.

The C DLL is based on the Eclipse paho-mqtt C DLL's and a C sample program.
The C sample program I transformed in the mqttPubMsg DLL to be called from a Winbatch script.
The C sample program connects to the MQTT broker (mosquitto) on a Windows10 'server', and publish a message (payload) on a certain topic.

The mqttPubMsg.dll calls the paho-mqtt3c.dll to handle the connection to the broker and to publish the payload message.
As a first step I developed a skeleton DLL in order to test if the DLLCall in the Winbatch script works ok and a result is given back to the WB script.
This first step worked fine. The second step was to assign various C variables with the relevant values based on the paho-mqtt3c.dll function parameters.
Also this version of the dll worked fine.
As the 3rd step I started to call the first paho-mqtt3c.dll function in order to create the connection to the MQTT broker.

Calling this version of the mqttPubMsg.dll in the WB script gives an error 'DLL not loaded'.
While using a C test program works ok, and also the call to a VBA script works correctly.
In both use cases the messages are received by the broker and published to a test subscriber program.

Both DLL's and the paho-mqtt3c.lib are stored in the same Windows directory as the WB script.
My Winbatch version is 2015B running Windows 10 Pro (64bits)

After searching the Tech KB & WB forum and other internet forums for several hours I'm stuck. The mqttPubMsg.dll works fine using a VBA script and a C program, but not in WB.
What can be the cause of the problem and what can be the solution?
In the attached ZIP file are the 3 sources (WB, VBA, C) and the source code of the mqttPubMsg.dll.

Many thanks in advance, best regards, Jan Willem Teunisse   

JTaylor

Is the DLL configured to use IDispatch?  That is required for WinBatch.

Jim

jwteunisse

This term iDispatch is new to me, so the answer to your question is probably no.
Where can I find this information how to use iDispatch, because I did read not this in the tutorials about using your own DLL's.

regards

JTaylor

Was thinking that was configured in the compiler but not seeing it in Visual C++.   Maybe I saw it in Visual C#.    I'll shut up and let someone who knows what they are talking about respond.

Jim

td

No need to worry about COM interfaces like IDispatch since you are not using COM but assuming you are not using a language file, WinBatch does not have an error message that includes the text "DLL not loaded".  So the question becomes where exactly in your script are you seeing this error message? Or do you mean error 1300, "Dll: File not loadable".  If it is the latter, there are numerous possibilities .  For example, compiling the dll as 64-bit and trying to load it into 32-bit WinBatch or visa versa.   Since you know your compiler and linker settings,  only you can figure out what the cause might be.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

jwteunisse

I'm sorry: the error message is indeed 1300 DLL file not loadable.

The error occurs in the statement
ScriptDir = DirScript()
DLL_Path = Strcat(ScriptDir, "mqttPubMsg.dll")
if FileExist(DLL_Path) then
   dllhandle=DllLoad(DLL_Path)   ;; here error occurs

I also tried mqtt_version = DllCall(DLL_Path, long:"getVersion"), resulting in the same error.

The DLL is compiled with MinGW using compile options 1999 ISO C language standard and Target x86 32 bits.
The linker library setting is pointing to pah-mqttx3.lib.
I'm running 32 bits Winbatch.


JTaylor

Sorry.  I almost always use COM interfaces and assumed that was what you were doing.

Jim

td

Quote from: jwteunisse on March 19, 2016, 09:21:02 AM
I'm sorry: the error message is indeed 1300 DLL file not loadable.

The error occurs in the statement
ScriptDir = DirScript()
DLL_Path = Strcat(ScriptDir, "mqttPubMsg.dll")
if FileExist(DLL_Path) then
   dllhandle=DllLoad(DLL_Path)   ;; here error occurs

I also tried mqtt_version = DllCall(DLL_Path, long:"getVersion"), resulting in the same error.

The DLL is compiled with MinGW using compile options 1999 ISO C language standard and Target x86 32 bits.
The linker library setting is pointing to pah-mqttx3.lib.
I'm running 32 bits Winbatch.

All WinBatch is doing at that point in your script is calling the LoadLibrary win32 API.  You are getting the error because the OS (not WinBatch) does not believe that the file is a valid x86 Windows DLL.  WinBatch  would generate a different error, if the file could not be found or was missing a dependent DLL.  There are two possible explanations. Either the process does not have read access to the DLL or some wrong compiler or linker setting is causing Windows to detect an invalid DLL.   
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

jwteunisse

Thanks for your reply. I have checked the read/execute permissions of both DLL's. I also checked again the compiler/linker settings.
As my VBA script runs succesfully with this version of the mqttPubMsg.DDL, I wonder if VBA uses the same LoadLibrary Win API as Winbatch?


td

Again there is no mystery here.  WinBatch is calling LoadLibrary and that win32 API is not loading the file. Also, checking file permissions will not necessarily tell you whether or not a process has read access to a file.  I would recommend  writing a script that calls the LoadLibrary function directly and then using the DllLastError function to get the system error.   You can then lookup the system error to get a better idea of what the system is unhappy about.

Code (winbatch) Select
handle = DllCall('kernel32.dll', long:'LoadLibraryA', lpstr:"pathto\spiffy.dll")
if !handle
   error = DllLastError()
   Message("System Error", error)
endif
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

jwteunisse

Some progress:
implementing your suggestion to load the library using kernel32.dll gives error 126 in Winbatch Studio as well as running the Winbatch interpreter.
Searching for loadlibrary 126 errors on the internet I remembered that the binaries for the C paho-mqttv3  are compiled/linked with VS2013. So looking up the webpage describing the Linux and Windows versions I now noticed that for Windows you need to install the VS2013 Redistributable package. After installing this packages and restarting Windows I can now say  that my WB script is now running without the 1300 error and publish nicely the MQTT payload message and topic using the WB interpreter.
But in Winbatch Studio I still get the load library 126 error.

td

You likely didn't get the CRT (or less likely some other DLL) installed in a location where ALL applications can find it.   If the CRT is the problem, the easiest fix is to statically link the CRT into your DLL.  This goes back to the point made many posts ago that the problem is likely related to compiler or linker settings...

BTW, you can us the Dependency Walker

https://technet.microsoft.com/en-us/sysinternals/bb896645

and Process Monitor

https://technet.microsoft.com/en-us/sysinternals/bb896645

to ferret out missing DLLs.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

td

"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

jwteunisse

Thanks for the tips. In my earlier internet search before posting this support question I read some tips about DepencyWalker and Process monitor.
Depency Walker: remarks were made in StackOverflow about the latest version, dated back about 10 years ago. Using it I noticed that DW found a couple of errors stating it did not find several API_WIN_CORE*.DLS, called from several MS_Win dlls.  After modifying the ENV Path setting some DLL errors were gone. But others remain, due to the fact that they are not installed on my development PC. This I have to investigate further.

ProcesMonitor: after compiling the WB script in an executable, I filtered out the tracing of the WB exe but ProcesMonitor did not log missing DLL's. The WB script was modified in calling the DLLCall statement in a 1 minute interval for a 20 minute periode and each time the MQTT payload message was delivired  to the MQTT broker and is received by the MQTT subsciber.

In The Tech Database I read a remark that Winbatch supports also .net assemblies. There is also a NuGet C# package available on Windows. I will make later today a new post with some questions on this .net subject.


td

Can quite make out exactly what you are trying to say but  if you are still getting a 126 error n WinBatch Studio, you have one or more dlls that the process reporting the error cannot find.  And with regard to dotNet,  the Consolidated WIL Help file documents the WIL dotNet related functions and the Tech Database contains multiple examples of their use.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

jwteunisse

Dear TD,
What I was trying to say was the following. The remarks in Stackoverflow are related to the latest build of depencyWalker, and that is to old (29 Oct 2006 in mycase).
But I have got some more news about the 126 error in Winbatch Studio. Studying Procmon logged activitities with running my WB script in Winbatch Studio showed me that after calling my mqttPubMgs.dll in the script directory (d:\Winbatch\Ontw) Studio was trying first to find the paho-mqtt3c.dll not in my script directory but in d:\Winbatch\system and then following the directories as defined in the PATH Env variable.

I regard that as strange behavior, I'm expecting a DLL first is searched in the directory where the executable or script is being executed.

After copying the paho-mqtt3c.dll in d:\Winbatch\system no errrors where shown in the Procmon log and the WB script was also exectued with no errors.

I think I can now finish my development by calling the DLL's in my final project WB script,

With regards


td

WinBatch Studio does search its executable's location and there is absolutely nothing 'strange' about the search sequence.  The dll search order is both well documented and well know in the Windows development community. Microsoft has a extensive article on dll search order and how it is influenced by registry settings and Windows version on their MSDN site.  The article also explains the security based reasons for that search order.  It is recommended reading.

There is a difference between WinBatch and WinBatch Studio that can affect DLL search order.  WinBatch has some legacy code in its startup routines that sets an old  hidden DOS environment variable that has the effect of making the running script's path the current working directory.  Amazingly, all versions of Windows still respect this legacy environment variable.  WinBatch Studio's debugger does not set that variable for more reasons that I care to go into here.   However, you can imitate WinBatch behavior in the debugger by placing the following at the top of your script

Code (winbatch) Select
if RtStatus() == 10 then DirChange(DirScript())


Also, I wouldn't be to concerned about the age of Dependency Walker.  The only thing to worry about is whether or not it still works and making sure you start it with the correct security token in UAC environments.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

jwteunisse

Thanks again for your explanation. I will keep it in mind for the next development project.  :)