我们有自己的粘合层代码thingamajig,它允许我们在我们的Win32 Delphi 程序中托管.NET 运行时。这使我们能够随着时间的推移逐步过渡到 .NET。
但是,我们不时会遇到一些问题,昨天我在 SO 上看到了一个关于 Jcl 的 .NET 主机实现的答案,所以我想看看是否有一些明显的差异。
原来有,但我不明白它做了什么,为什么,以及我是否需要这样做。我当然会尝试它,但我非常希望其他了解这个奇怪代码背后原因的人告诉我它的作用。
随着时间的推移,我们可能会切换到使用 Jcl 实现,但由于我们即将发布,除非为了解决当前问题绝对有必要,否则在这个级别的代码进行大修是不合理的,所以请不要t 只是建议我们切换。
无论如何,不同之处在于它们如何调用 .NET 函数以加载和绑定到 .NET 运行时,基本上它们如何调用从 .NET dll 导出的函数。
这是我的代码:
type
TCorBindToRuntimeEx = function(pwszVersion: PWideChar;
pwszBuildFlavor: PWideChar;
startupFlags: DWord; rclsid, riid: PGUID;
out ppv: IUnknown): Integer; stdcall;
...
var
CorBindToRuntimeEx : TCorBindtoRuntimeEx = nil;
...
CorBindToRuntimeEx := GetProcAddress(Runtimehandle, 'CorBindToRuntimeEx');
...
clsid := CLASS_CorRuntimeHost;
iid := IID_ICorRuntimeHost;
rc := CorBindToRuntimeEx('v2.0.50727', 'wks', 0, @clsid,
@iid, UnkRuntimeEngine);
现在,这里我只是简单地使用 GetProcAddress 将导出函数的地址加载到一个变量中,输入为stdcall
函数指针,然后调用它。这行得通,有点。正如我所说,在少数情况下会出现一些奇怪的错误消息。
好的,这是他们的代码,并特别注意带有汇编代码的函数。
function CorBindToRuntimeEx(pwszVersion, pwszBuildFlavor: PWideChar;
startupFlags: DWORD; const rclsid: TCLSID; const riid: TIID;
out pv): HRESULT; stdcall;
{$EXTERNALSYM CorBindToRuntimeEx}
...
var
_CorBindToRuntimeEx: Pointer = nil;
function CorBindToRuntimeEx;
begin
GetProcedureAddress(_CorBindToRuntimeEx, mscoree_dll,
'CorBindToRuntimeEx');
asm
mov esp, ebp
pop ebp
jmp [_CorBindToRuntimeEx]
end;
end;
...
OleCheck(CorBindToRuntimeEx(PWideCharOrNil(ClrVer),
PWideChar(ClrHostFlavorNames[Flavor]), Flags,
CLASS_CorRuntimeHost, IID_ICorRuntimeHost,
FDefaultInterface));
请注意,我已经稍微重新格式化了代码以避免在 SO 上出现水平滚动条,但只是添加了一些换行符和一些缩进,代码是原样的。
最后的调用可能无关紧要,它基本上会传递与我们相同的参数(请注意,我们将 0 作为选项值传递,但我们也尝试使用 Jcl 代码使用的相同特定参数,但问题仍然存在展示)。
所以,我的问题是,汇编代码是做什么的?我知道它在技术意义上是做什么的,我以前一直在编程汇编,所以它操纵堆栈指针。
问题是为什么它必须这样做。我只是不明白。
可能是堆栈帧毕竟不是吗? stdcall
今天请教我一些东西。
编辑:好的,相应地更改了我的代码,但我们的问题仍然存在,所以不是这样。看起来我毕竟会做一些 WinDbg 来挖掘第三方代码。