获取 C# P/Invoke 调用 C++ dll 的正确参数时出现问题

问题描述 投票:0回答:2

尝试从 Oracle 的 Outside In API 互操作功能。 具有以下功能:

SCCERR EXOpenExport {VTHDOC hDoc, VTDWORD dwOutputId, VTDWORD dwSpecType, 
VTLPVOID pSpec, VTDWORD dwFlags, VTSYSPARAM dwReserved, VTLPVOID pCallbackFunc, 
VTSYSPARAM dwCallbackData, VTLPHEXPORT phExport);

从头文件中我将参数减少为:
typedef VTSYSPARAM VTHDOC、VTLPHDOC *
typedef DWORD_PTR VTSYSPARAM
typedef 无符号长 DWORD_PTR

typedef unsigned long VTDWORD   

typedef VTVOID* VTLPVOID  
#define VTVOID void  

typedef VTHDOC VTHEXPORT, *VTLPEXPORT  
These are for 32 bit windows 

浏览我找到的头文件、示例程序和文档:
1. pSpec 可能是指向缓冲区或 NULL 的指针,因此我将其设置为 IntPtr.Zero (文档)。
2. dwFlags 和 dwReserved 根据文档“必须由开发者设置为 0”。
3. 如果我不想处理回调,可以将 pCallbackFunc 设置为 NULL。
4. 最后两个基于我为使用 [StructLayout(LayoutKind.Sequential)] 编写的 C# 包装器的结构。然后实例化并生成参数,首先使用 Marshal.AllocHGlobal(Marshal.SizeOf(instance)) 创建一个 IntPtr,然后获取作为 dwCallbackData 的 uint 和 phExport 的 IntPtr 传递的地址值。

最终参数列表如下: 1. phDoc 作为 IntPtr,由 DAOpenDocument 函数加载地址 之前。
2. dwOutputId 作为 uint 设置为 1535,表示 FI_JPEGFIF
3. dwSpecType as int 设置为 2,表示 IOTYPE_ANSIPATH
4. pSpec 作为 IntPtr.Zero,输出将被写入其中
5. dwFlags as uint 按照指示设置为 0
6. dwReserved as uint 按照指示设置为 0
7. pCallbackFunc 作为 IntPtr 设置为 NULL,因为我将处理结果
8. dwCallBackDate 作为 uint 结构体缓冲区的地址
9. phExport 作为 IntPtr 到另一个结构缓冲区

仍然从 API 收到未定义的错误。这意味着调用返回一个未在任何头文件中定义的 961。过去,当我选择的参数类型不正确时,我就会遇到这种情况。
我开始使用 Interop Assistant,它有助于了解有多少参数类型被翻译。然而,它受到我从头文件中收集正确的本机类型的能力的限制。例如前面函数中使用的hDoc参数被定义为非文件系统句柄,因此尝试使用Marshal创建句柄,然后使用IntPtr,最后结果是一个int(实际上是这里使用的&phDoc) ).
那么除了反复试验之外,还有更科学的方法吗?
吉姆

c# pinvoke oracle-outside-in
2个回答
0
投票

您可以搜索 http://pinvoke.net 寻找现有解决方案,或者您可以尝试 PInvoke Signature Toolkit。这些可能会提供一些帮助。


0
投票

您的定义:

typedef unsigned long DWORD_PTR;

不正确 —

DWORD_PTR
定义为:

typedef ULONG_PTR DWORD_PTR;

依次定义为:

typedef unsigned __int3264 ULONG_PTR;

属性

__int3264
已记录在here,我正在重现最重要的一点:

关键字

__int3264
指定具有以下属性的整型:

  • 在 32 位平台上它是 32 位的
  • 在 64 位平台上是 64 位
  • 它在线上是 32 位的,以实现向后兼容性。它在发送端被截断,并在接收端被适当扩展(签名或未签名)。

当您编组 C“类型”(例如

DWORD_PTR
)时,其大小取决于平台指针大小,这通常是操作系统参数的情况(例如
LPARAM
WPARAM
LRESULT
SIZE_T
、等),如名称
VTSYSPARAM
所示,您应该使用
IntPtr
,而不是
uint

基本上:

  1. dwReserved
    uint
    按照指示设置为
    0

应该是:

  1. dwReserved
    IntPtr
    按照指示设置为
    IntPtr.Zero

然后它应该可以工作,如果没有,您需要确保在整理必要的结构时没有犯类似的错误。

© www.soinside.com 2019 - 2024. All rights reserved.