1

我很困惑如何将句柄从.Net 传递给我的托管对象到非托管代码。现在我正在使用 C# 为 Oracle Siebel CRM 开发一种“驱动程序”。以及我如何面对如何将句柄传递给驱动程序 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(从 260p 开始。 )。

但是我有一些大约 10 年前用 Delphi 编写的示例。我将从那里提供一些我认为可能有用的代码。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 找到解决方案,但它也没有帮助。

4

2 回答 2

1

GCHandle该参数没有位置。这用于固定托管内存等操作。此句柄由非托管代码提供。它是一个不透明的指针。

Delphi 代码,顺便说一下,我从你的另一个问题中知道有点不稳定,将其声明为THandle. 这在语义上是不正确的,因为我不认为这个句柄真的是 Win32 HANDLE

但是,可以肯定地说,这个句柄只是一个IntPtr. 您完全按照我在上一个问题中的说明处理该参数:

out IntPtr handle

该函数产生一个指向它的状态的句柄,指向函数刚刚创建的东西。您记住它,然后将其传递给需要该句柄的其他函数。

于 2014-11-22T06:57:56.660 回答
0

经过调查,我发现这里的句柄是一个指向类实例的指针(其中定义了 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。

于 2014-11-28T13:01:08.180 回答