I'm new to DLL programming and checked out the FAQ about .dll programming, but can't find any help on this subject

FYI: I'm using RadASM with hutch's MASM32v8

I have my C++ program using an imported DLL from a C++ written dll. The prototype looks something like this


unsigned long __cdecl Detect_Bandwidth(unsigned long,unsigned long,int,int &,unsigned long &,unsigned long,struct tBandtestSettingsStruct *,char *)


If I try to make a function named Detect_Bandwith with 8 DWORDS as params, the program fails to load, telling me

The procedure entry point ?Detect_Bandwidth@@YAKKKHAAHAAKKPAUtBandtestSettingsStruct@@PAD@Z could not be located (...)


So I tried to name the proc as ?Detect_Bandwidth@@YAKKKHAAHAAKKPAUtBandtestSettingsStruct@@PAD@Z and puting that name in the .def file.
But then, the linker fails, telling me


BandTest.exp : error LNK2001: unresolved external symbol "unsigned long __cdecl Detect_Bandwidth(unsigned long,unsigned long,int,int &,unsigned long &,unsigned long,struct tBandtestSettingsStruct *,char *, ?? ) throw( ?? )" (?Detect_Bandwidth@@YAKKKHAAHAAKKPAUtBandtestSettingsStruct@@PAD)
BandTest.dll : fatal error LNK1120: 1 unresolved externals


The DLL itself is fine, and I know that for a fact (renaming the function and calling it from another Win32Asm program works).. The rule is that I want the original C++ clients to remain unchanged but to re-create the DLL in asm.

These are the settings of the asm
.386
.model flat,stdcall
option casemap:none
Posted on 2003-07-05 16:47:34 by FearHQ
When you use a DLL created in C you must decorate the name to use it in ASM

Detect_Bandwidth

becomes:

_Detect_Bandwidth@24

Where @24 is the number of BYTES it pushes onto the stack

In your code you would use
Detect_Bandwidth equ _Detect_Bandwidth@24

Detect_Bandwidth PROTO :DWORD, :DWORD, :DWORD, :DWORD, :DWORD, :DWORD, :DWORD, :DWORD
Posted on 2003-07-05 17:07:03 by donkey
donkey: Thanks for interveining so fast again :) However your solution did not fix the problem. I am not trying to use a C dll in asm, I'm trying to re-create the C dll in asm - to port it. I tried to give the function the "decorated" name
Detect_Bandwidth@@YAKKKHAAHAAKKPAUtBandtestSettingsStruct@@PAD@Z
and using that name in the .def, but the linker seems noone too happy about that.
Mabe it has to do with stdcall?
Posted on 2003-07-05 17:20:07 by FearHQ
If you use stdcall in your compiler directives it shouldn't be a problem.

.486
.model flat, stdcall ;32 bit memory model
option casemap :none ;case sensitive

I'm afraid that I don't use C so some-one else will have to help you.
Posted on 2003-07-05 17:28:07 by donkey
Show the code for the .h file the defines the Detect_Bandwidth function.

Just off the top of my head, if you wnat to use the dll without modifying any of the C++ code you will need to change the prototype to look like this:



extern "C" __declspec(dllimport) unsigned long __stdcall Detect_Bandwidth(unsigned long,unsigned long,int,int &,unsigned long &,unsigned long,struct tBandtestSettingsStruct *,char *)


The extern "C" tells the linker that the name is undecorated, so just call the proc Detect_Bandwith in the ASM file. You also need to the __stdcall because in your ASM file you state that are using the stdcall calling convention.
Posted on 2003-07-05 19:39:54 by Mecurius
Mecurius: I cannot change the prototype. Well, I can, but that's not the goal. Your suggestion will be helpfull for future projects I may encounter, but in this situation, I cannot modify the prototype, the headers or anything... Else I'd use simple undecorated calling convention as you specified... What I need here is to be able to redistribute the .dll without others having to change the main .exe one bit. What I have to do is to force the linker to accept the decorated name... But somehow that doesn't seem to work. I may be mistaken, and stdcall calling convention is not a must in my asm, I can choose whichever is more convenient for my function. Thank you for your sound advice though :) I don't have the .h at hand, but I'll look for it
Posted on 2003-07-05 21:13:26 by FearHQ
extern "C" tells the linker to use C linkage convention, of which the name decoration is just a part. Names in C are not undecorated, rather they are decorated with an underscore, but are still far less obfuscated than with the C++ convention.

If you can manage to change the program that calls the DLL you're trying to port to ASM, then I would recommend changing to C linkage for both the exe and the dll. It will make life easier.

If you cannot do anything about the exe, then just name the procedure as usual in your ASM source and then in your DEF file under the exports section use the format export_name = internal_name @ordinal where export_name is how the name is exported in the dll, internal_name is how you named it in the ASM source, and ordinal is the ordinal number of the exported procedure used in the original dll.

Use dumpbin on the original dll beforehand to see what the exported names and ordinals are.
Posted on 2003-07-05 21:15:03 by iblis
FearHQ,

Do you have the source for the DLL? If so make a static .lib out of the ASM proc, and in the Detect_Bandwidth's cpp file, call the ASM proc. Recompile and you should be good.

Ibilis,

You are incorrect. I just tested this. I used extern "C" to link to the test ASM dll without applying the _ and @N decoration using Studio 2002.



#include "stdafx.h"

extern "C"__declspec(dllimport) void __stdcall TestProc();
#pragma comment(lib, "C:\\masm32\\EXAMPLE1\\DLL\\TSTDLL.LIB")

int _tmain(int argc, _TCHAR* argv[])
{
TestProc();
return 0;
}

Posted on 2003-07-05 21:53:44 by Mecurius
No, I'm not. From MSDN:

"In C, the compiler prefixes names with an underscore. This is often called "decoration." In C++, name decoration is used to retain type information through the linkage phase."
Posted on 2003-07-05 22:10:20 by iblis
iblis: Thanks a million. I used what you suggested to accomplish what I needed to. But that's not all... The linker doesn't like the '@' sign in export name... Therefore I substituted the '@'s with '\' and edited the final dll to have '@'s instead. Works great. Ofcourse I had to change back to 'c' convention instead of stdcall (duh..)
Here's what my def file looked like for anyone else that would have the same problem


EXPORTS
?Detect_Bandwidth\YAKKKHAAHAAKKPAUtBandtestSettingsStruct\PAD\Z = Detect_Bandwidth @1


note that my solution is 'dirty' as it requires to hex edit the export name in the .dll later, but the first @ cuts the export name right there. Note that it was ordinal 1.

Mecurius: even though your solutions aren't applicable to the situation, it's still something to consider in other projects. Thanks for trying to solve the problem


Oh, and if anyone has a solution for allowing the '@' symbol in the export name, please post it for the sake of proper coding ;)
Posted on 2003-07-05 23:12:22 by FearHQ

The linker doesn't like the '@' sign in export name...


Hmm, it shouldn't mind it. What was the error message you got? I just tried it and it worked fine. There's also no mention of the @ symbol in the DEF specs.

If you're sure you made no other syntactic errors, maybe try enclosing the name in quotes and see if that works.


EDIT:
EXPORTS
? Detect_Bandwidth\YAKKKHAAHAAKKPAUtBandtestSetting
sStruct\PAD\Z = Detect_Bandwidth @1


You have a space between the ? and the rest of the name. If that quote was a copy and paste job from your DEF, then that might be your problem. You can't have spaces in your names.
Posted on 2003-07-06 02:23:03 by iblis
iblis: the linker gives no error, but the export in the .dll is clearly wrong. It cuts everything off after it ecnounters the @ symbol and links fine. So an exported name lile
MyName@blablablablabla becomes MyName

And something's wrong with the quote code in the forum itself. It added a line break and a space where it felt like placing one, which is rude :P
Links fine always, but ?Detect_Bandwith isn't exactly the name I want... Everything else is perfect, no place to mess up really... Just made a blank dll to test. Will work on this in the morning ;)
Posted on 2003-07-06 03:07:48 by FearHQ
Hmm, I have no idea what's wrong then.
It worked just fine for me.

In the DEF I put:
[size=12]?GetDLLVersion@@YGHPAUHWND__@@0PAD1HH@Z = GetDLLVersion @1[/size]

And dumpbin showed:
[size=12]1    0 0000100F ?GetDLLVersion@@YGHPAUHWND__@@0PAD1HH@Z[/size]

Maybe there's a linker option to tweak somewhere? I doubt it. I linked with the basics:
[size=12]kernel32.lib user32.lib /nologo /dll /machine:I386

/def:"testdll.def" /out:"testdll.dll"[/size]

Or maybe you have an different version of LINK. I'm using 6.00.8447. Other than that I don't know what to tell you, sorry.
Posted on 2003-07-06 04:12:12 by iblis
strange... this it the linker I got with MASM32v8 from hutch's page
"Microsoft (R) Incremental Linker Version 5.12.8078"

That's probably the reason... I linked with basics too
Posted on 2003-07-06 13:52:23 by FearHQ
If the mods don't mind, I or somebody could upload my LINK here for you. I don't know how legal that is though.
Posted on 2003-07-06 18:32:19 by iblis