Проблема с передачей дескриптора к управляемому объекту с помощью PInvoke
Я совершенно не понимаю, как передать дескриптор моего управляемого объекта из.Net в неуправляемый код. Сейчас я разрабатываю своего рода "драйвер" для Oracle Siebel CRM с использованием C#. И как я столкнулся с проблемой о том, как передать дескриптор в Driver API, есть такой метод:
ISCAPI ISC_RESULT CreateISCDriverInstance
/* in */(const ISC_STRING mediaTypeStr,
/* in */ const ISC_STRING languageCode,
/* in */ const ISC_STRING connectString,
/* in */ const struct ISC_KVParamList* datasetParams,
/* out */ ISC_DRIVER_HANDLE* handle);
И у меня есть проблема с последним параметром ISC_DRIVER_HANDLE* дескриптор. Я хочу сказать, что это может выглядеть довольно странно, но у меня нет определения типа ISC_DRIVER_HANDLE.
Насколько я знаю, можно использовать GCHandle для работы с этим... И вот мое видение того, как это должно быть реализовано:
[STAThread]
[DllExport("CreateISCDriverInstance", CallingConvention = CallingConvention.StdCall)]
public static int CreateIscDriverInstance([MarshalAs(UnmanagedType.LPWStr)] string mediaTypeStr,
[MarshalAs(UnmanagedType.LPWStr)] string languageCode,
[MarshalAs(UnmanagedType.LPWStr)] string connectString,
[In] ref IscKvParamList datasetParams,
out IntPtr handle)
{
... // Here I'm doing something with incoming data
var drvEntryPointHandle = GCHandle.Alloc(EntryPoints, GCHandleType.Pinned);
handle = GCHandle.ToIntPtr(drvEntryPointHandle);
return (int) ScErrorCode.ScEcOk;
}
Но после вызова этого метода я получу сбой CLR: (я ужасно сожалею о количестве следов)
ModLoad: C:\Debug\DriverLibrary.dll
ModLoad: C:\Windows\SysWOW64\MSCOREE.DLL
ModLoad: C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscoreei.dll
ModLoad: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
ModLoad: C:\Windows\SysWOW64\MSVCR120_CLR0400.dll
(730.4a4): Unknown exception - code 04242420 (first chance)
ModLoad: C:\Windows\assembly\NativeImages_v4.0.30319_32\mscorlib\d1265d6159ea876f9d63ea4c1361b587\mscorlib.ni.dll
ModLoad: \DriverLibrary.dll
ModLoad: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clrjit.dll
ModLoad: C:\Windows\Microsoft.NET\Framework\v4.0.30319\diasymreader.dll
ModLoad: NLog.dll
.......................................
ModLoad: C:\Windows\assembly\NativeImages_v4.0.30319_32\System.Runteb92aa12#\ad1a5e8488b493088c4317191604dc81\System.Runtime.Serialization.ni.dll
(730.4a4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
Вопрос: как передать дескриптор управляемого объекта из.Net в неуправляемое приложение? PS Дополнительная информация. Нехватка информации - главная проблема здесь. Документация, предоставленная Oracle, очень запутанная и неполная. Если у кого-то есть сомнения относительно усилий, которые были приложены к поиску информации... Вот ссылка на оригинальную документацию https://docs.oracle.com/cd/E14004_01/books/PDF/SiebCTIAdm.pdf (начинается с 260 стр.).
Но у меня есть пример, который был написан на Delphi около 10 лет назад. Я предоставлю некоторый код оттуда, который я думаю, может быть полезным. 1) Функция CreateISCDriverInstance(в классе TicISCCommunicationDriver)
function CreateISCDriverInstance(const AMediaTypeStr, ALanguageCode,
AConnectString: PWideChar; const AParams: TISCNamedParamList;
out ADriverHandle: THandle): HRESULT;
begin
try
ADriverHandle := TicISCCommunicationDriver.CreateInstance(AParams).Handle;
Result := SC_EC_OK;
except
Result := SC_EC_DRIVER_CREATION_ERR;
end;
end;
2) Определение части или TicISCCommunicationDriver:
TicISCCommunicationDriver = class(TObject)
strict private
class var
FInstance: TicISCCommunicationDriver;
...
var
FHandle: THandle;
...
3) Конструктор: функция класса TicISCCommunicationDriver.CreateInstance(const AParams: TISCNamedParamList): TicISCCommunicationDriver; начинать, если не назначено (FInstance), то FInstance:= TicISCCommunicationDriver.Create(AParams); Результат:= FInstance; конец;
constructor TicISCCommunicationDriver.Create(const AParams: TISCNamedParamList);
var
IsDebug: boolean;
begin
inherited Create;
FHandle := THandle(@Self);
...
end;
Я никогда ничего не разрабатывал в Delphi, но, насколько я могу судить - это шаблон синглтона, реализованный в Delphi. А также FHandle:THandle
это просто дескриптор экземпляра TicISCCommunicationDriver. После поиска в Google я обнаружил, что THandle - это дескриптор, идентифицирующий глобально распределенный объект динамической памяти. pps Также я попытался найти решение с помощью HandleRef, но это тоже не помогло.
2 ответа
GCHandle
нет места для этого параметра. Это используется для таких операций, как закрепление управляемой памяти. Этот дескриптор обеспечивается неуправляемым кодом. Это непрозрачный указатель.
Код Delphi, который, кстати, я знаю по вашему другому вопросу, немного странный, объявляет это THandle
, Это семантически отключено, потому что я не думаю, что этот дескриптор действительно Win32 HANDLE
,
Тем не менее, можно с уверенностью сказать, что эта ручка просто IntPtr
, Вы имеете дело с этим параметром в точности так, как я сказал в вашем предыдущем вопросе:
out IntPtr handle
Функция возвращает дескриптор своего состояния, вещи, которую функция только что создала. Вы помните это и затем передаете это другим функциям, которые нуждаются в этой обработке.
После исследования я обнаружил, что здесь handle - это указатель на экземпляр класса (где определен CreateISCDriverInstance). После передачи дескриптора Siebel он будет пытаться вызывать методы класса Driver по ссылке.
class Driver
{
private static readonly GCHandle gHandle;
static Driver
{
// ......
gHandle = GCHandle.Alloc(DriverEntryPoints.Instance, GCHandleType.Pinned);
}
[STAThread]
[DllExport("CreateISCDriverInstance", CallingConvention = CallingConvention.Cdecl)]
public static int CreateIscDriverInstance([MarshalAs(UnmanagedType.LPWStr)] string mediaTypeStr,
[MarshalAs(UnmanagedType.LPWStr)] string languageCode,
[MarshalAs(UnmanagedType.LPWStr)] string connectString,
[In] ref IscKvParamList datasetParams,
out IntPtr handle)
{
//...
handle = GCHandle.ToIntPtr(gHandle);
//...
}
}
ps Также вызывать преобразования - это Cdecl.