Click here to Skip to main content
15,885,546 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello guys.
I have a DLL containing this function:

function DCL_Initialize(bDeviceID: Byte; sIP: PAnsiChar): Byte; stdcall external 'DCL.dll';

now I want to call this function from C as this(somewhat simplified):
C++
#define DLL_EXPORT __declspec(dllexport) __stdcall
typedef char DLL_IMPORT DCLINITIALIZE(char bDeviceId, char *pStr);
pString = "Some string";
DCLINITIALIZE * pfnInitialize = (DCLINITIALIZE*)GetProcAddress(hModule, "DCL_Initialize");
if (pfnInitialize)
  pfnInitialize(1, pString);
The function doesn't return.
I think passing string to pascal routines from C may have special considerations.
My knowledge of pascal is very limited. and I don't know what is pAnsiChar;
Can anybody help me?

Edit:
I'm not sure the library is written in pascal. The only thing I know is its pascal prototype and that it works in a delphi application correctly.
pumpbin.exe /exports shows the names of funtions not capitalized

Edit2: string Software\Borland\Delphi\Locale found in DCL.dll several times, so it may be created by delphi

Edit3: The thread encounters a first chance exception and terminates. but the equivalent code in delphi works. the only thing to matter is passing char *sIP to
pascal function. is char * in C compatible to PAnsiChar in pascal?

Edit4: Visual studio 2013's debugger and delphi's debugger show different disassembly. Bellow is shown some part of both. The difference is marked by my comment.
C++
/11th assembly instruction in DCL_Initialize loaded by delphi 7
0029B8E7 55         push ebp
0029B8E8 688ABA2900 push $688ABA2900
0029B8ED 64FF30     push dword ptr fs:[eax]
0029B8F0 648920     mov fs:[eax], esp
//The following assembly instruction is two byte in delphi, 4 byte in C, and they are entirely different
0029B8F3 33DB       xor eax, eax    //different from C disassembler
0029B8F5 C605F0FF290000 mov byte ptr [$0029FFF0], $00
0029B8FC 33C0       xor eax, eax
0029B8FE 55     push ebp
0029B8FF 6863BA2C00 push $002CBA63
0029B904 64FF30     push dword ptr fs:[eax]
0029B907 648920     mov fs:[eax], esp
0029B90A 8A4508     mov al, [ebp+$08]
0029B90D E8FEFEFFFF call -$00000102
0029B912 85C0       test eax, eax
002CB914 740F       jz +$0f


//11th assembly instruction in DCL_Initialize loaded by C(Caller code compiled by visual studio 2010 or 2013)
004D52C7 55                   push        ebp
004D52C8 68 0E 55 4D 00       push        4D550Eh
004D52CD 64 FF 30             push        dword ptr fs:[eax]
004D52D0 64 89 20             mov         dword ptr fs:[eax],esp
//The following assembly instruction is two byte in delphi, 4 byte in C, and They are entirely different
004D52D3 C6 45 FF 00          mov         byte ptr [ebp-1],0   
004D52D7 C6 05 18 54 4E 00 00 mov         byte ptr ds:[4E5418h],0
004D52DE C6 05 20 54 4E 00 00 mov         byte ptr ds:[4E5420h],0
004D52E5 C6 05 19 54 4E 00 00 mov         byte ptr ds:[4E5419h],0
004D52EC 33 C0                xor         eax,eax
004D52EE 55                   push        ebp
004D52EF 68 E5 54 4D 00       push        4D54E5h
004D52F4 64 FF 30             push        dword ptr fs:[eax]  
004B52F7 64 89 20             mov         dword ptr fs:[eax],esp
004B52FA 8A 45 08             mov         al,byte ptr [ebp+8]
004B52FD E8 FA FD FF FF       call        039B50FC  
004B5302 85 C0                test        eax,eax
004B5304 74 11                je          039B5317  
And noticable is use of fs segment register in delphi dll. Is delphi's PE model is flat?
Edit5: dumpbin /disasm produces an assembly listing exactly matching that of C disassembly, different from disassembly of Delphi.
Posted
Updated 5-Jul-15 1:37am
v10

The pascal convention seems to be obsolete. Check here for more info:
https://msdn.microsoft.com/en-us/library/wda6h6df.aspx[^]

Good luck!
 
Share this answer
 
Comments
mr.abzadeh 2-Jul-15 8:55am    
I don't want to use pascal calling convention. I want to use a function in a dll whoes pascal prototype is known. source code not available
You have to simply provide a prototype for the function to call that is equivalent to PASCAL function.
In your case it should be:
C++
#pragma comment(lib, "DCL.lib")
#ifdef __cplusplus
extern "C" {
#endif
char __declspec(dllimport) WINAPI DCL_Initialize(char bDeviceID, char *sIP);
#ifdef __cplusplus
    }
#endif

The function name is normally all capitals in PASCAL. Delphi don't capitalize functions.
The pragma instructs the linker to include the library DCL.lib in the link stream, you have to pass to the linker the folder the dll is (normally the /I switch). If you don't have a typelibrary (DCL.lib) available for the dll you can use an utility to build a typelib from a DLL, i.e. Tlbexp.exe[^] from MS, or polib from PellesC[^].
Or loading dinamically the function as in your sample.
The pAnsiChar, aka PChar, type is equivalent to the null terminated C string.
If the function don't return you have to check with debugger to understand what happens. One problem could be due to Pascal compiler, while C is generally compliant PASCAL isn't. Maybe the calling convention is different.
I have also noticed that you removed the underscore between DCL and INITIALIZE in function name. Make a dump of DLL and check if both functions, DCL_INITIALIZE and DCLINITIALIZE, exists, in that case you are calling a different function.
 
Share this answer
 
v7
Comments
mr.abzadeh 2-Jul-15 8:51am    
That didn't work. The error is:
error LNK2019: unresolved external symbol "__declspec(dllimport) char __stdcall DCL_Initialize(char,char *)"
The function name in uppercase also didn't work. dumpbin.exe /exports shows the function name not capitalized. I'm not sure the DCL.DLL is written in pascal, The only thing I know is it's pascal prototype
function DCL_Initialize(bDeviceID: Byte; sIP: PAnsiChar): Byte; stdcall external 'DCL.dll';
is used in a delphi application and it works correctly.
I think using #pragma comment will not work here because the DCL.dll doesn't export function __imp_DCL_Initialize
Frankie-C 2-Jul-15 12:17pm    
The name of the function then is 'DCL_Initialize' because you got it with podump.
The __imp_DCL_Initialize should exist because it is automatically created from the linker when builds the jump table.
The #pragma comment tells to the linker to include the import library DCL.lib, not to change symbol. You can remove it and add DCL.lib to the linker input files list.
mr.abzadeh 2-Jul-15 13:04pm    
The DCL.lib is compiled and linked with borland delphi, and no __imp_... functions exist in it. There isn't any decorative problem, because I Get the address of function. dumpbin.exe with option /exports shows exactly the same name, no decoratation exists in DCL.dll. It is interesting that the function name is case sensitive. I think The only problem is compatibility of char * and PAnsiChar. Sorrily, I don't have a delphi or pascal compiler to test this problem on depth. Thanks a lot
Frankie-C 3-Jul-15 5:31am    
Sure the library name is undecorated. I refer to the decoration problem on C compiler side (and this could be correct using the 'extern C'). But I forget that even C will look for the decorated symbol DCL_Initialize@8 that doesn't exist in your library. What I don't understand is if you created an import library from the DLL or not. If you don't you'll never find aliased symbols.
Anyway using the GetProcedureAddress should solve the problem.
The not return problem can be related to parameters, as far as I know in C and Delphi they are pushed onto the stack in the same order (reversed respect as they are declared), but just to check you can try to reverse them in the function declaration.
Frankie-C 2-Jul-15 12:22pm    
Are you using C or C++? If you're using C++ the problem could be the decorations.
Try to include the declaration between 'extern C' See updated answer.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900