У нас есть собственный клеевой слой-code-thingamajig, который позволяет нам размещать среду выполнения .NET в нашей программе Win32 Delphi. Это позволило нам постепенно перейти на .NET со временем.
Но время от времени у нас возникают некоторые проблемы, и вчера я увидел здесь ответ на SO, касающийся реализации хоста JNET .NET, поэтому я решил посмотреть, есть ли очевидные различия .
Оказывается, есть, но я не понимаю, что он делает, почему и нужно ли мне делать то же самое. Я, конечно, попробую, но я бы очень хотел, чтобы кто-то еще, понимающий причину этого странного кода, рассказал мне, что он делает.
Со временем мы могли бы перейти на использование реализации Jcl, но, поскольку у нас есть готовящийся к выпуску выпуск, если только это не является абсолютно необходимым для решения текущих проблем, то капитальный ремонт на этом уровне кода не оправдан, поэтому пожалуйста, не предлагайте нам просто поменяться.
В любом случае, разница заключается в том, как они обращаются к функциям .NET для загрузки и привязки к среде выполнения .NET, в основном к тому, как они вызывают экспортированные функции из библиотеки .NET.
Вот мой код:
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 покопаться в стороннем коде.