3D API DLL function export problems, Help

euan

New member
I'm trying to write a dummy dll for an ancient 3D API, and I can't for the hell of it figure out how to match the original DLL's export type.


The header file defines a macro for exporting the functions as a dll as follows:

Code:
#if defined (BUILD_AS_DLL) 
//export both the function as is and a function pointer
//This allows a GetProcAddress() to work without name mangling
    #define PROTOTYPE(function_name, return_type, parameters)   \
    return_type DLLEXPORT WINAPI function_name parameters;      \
    typedef return_type (WINAPI *function_name##_t) parameters; \
    extern DLLEXPORT function_name##_t function_name##_lib
#else
    #define PROTOTYPE(function_name, return_type, parameters)   \
    typedef return_type (WINAPI *function_name##_t) parameters; \
    return_type DLLEXPORT WINAPI function_name parameters;      
#endif

An exported function is then declared in the header as follows:

Code:
PROTOTYPE (3DAPI_Init, int, (void));

If I look at the export table in the original DLL the function will have 2 items:

3DAPI_Init_lib
_3DAPI_Init@2


So my problem is what is DLLEXPORT? It's not defined anywhere. Is this some ancient MSVC4.0 thing? Or is it just "#define DLLEXPORT __declspec(dllexport)"? I know that if I put the /Gz in the MSVC6 compiler options it will export __declspec(dllexport) functions in the __stdcall format which is the "_functionName@2", and not declaring /Gz will export "functionName". How do I do both at the same time using that macro, or another method. I can't write DLLs like this to save myself! Normal windows stuff is no problem, but things like this just stall my brain. :confused:


Oh and I won't mention the API becuase nobody will have ever heard of, nor used it! It doesn't even show up in google!!!
 
Forgive me if this is completely wrong ( I may be suffering from brain lock too ).

Wouldn't you just put a " #define BUILD_AS_DLL " In your code before including the header file? Or you could put BUILD_AS_DLL in your Preprocessor definitions.

"So my problem is what is DLLEXPORT? It's not defined anywhere. Is this some ancient MSVC4.0 thing? Or is it just "#define DLLEXPORT __declspec(dllexport)"?"

Its defined as part of the microsoft specific extensions to the C & C++ languages. Its defined just as you have above...
#define DllImport __declspec( dllimport )
#define DllExport __declspec( dllexport )
 
No that makes perfect sense.

However it still doesn't seem to make the DLL match the original one in terms of the export table.

If I do what you suggested and changed the code to use the PROTOTYPE macro in the function prototypes, I still end up with just the 1 entry per function. for example "_3DAPI_Init@0" There still is no "3DAPI_Init_lib" export.

When I try to execute the dll and sample program, the main program always crashes with an unhandled exception @ 0xC0000005, see trace below.

Which one is supposed to be a pointer to the function, and which is suppoed to be the actual function? Is that even what it is supposed to be?

asm from unhandled exception
Code:
_3DAPI_Init@0:
004027C0   push        esi
004027C1   push        edi
004027C2   push        offset string "3DAPI" (0042ac50)
004027C7   call        dword ptr [__imp__LoadLibraryA@4 (004312c8)]
004027CD   mov         [__LINE__Var+4 (0042aa40)],eax
004027D2   cmp         eax,20h
004027D5   jae         _3DAPI_Init@0+29h (004027e9)
004027D7   mov         eax,1
004027DC   pop         edi
004027DD   mov         dword ptr [__LINE__Var+4 (0042aa40)],0
004027E7   pop         esi
004027E8   ret
004027E9   xor         esi,esi
004027EB   push        offset string "3DAPI_Init_lib" (0042ac3c)
004027F0   mov         eax,[__LINE__Var+4 (0042aa40)]
004027F5   mov         edi,dword ptr [__imp__GetProcAddress@8 (004312cc)]
004027FB   push        eax
004027FC   call        edi
004027FE   mov         eax,dword ptr [eax] 
00402800   cmp         eax,esi
00402802   jne         _3DAPI_Init@0+4Eh (0040280e)
00402804   mov         eax,offset _WinMain@16+17A0h (004027b0)
00402809   mov         esi,1
0040280E   test        esi,esi
00402810   je          _3DAPI_Init@0+63h (00402823)

0x004027FE is where the exception occurs. eax = 0

It seems to be that the code calls GetProcAddress looking for "3DAPI_Init_lib" and never finds it. As far as I can see the getprocaddress is not looking for the ordinal value of the exported function (because that would fail). It's looking for the _lib export which isn't being created and exported.

I'm begining to thing the problem is down to the line:

extern DLLEXPORT function_name##_t function_name##_lib

It doesn't seem to be doing anything.

Need headache cure fast... :(
 
Just posting to let you know that I have been trying to figure this out. But to be honest, I have not a clue how that macro is supposed to work.

These two lines in the "#if defined (BUILD_AS_DLL)" seem strange to me->

return_type DLLEXPORT WINAPI function_name parameters; \
typedef return_type (WINAPI *function_name##_t) parameters; \

Shoudn't the typedef for return_type be declared before using return_type? Have you tried switching these two lines?
 
Yes I thought that was a mistake i the header too. But it makes no difference if you swap it around.

The only reason I could think of for it being the way it is currently, is that the return type is redefined (cast is probably the correct term) to be a pointer to the function after being used in the function declaration (ie int32 WINAPI function_name(parameters) ). The second export is another function but the return type is cast as a pointer to the function. :confused:

But never the less, it doesn't export anything.

I'm going to try making another macro that just exports the pointer to the function, and try to get the name right. I think it will have to be overridden to make the export naming convention correct (we can't have _ @# appended to it it). I'll then make a separate delaration of the pointers exports.

The annoying thing is my win2k profile got screwed up, and I now have to re-install MSVC, DXsdk, and just about everything else. :rolleyes:
 
No ... wait :D

whateverfunction_lib is a function pointer, not a function with a return type of a function pointer. Geddit? ;)

eg
int function(float);

int (*funtion_lib)(float);

function_lib is a pointer to a function taking a float and returning an int.

So you'll have to
1)define these pointers somewhere in your code (right now you only have the declaration which is not enough for an export).
2)initialize the function pointers to proper values. My guess would be that they ought to point to the functions they derive their names from.

Snippets
Code:
//the header with the macros
...
PROTOTYPE(groovy_function,int,(float));
Code:
//a c or cpp file that includes the header

//function pointer
groovy_function_t groovy_function_lib=groovy_function;

//actual function
int groovy_function(float blurb)
{
   //do something
   return(something);
}
The linker will know how to get the function's address into the function pointer. Works fine. I'm doing this kind of stuff regularly for processor specific optimizations (read: selecting SSE/3DNow/x87 versions of the same function).

Hth :)
 
zeckensack said:
No ... wait :D

whateverfunction_lib is a function pointer, not a function with a return type of a function pointer. Geddit? ;)

eg
int function(float);

int (*funtion_lib)(float);

function_lib is a pointer to a function taking a float and returning an int.

So you'll have to
1)define these pointers somewhere in your code (right now you only have the declaration which is not enough for an export).
2)initialize the function pointers to proper values. My guess would be that they ought to point to the functions they derive their names from.

Snippets
Code:
//the header with the macros
...
PROTOTYPE(groovy_function,int,(float));
Code:
//a c or cpp file that includes the header

//function pointer
groovy_function_t groovy_function_lib=groovy_function;

//actual function
int groovy_function(float blurb)
{
   //do something
   return(something);
}
The linker will know how to get the function's address into the function pointer. Works fine. I'm doing this kind of stuff regularly for processor specific optimizations (read: selecting SSE/3DNow/x87 versions of the same function).

Hth :)


Thankyou!!!

That works. It only takes a simple explanation for everything to make sence. In fact I can't believe I didn't see it. I won't say is simple, and obvious (I don't think it is). But if you apply some logic, well I guess it should! :D

Just to make sure my head wasn't stuck in the clouds the DLL promptly crashed where it always does. :( Same error. Not sure what's wrong. I hope it is nothing to do with ordinals being different in the new DLL.

There are currently 4 exports in the original DLL that are undefined in the spec. I think they are created by DirectX or something what do you think?


Code:
// ??0CSurfHeap@@QAE@II@Z; Index 1;	Information not available

// ??4CSurfHeap@@QAEAAV0@ABV0@@Z; Index 2;	Information not available

// ?AllocSurfMem@CSurfHeap@@QAE?AW4EC@@PAVCSurf@@@Z; Index 3;	Information not available

// ?DeallocSurfMem@CSurfHeap@@QAE?AW4EC@@PAVCSurf@@@Z; Index 4;	Information not available

// ?SetSurfMem@CSurfHeap@@QAE?AW4EC@@PAVCSurf@@I@Z; Index 5;	Information not available
 
euan said:
Just to make sure my head wasn't stuck in the clouds the DLL promptly crashed where it always does. :( Same error. Not sure what's wrong. I hope it is nothing to do with ordinals being different in the new DLL.

There are currently 4 exports in the original DLL that are undefined in the spec. I think they are created by DirectX or something what do you think?


Code:
// ??0CSurfHeap@@QAE@II@Z; Index 1;	Information not available

// ??4CSurfHeap@@QAEAAV0@ABV0@@Z; Index 2;	Information not available

// ?AllocSurfMem@CSurfHeap@@QAE?AW4EC@@PAVCSurf@@@Z; Index 3;	Information not available

// ?DeallocSurfMem@CSurfHeap@@QAE?AW4EC@@PAVCSurf@@@Z; Index 4;	Information not available

// ?SetSurfMem@CSurfHeap@@QAE?AW4EC@@PAVCSurf@@I@Z; Index 5;	Information not available
[/B]
These are definitely exports, not imports?
And they're exported by the original DLL which you are trying to rewrite, right?

That looks like some kind of Visual C function name mangling. It's hard to guess what these are.
Functions that are purely c, ie they are declared as extern "C", not overloaded and take/return only basic types are usually mangled as _name@8 or some other number (the number is the total size of arguments in bytes). If you get question marks, multiple @s and other stuff, you're probably dealing with functions that take class types or something.

Hard to guess what to do, sorry :(
 
I'm going to go on the assumption that they are not important, or are created by something else such as DirectX, or are there for debug purposes. I think (by sheer guess work), that they export the framebuffer surface, and the DLL's memory heap, or similiar. They are not part of the API, so hopefully games won't notice they're not there. :)

Thanks for your help.
 
Just a big thanks to zeckensack, and Boke for your help. I've managed to get off the ground. The application can now runs using a dummy dll to some extent. Well, it at least accepts the DLL as being compatible. :) I only have MSVC installed, so I haven't started much in the way of proper 3d coding. Luckily the app even spits out some debug data to the MSVC output window. Most cool. Here's my progress:

Code:
Load/start DirectDraw
ATI library start::
   Init
   create render context
   get card capabilities
DSoundInit
Loaded 'C:\WINDOWS\system32\wdmaud.drv', no matching symbolic information found.
Loaded 'C:\WINDOWS\system32\wdmaud.drv', no matching symbolic information found.
Loaded 'C:\WINDOWS\system32\msacm32.drv', no matching symbolic information found.
Loaded 'C:\WINDOWS\system32\msacm32.dll', no matching symbolic information found.
Loaded 'C:\WINDOWS\system32\midimap.dll', no matching symbolic information found.
Loaded 'C:\WINDOWS\system32\setupapi.dll', no matching symbolic information found.
Loaded 'C:\WINDOWS\system32\setupapi.dll', no matching symbolic information found.
Loaded 'C:\WINDOWS\system32\setupapi.dll', no matching symbolic information found.
Loaded 'C:\WINDOWS\system32\setupapi.dll', no matching symbolic information found.
Loaded 'C:\WINDOWS\system32\setupapi.dll', no matching symbolic information found.
Loaded 'C:\WINDOWS\system32\setupapi.dll', no matching symbolic information found.
Loaded 'C:\WINDOWS\system32\ksuser.dll', no matching symbolic information found.
    complete OK
DirectSound started OK
Loaded 'C:\WINDOWS\system32\mcicda.dll', no matching symbolic information found.
Loaded 'C:\WINDOWS\system32\dinput.dll', no matching symbolic information found.
Loaded 'C:\WINDOWS\system32\hid.dll', no matching symbolic information found.
Loaded 'C:\WINDOWS\system32\setupapi.dll', no matching symbolic information found.
InitialiseHardware:
SetHardwareVideoMode:
    Switching to 320x200
    Allocating front/back buffers
    Picking up back buffer
    Allocating Z-buffer
	Creating texture surfaces
DirectDraw error code 80004001 (16385)
Fatal DirectDraw error!
TerminateGame
Shutting down DirectDraw
TerminateLibrary:
The thread 0x6D8 has exited with code 1 (0x1).
The thread 0x3F8 has exited with code 1 (0x1).
The thread 0x5FC has exited with code 1 (0x1).
The thread 0x28C has exited with code 1 (0x1).
The thread 0x3EC has exited with code 1 (0x1).
The thread 0x67C has exited with code 1 (0x1).
The program 'D:\test\Debug\game.exe' has exited with code 1 (0x1).

I'm starting to feel confident again. I'll need to get the DX8 SDK installed (maybe 7 not sure yet, soon see). Don't know about that 320x200 resolution. I don't think the radeons support that leagacy kind anymore. I think the DX control panel will answer that one, or I figure out the command switches for the app, or a hex edit. The latter would probably be more fun. :hmm:

Anyway. Thanks lots! :)
 
Back
Top