How to build a DLL from C source on Windows

I need to build a little DLL that I can link to (using declares) from my Xojo-made Win 32 bit application.

I’ve manage to install MinGW (with MSYS) and am able to compile and link the C source using these commands, for example:

gcc -c mycode.c gcc -shared -o mycode.dll mycode.o

When I try to declare against this dll, I get the runtime error [quote]File to load library mycode.dll
%1 is not a valid Win32 application.[/quote]

So I am probably building the dll incorrectly.

When I use the “file mycode.dll” command in the msys shell, it tells me: [quote]PE32+ executable for MS Windows (DLL) (console) Mono/.Net assembly[/quote]

That suggests to me that it’s a 32 bit dll, so what is the error message about?

Also, has someone perhaps already written a guide on how to build libs from C (C++) using CygWin or MinGW for Xojo?

It appears I have installed the wrong version of MinGW - I have one that can only build 64 bit apps, it seems. Re-Installing now to see if the other does better…

So, installing the “i686” instead of the “x86_64” version of MinGW seems to build the right architecture now. The “file” command now gives me:

But the error msg is now getting worse: It states:

When I was still building the wrong architecture before, I only got this msg when I failed to place the DLL either next to the xojo-built exe or into the Libs folder next to the app. But now I get it even if I see the DLL in those places. No idea what’s wrong now.

It appears that Xojo doesn’t give the complete error information here - my DLL was using some other libs (libz, pthreads), and even though I believe I told the linker to link those object files into the dll, and the “nm” command also showed their symbols, it appears that there’s still something that wants to be loaded externally: When I remove all those references and make the DLL contain only one simple function, I don’t get the “The specified module could not be found” error msg any more. This suggests that the error did not mean my dll but some other dll it could not find. Meh.

Now, however, I’m even stuck with the simple single function and without any other lib references: Xojo says it cannot find the function I’m referencing in the declare.

This is such a pain. Has no one ever done this before? Building dylibs on OSX is so easy and straight-forward. But here on Windows, it’s really hard to figure out. There’s no examples, either, it seems.

update I made at least the simple function work now - the last issue was that, despite using

__declspec(dllexport) __stdcall extern int my_init (int x)

The exported symbol would still include the parameter, i.e. it wasn’t “my_init” but “my_init@4”. I could see that by using the “nm” tool.

So, that leaves me with figuring out why the more complex version that uses phreads and libz doesn’t get loaded.

So the problem is apparently related to the fact that the DLL that I want to use needs to load another DLL. And somehow, Xojo’s runtime doesn’t cope with that. I have tried placing the secondary DLL into \Windows\System32" as well as into the same place where my own DLL is placed (i.e. next to the exe or into the libs folder). Nothing works.

I can, however, declare to the secondary DLL and it gets loaded. But I cannot declare to my own DLL which then needs the secondary DLL. Even declaring both does not help. This looks like a bug to me, now. Or maybe the dll is built wrong, and its imports do not correctly reference the other DLL. Hard to tell. Damn.

Is this a dll that is trying to dynamically load another (I assume thats the case)
And where have you placed the original DLL you declare into ?

The DLL I built probably uses one or more DLLs. Initially, I thought it was only the “libz” DLL, which I placed next to the .exe, along with my DLL. But that didn’t help - still getting the “module not found” error. Looking at the “external” symbols, using “nm -u”, I found that it references other external symbols as well. But there doesn’t seem to be any information about which libs it expects to find. Without that info in the DLL, the loader can’t load the mising DLLs, of course. But I can’t fix this either, because I don’t even know which DLLs are missing.

I’ve tried placing every DLL the MinGW contains next to the exe, but that isn’t working, either. I’d also have to try to load each of them to see if that helps. Some info about how Xojo’s DLL loader works would be helpful here so that I don’t keep digging in the dark.

For instance, assuming that I declare a function that uses DLL “A”, and if “A” refs DLL “B”, how would I manage to satisfy the loader? I guess the order is important, e.g. if I order them wrong, then the loader will try to load A before B, and will fail at that. So, how do I enforce the correct order? Does the order of the declares define the order by which the loader loads, or is it in reverse, or is it even random? Also, would I have better control if I used soft declares, because I guess that I can control the loading order better by controlling which external function I call first.

Finally, what do I do if I know that DLL B has to be loaded but I don’t know any function I could reference in it? Because , without actually calling a function from my Xojo code, the loader won’t even try to load the DLL.

To solve all this, could I perhaps use some Win32 function to load the suspected secondary DLLs, and would the loader then be happy? If so, which function would I call? I searched on SO, but all the solutions there are for C#, not for the old WinAPI. E.g. this one:

The only ones we do anything special for is Plugins since they can be relocated into the Libs dir
So we set a specific dll load directory

Declares we just use loadlibrary as far as I know so dll’s on the dll search path should be all thats required

I know something that came up the other day that wasn’t obvious and not sure how this affects mingw BUT using a statically linked in c runtime can be an issue

Try one of the VS Express editions
I’m sure one can turn out a dll

Norman, I want to use pthreads, and the VC libs don’t offer that. I thought I could save some time if I could simply re-use my preemptive thread code written using POSIX APIs instead of writing a custom solution for Windows. By now, I think I should have gone down that path, though - couldn’t have been more difficult.

Jean-Paul, thank you for the pointer to that article. I had not seen that before, and it contained crucial information, such as how to build the dll for use with VB, removing the @… from the names, etc.

For the record, that’s how I now build the dll:

gcc -c mycode.c gcc -shared -o mycode.dll mycode.o -s -Wl,--subsystem,windows,--kill-at

And Norm, thanks for clarifying that Xojo is just using LoadLibrary. After writing a test app in C and looking at the DLL file with a hex editor, I finally figured it all out. The issue was that the pthreads lib was not “pthreads.dll” but “libwinpthread-1.dll”. Once I found that out, I made it work.

So, the problem is indeed that LoadLibrary could not load my DLL because my DLL referenced another DLL, and that was not found. What’s really bad about this is that one does not get the information which DLL was not found. I wonder if another WinAPI function would reveal that? If so, Xojo’s DLL loader should use that in order to give us better information why the DLL loading failed.

I’d use Windows API for Windows DLL’s
I have no idea how well POSIX pthreads will or wont work
Even mingw’s implementation is a wrapper to make Windows threading have a POSIX API
So its a wrapper at best and who knows how well that will work

But you pursue what you want - this IS your code not mine :slight_smile:

As for LoadLibrary I’m not sure it tells specifics about why a DLL loading a dependent DLL failed
Just that it did fail

Testing shows that the pthreads implementation is sufficiently efficient for my use case. Saves me from maintaining two versions of the code.

I now have an app that compresses large amount of data (entire disk contents, actually) in multiple threads, using all available CPU cores, and the result is that it can be even faster than without compression, because the compressed data leads to less disk writing operations. Yay.