Портируйте этот код C на Delphi/Lazarus
У меня есть этот код на C, который я хочу перенести в Delphi, но я не могу заставить его работать.
.CPP КОД
#include <Windows.h>
#include <io.h>
#include <stdio.h>
#include "GLibExp.h"
#pragma comment(lib, "GLib.lib")
void MyCFunc(LPCTSTR GStr)
{
GFile GVar = NULL;
GVar = GrfLoad(GStr, 1);
if ( !GVar )
{
printf("Error during loading!\n");
} else
printf("All fine!\n");
GrfFree(GVar);
system("pause");
}
void main()
{
CHAR StrG[MAX_PATH] = "Test.grf";
MyCFunc(StrG);
return;
}
GLibExp.h
#ifndef GLibExpH
#define GLibExpH
#if defined(GRF_DLL)
#define GEXPORT __declspec(dllexport)
#else
#define GEXPORT extern
#endif
class CGFILE;
typedef CGFILE* GFile;
//typedef void* GFile; //Also works like this
#ifdef __cplusplus
extern "C" {
#endif
GEXPORT GFile GrfLoad(const char *GName, unsigned char Mode = 1);
GEXPORT void GrfFree(GFile GVar);
#ifdef __cplusplus
}
#endif
#endif//GLibExpH
Программа вызывает DLL во время выполнения, чтобы использовать GRFLoad
а также GRFFree
функции. Я пытаюсь перенести это в Delphi, но безуспешно.
Код Delphi/Lazarus:
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;
{$Link GLib.lib}
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
{ TForm1 }
function GrfLoad(const fname: PChar; Modo: Boolean): Pointer; cdecl; external 'GLib.dll';
procedure TForm1.Button1Click(Sender: TObject);
var
PVar: Pointer;
begin
PVar:= GrfLoad(PChar('test.grf'),false);
end;
end.
Если я закомментирую строку {$Link GLib.lib}
программа запускается, но всегда вылетает при звонке GRFLoad
(программа перестает работать, а затем закрывается). Если я уйду в {$Link GLib.lib}
строка, программа не компилируется и сообщает об ошибке:
project1.lpr (20,1) Ошибка: незаконное использование COFF Magic при чтении GLib.lib
Есть намеки?
ПРИМЕЧАНИЕ. Я только что добавил ссылку на проект Visual C++ 2010 со всеми необходимыми файлами. Фактически, я только что создал "Новый проект -> Консольное приложение Win32" (я отмечаю "пустой проект" в мастере), добавил новый файл CPP, вставил код и изменил "Свойства -> Свойства конфигурации -> Линкер" - > Включить инкрементное связывание: НЕТ ", вот и все.
https://drive.google.com/open?id=1JxW4Wra_kT8gfBda1t0WWqagzazzQVne
2 ответа
Правильное объявление функций будет использовать PAnsiChar
(char
всегда является однобайтовым типом в C и C++):
type
GFile = Pointer; // alternatively: GFile = THandle;
function GrfLoad(const FName: PAnsiChar; Mode: Boolean): GFile; cdecl; external 'GLib.dll' name 'GrfLoad';
procedure grfFree(GVar: GFile); cdecl; external 'GLib.dll' name 'GrfFree';
Но вполне возможно, что экспортированные имена не GrfLoad
а также GrfFree
, но разные имена, например _GrfLoad
а также _GrfFree
, Вы можете узнать, какие имена на самом деле экспортируются, используя такой инструмент, как MS Dependency Walker или используя собственный Delumpi TDump.exe (см. Раздел "Экспорт"), т.е. используя
tdump glib.dll
в командной строке в каталоге, где находится glib.dll.
Если имена различаются, вам придется изменить части имен внешнего объявления, например external 'Glib.dll' name '_GrfLoad';
, так далее.
Еще немного информации в моей статье: Подводные камни конвертации.
Конечно, также возможно, что DLL не может найти другую DLL, от которой она зависит. Dependency Walker также расскажет вам о пропавшем импорте.
Обновить
Обратите внимание, что DLL в zip-файле, с которым вы связались, называется GrfLib.dll, а не GLib.dll. И имена действительно экспортируются как GrfLoad
и т.п.
Вполне возможно, что у вас есть glib.dll в вашей системе, но он не будет содержать функции, которые вы ищете.
Также обратите внимание, что большинство людей не любят скачивать zip из неизвестного источника. Они не могут знать, что на самом деле в этом.
Это решено! Я просто изменяю декларацию с:
function GrfLoad(const fname: PChar; Modo: Boolean): Pointer; cdecl; external 'GLib.dll';
чтобы:
function GrfLoad(const fname: PChar; Modo: Byte): Pointer; cdecl; external 'GLib.dll';
и звонок от:
PVar:= GrfLoad(PChar('test.grf'),false);
чтобы:
PVar:= GrfLoad(PChar('test.grf'),1);
И это все. спасибо Мбо, Виктории и Руди Велтуису за помощь.