Как импортировать функцию из DLL, сделанной в Delphi?

Можете ли вы сказать мне, как я могу использовать следующие функции в моей программе C.

Delphi DLL - Экспортируемые функции:

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

У меня нет исходного кода для этой DLL, поэтому я должен адаптировать свою программу на C к этой DLL, а не наоборот.

Я делаю следующее и получаю ошибку

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:");
}

Спасибо


person Z80    schedule 04.03.2009    source источник
comment
Какую именно ошибку вы получаете? Без этой информации трудно помочь.   -  person rusvdw    schedule 04.03.2009
comment
Программа компилируется и запускается, но происходит сбой при вызове функции DLL.   -  person Z80    schedule 05.03.2009


Ответы (2)


Поскольку у вас нет исходного кода DLL, вам нужно проявить немного творчества на стороне C. Несмотря на то, что ShortString указан как результат функции, на самом деле вызывающий объект несет ответственность за предоставление места для размещения результата. Поскольку это функция stdcall, параметры передаются справа налево, так что это означает, что адрес результата ShortString передается последним. Чтобы это выровнялось, ему потребуется первый параметр в списке. Я сделаю первый API, GetCPUID. В C это может выглядеть примерно так:

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
}

Я оставлю GetPartitionID в качестве упражнения для читателя :-).

person Allen Bauer    schedule 04.03.2009
comment
Компилятор C также знает, как вызывать функции stdcall. Если код Delphi ожидает, что это будет последний параметр, объявите его таким же образом и в коде C. - person Rob Kennedy; 04.03.2009
comment
Результат функции в этом сценарии всегда передается как последний элемент в стеке. Если бы был другой параметр, он был бы объявлен в том же порядке, что и объявление Delphi после параметра результата. - person Allen Bauer; 04.03.2009
comment
Я не думаю, что для cpuCore следует передавать «1», тогда параметр функции DLL, вероятно, будет символом, а не байтом. Ставить 0 или 1 кажется гораздо логичнее. - person mghie; 04.03.2009
comment
Я просто следовал примеру ОП. Именно они должны убедиться, что параметр правильный. Кроме того, это не было целью того, о чем спрашивали. - person Allen Bauer; 04.03.2009
comment
Да. Параметр для CpuCore равен 0 для первого процессора, 1 для второго и т. д. Для раздела должен быть C или D или.... - person Z80; 05.03.2009

ShortString — это не то же самое, что PChar (char *). Это массив символов, первый символ которого представляет собой длину строки. Для C лучше всего использовать PChar (char *) полностью.

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);
person Lars Truijens    schedule 04.03.2009
comment
У меня нет исходного кода для этой DLL, поэтому я могу адаптировать свою программу на C к этой DLL, а не наоборот. - person Z80; 04.03.2009
comment
Вы всегда можете написать оболочку Delphi для вызова DLL, возвращающей PChar вместо ShortString. - person RobS; 05.03.2009