Problems with RunTime Linking DLLs

Started by
7 comments, last by ElectroDruid 18 years, 10 months ago
Hello, I'm exploring DLLs for the first time, and I'm having some difficulties getting them to work. I'm creating my DLL with code that looks basically like this:
//mydll.h
__declspec(dllexport) void SomeFunction();

//////////////////////////////

//mydll.cpp
#include"mydll.h"

void SomeFunction()
{
    cout << "All your DLL are belong to us\n" << endl;
}
So far so good. I can load and run this function from a different app in the obvious way:

//mydll.h
__declspec(dllimport) void SomeFunction();

//////////////////////////////

// myDllCallTest.cpp

#include"mydll.h"
#include<conio.h>
#pragma comment(lib, "mydll.lib")

void main()
{
    SomeFunction();
    system("PAUSE");
}
Incidentally, the DLL seems to take a good 5-10 seconds to load and do anything, I don't know if that's normal. Now, I'm trying to load the same DLL I created from the first bit of source into yet another app, this time dynamically. The ultimate goal is to end up with something along the lines of what's described in the MSDN document "DLLs, The Dynamic Way" but in the meantime I'm messing around with one of the basic examples from this doc: http://www.gamedev.net/reference/articles/article928.asp

#include<conio.h>
#include <windows.h> 
#include <stdio.h>

extern "C" void SomeFunction();
typedef void (*MYFUNCTION)(void);

void main()
{
	MYFUNCTION pfnMyFunc=0;

	HINSTANCE hMyDll = LoadLibrary("mydll.dll");

	if(hMyDll != NULL)
	{
		pfnMyFunc= (MYFUNCTION)GetProcAddress(hMyDll, "SomeFunction");

		if(pfnMyFunc== 0)   
		{
			FreeLibrary(hMyDll);
			return;
		}

		pfnMyFunc();

		FreeLibrary(hMyDll);
	}

	system("PAUSE");
}
I don't do the __declspec(dllimport) or the #pragma, I just rely on what's listed about. I get the couple of second pause (like I did with the load-time linking), but no display. From single stepping through the code it seems that the DLL is actually loading, but pfnMyFunc isn't set properly by the GetProcAddress call. Anyone know why that might be? As a side note/related question, what would be a good way to lay out a project in .NET such that I can use one solution which can compile DLLs as well as compile the code that uses them? I'm thinking along the lines of breaking the solution up into a bunch of projects, each one representing a DLL (except one which is the executable code which loads the DLLs), and setting the dependencies such that if you try to compile the executable project, it will first compile any changes it finds in any of the DLLs. Will that work or am I barking up the wrong tree? Thanks in advance for any light you might be able to shed on all this stuff :)
"We two, the World and I, are stubborn fellows at loggerheads, and naturally whichever has the thinner skull will get it broken" - Richard Wagner
Advertisement
I'm doing a similar thing at the moment which is working without any problems. "pfnMyFunc isn't set properly by the GetProcAddress cal" - do you mean that the function isn't being set at all, or to something wrong? If GetProcAddress is failing completely it could be something to do with the name mangling. I don't know what the 'proper' solution to this is, but I found putting a .DEF file in the source directory for the DLL seems to work; the linker picks it up and knows to export the correctly named symbols. Here's mine:

LIBRARY XGEXT_Render2D_AllegroEXPORTS		XGEXT_Start	XGEXT_Exit	XGEXT_GetInternalName	XGEXT_GetEntity


As for the dependencies, yes, it can be set up like that. I have the DLLs set as dependencies of the main project, and set their output directories to be the location needed for the main executable. They're all in separate projects, but loaded into one main workspace.

EDIT: Put in source tags. Haven't been here for so long...
"The finger of blame has turned upon itself"
pfnMyFunc starts off with the value of type void* (at least according to my debugger), and the GetProcAddress call doesn't change that, so the if statement straight afterwards picks that up, unloads the library and returns from main().

I made a .def file (I'm guessing it's basically just a text file with the extension changed?), and put it in the source/project directory. It reads:

LIBRARY mydll
EXPORTS
SomeFunction

The linker didn't appear to pick up on it or do anything particularly special. I dragged it into the project workspace as well, but nothing seems to happen.

One thing I forgot to mention, although I don't know if it's relevant is a linker warning I get when building the DLL:
LINK : warning LNK4243: DLL containing objects compiled with /clr is not linked with /NOENTRY; image may not run correctly

I figured that that was reasonable given that my DLL doesn't (and shouldn't) involve a main() of any description. I tried adding /NOENTRY to the linker command line but that just results in an error:
LIBCMTD.lib(crt0.obj) : error LNK2019: unresolved external symbol _main referenced in function _mainCRTStartup

I'm not fussed about the warning, just thought I'd mention it in case it was relevant
(Doh! GameDev being weird with my login, the above post was me)
"We two, the World and I, are stubborn fellows at loggerheads, and naturally whichever has the thinner skull will get it broken" - Richard Wagner
Shouldn't __declspec(dllexport) be extern "C" __declspec(dllexport)? This is how I've always had to declare it anyway.

Edit: Ah, thats what I did wrong (I was trying it in an app and couldn't get it to work.) I had a typo (as you said). dllimport should be dllexport.

[Edited by - Programmer16 on June 21, 2005 1:13:43 PM]
Quote:Original post by Programmer16
Shouldn't __declspec(dllimport) be extern "C" __declspec(dllimport)? This is how I've always had to declare it anyway.

It doesn't look like it has to be*. Load-time linking works fine for me either way, but that's not my problem. I still can't get runtime linking to find my functions in the DLL.


* (But I am playing with a really simple example, so it's possible I could have run into problems later)
"We two, the World and I, are stubborn fellows at loggerheads, and naturally whichever has the thinner skull will get it broken" - Richard Wagner
These problems is often because of name mangling, where SomeFunction becomes _SomeFunction@0 or similar. It is the more strange name _SomeFunction@0 that GetProcAddress needs. Try to use the following command line to figure out which name to send to GetProcAddress:
dumpbin /exports mydll.dll

If you use extern "C" linkage and STDCALL calling convention, you will not get any extra mangling of your name, which makes things simpler. You can also use syntax in the DEF-file to customize in which way the functions are exported.

List of different exported names I get (this is kind of compiler specific) with different methods:
__declspec(dllexport) void SomeFunction(); // ?SomeFunction@@YAXXZ
extern "C" __declspec(dllexport) void SomeFunction(); // SomeFunction
__declspec(dllexport) void __stdcall SomeFunction(); // ?SomeFunction@@YGXXZ

And with a def-file looking like this:
LIBRARY mydllEXPORTS    SomeFunction

it gets the name SomeFunction. You may have to specify the def-file in "Project Properties -> Linker -> Input -> Module Defintion File"

Regarding your warning: /clr means that you use C++ Managed Extensions, which ables you to run managed code and access the objects of the .NET Framework. However, the code automatically run during the initialization of a mixed DLL violates the restrictions for DllMain. This problem is not completely solved by Microsoft yet. Is it necessary to use .NET Framework in your DLL?

[Edited by - EliasAE on June 21, 2005 5:56:52 AM]
Got it! EliasAE, you were right in that the DLL contained mangled names because I wasn't exporting as extern "C". (Similarly, Programmer16 was kinda right except that the important part is the export, not the import). I don't seem to need a .def file with the way I'm doing things now, but it's very handy to know how to get the linker to pay attention to one if I need it to. I might well need that in the future.

So I guess the only other mystery is why does my program take so long to start up? I'm only doing runtime linking now, but the program still seems to pause for 5-10 seconds before entering main(). Is that normal?
"We two, the World and I, are stubborn fellows at loggerheads, and naturally whichever has the thinner skull will get it broken" - Richard Wagner
Another, probably very dumb question. Hopefully this is the last one though :o)

Is there any way a DLL can get access to anything in the code which loads it? In other words, can it make use of the global classes and data in my main program? I managed to get my code to compile with a DLL project including a header which declares a variable, but the main program and the DLL seem to bother end up with their own individual copies of the variable which they update independently.
"We two, the World and I, are stubborn fellows at loggerheads, and naturally whichever has the thinner skull will get it broken" - Richard Wagner

This topic is closed to new replies.

Advertisement