views:

1292

answers:

2

Can you tell me how do i use the following functions in my C program.

Delphi DLL - Exported functions :

function GetCPUID (CpuCore: byte): ShortString; stdcall;
function GetPartitionID(Partition : PChar): ShortString; stdcall;

I don't have the source code for that DLL so I must adapt my C program to that DLL and not the other way around.

I do the following and get error

typedef char* (_stdcall *GETCPUID)(BYTE);
typedef char* (_stdcall *GETPID)(PCHAR);
GETCPUID pGetSerial;
GETPID pGetPID

HMODULE hWtsLib = LoadLibrary("HardwareIDExtractor.dll");
if (hWtsLib){
pGetSerial = (GETCPUID)GetProcAddress(hWtsLib, "GetCPUID");
char *str = (char*) malloc(1024);
str = pGetSerial((BYTE)"1");

pGetPID= (GETPID )GetProcAddress(hWtsLib, "GetPartitionID");
char *str1 = (char*) malloc(1024);
str1 = pGetPID("C:");
}

Thanks

+2  A: 

ShortString is not the same as PChar (char *). It is an array of char with the first char being the length of the string. For C it is best you use PChar (char *) all the way.

procedure GetCPUID (CpuCore: byte; CpuId: PChar; Len: Integer); stdcall;
procedure GetPartitionID(Partition : PChar; PartitionId: PChar; Len: Integer); stdcall;

typedef (_stdcall *GETCPUID)(BYTE, char*, int);
typedef (_stdcall *GETPID)(PCHAR, char*, int);
GETCPUID pGetSerial;
GETPID pGetPID

HMODULE hWtsLib = LoadLibrary("HardwareIDExtractor.dll");
if (hWtsLib){
pGetSerial = (GETCPUID)GetProcAddress(hWtsLib, "GetCPUID");
char *str = (char*) malloc(1024);
pGetSerial((BYTE)"1", str, 1024);

pGetPID= (GETPID )GetProcAddress(hWtsLib, "GetPartitionID");
char *str1 = (char*) malloc(1024);
pGetPID("C:", str, 1024);
Lars Truijens
I don't have the source code for that DLL so I can adapt my C program to that DLL and not the other way around.
Altar
You could always write a Delphi wrapper to call the DLL returning PChar instead of ShortString
RobS
+7  A: 

Since you don't have the source to the DLL, you'll need to get a little creative on the C side of things. Even though the ShortString is listed as the function result, it is actually the responsibility of the caller to provide a location in which to place the result. Because this is a stdcall function, parameters are passed in from right to left, so that means that the address of the ShortString result is passed in last. To get this to line up, it will need to the first parameter listed. I'll do the first API, GetCPUID. In C, it might look something like this:

typedef struct ShortString {
  char len;
  char data[255];
};
typedef void (_stdcall *GETCPUID)(struct ShortString *result, BYTE cpuCore);

GETCPUID pGetSerial;

HMODULE hWtsLib = LoadLibrary("HardwareIDExtractor.dll");
if (hWtsLib) {
  ShortString serial;
  pGetSerial = (GETCPUID)GetProcAddress(hWtsLib, "GetCPUID");
  pGetSerial(&serial, '1');
  char *str = malloc(serial.len + 1); // include space for the trailing \0
  strlcpy(str, serial.data, serial.len);
  str[serial.len] = '\0'; // drop in the trailing null
}

I'll leave the GetPartitionID as an exercise for the reader :-).

Allen Bauer
The C compiler knows how to call stdcall functions, too. If the Delphi code is expecting it to be the last parameter, then declare it that way in the C code, too.
Rob Kennedy
The "function result" in this scenario is always passed as the last item on the stack. If there had been another parameter, it would have been declared in the same order as the Delphi declaration *after* the result param.
Allen Bauer
I don't think that '1' should be passed for cpuCore, then the parameter of the DLL function would probably be a char, not a byte. Putting 0 or 1 there seems to be much more logical.
mghie
I was merely following the example of the OP. It is up to them to ensure that the parameter is correct. Besides, that wasn't the focus of what was being asked.
Allen Bauer
Yes. The parameter for CpuCore is 0 for first CPU, 1 for the second and so on....For partition there should be "C" or "D" or....
Altar