2013-09-07 3 views
3

У меня есть DLL C и вы хотите называть его из Delphi XE3 Update 2. Любопытно, что в моем проекте, называющем его динамически, он отличается от его статического старта. Вот «минимальный» код для воспроизведения (я изменил Lib/functionnames):Dynamic vs. Static DLL Linking is different

program testProject; 

{$APPTYPE CONSOLE} 
{$R *.res} 

uses 
    System.SysUtils, System.classes, Windows; 

function keylist_open (keylist: PPointer): Integer; external 'libLib'; 

var 
    Handle: HINST; 
    DLLName: PChar = 'libLib.dll'; 

type 
    Tkeylist_open = function(keylist: PPointer): Integer; stdcall; 

const 
    keylist_openDynamic: Tkeylist_open = nil; 

var 
    keylist: Pointer; 


begin 
    Handle := LoadLibrary(DLLName); 
    if Handle = 0 then 
     Exit; 
    @keylist_openDynamic := GetProcAddress(Handle, 'keylist_open'); 

    keylist_open(@keylist); 
    if (keylist = nil) then 
     Writeln('static: keylist is nil'); 
    keylist_openDynamic(@keylist); 
    if (keylist = nil) then 
     Writeln('dynamic: keylist is nil'); 
end. 

Выход

static: keylist is nil 

Это означает, что вызов функции динамически отличается от статически. keylist действительно инициализируется правильно, называя его динамически. смотрит в сгенерированный код на ассемблере я понимаю, что переменная 'KeyList' помещается в регистр EAX:

testProject.dpr.34: keylist_open(@keylist); 
004D16A2 B804B04D00  mov eax,$004db004 
004D16A7 E8ECC6FFFF  call keylist_open 

затем

testProject.dpr.12: function keylist_open (keylist: PPointer): Integer; external 'libLib'; 
004CDD98 FF255CC54D00  jmp dword ptr [$004dc55c] 

и другой прыжок

libLib.keylist_open: 
5B364508 E903A23D00  jmp $5b73e710 

, но затем dll (я не знаю, какая функция это, какая-то точка входа или подпрограмма), есть

5B73E710 55    push ebp 
5B73E711 8BEC    mov ebp,esp 
5B73E713 81ECDC000000  sub esp,$000000dc 
5B73E719 53    push ebx 
5B73E71A 56    push esi 
5B73E71B 57    push edi 
5B73E71C 8DBD24FFFFFF  lea edi,[ebp-$000000dc] 
5B73E722 B937000000  mov ecx,$00000037 
5B73E727 B8CCCCCCCC  mov eax,$cccccccc 
... 

кажется, что параметр eax перезаписан в eax. две строки позже код для динамического вызова:

testProject.dpr.37: keylist_openDynamic(@keylist); 

004D16CE 6804B04D00  push $004db004 
004D16D3 FF15F0564D00  call dword ptr [$004d56f0] 

прыжки

libLib.keylist_open: 
5B364508 E903A23D00  jmp $5b73e710 

и, таким образом, тот же код. Но поскольку параметр теперь не хранится в eax, перезапись eax не имеет значения.

звоните, кто-нибудь проливает свет здесь, что происходит неправильно, то есть что не так с моим статическим кодом и почему?

+0

крысы! это оно! не должен был полагаться на delphi-учебник, который связывал dll delpih, поэтому мысль stdcall предназначена только для динамической компоновки: (... большое спасибо !! – complexM

ответ

2

Две версии отличаются в соглашении о вызовах. Вариант связывания времени выполнения использует stdcall, а вариант связывания времени загрузки использует register.

Сделать совпадающие соглашения, и все будет хорошо.