Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/298.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将指针数组传递给非托管DLL函数_C#_Dll_Pinvoke_Dllimport - Fatal编程技术网

C# 将指针数组传递给非托管DLL函数

C# 将指针数组传递给非托管DLL函数,c#,dll,pinvoke,dllimport,C#,Dll,Pinvoke,Dllimport,我试图使用下面的C#代码创建并传递指向非托管DLL函数的指针数组 然而,在我最后一次通话时,我收到了一个AccessViolationException。我认为这与我传递的数组指针有关,但是我还没有找到解决方案 我在这里试图实现的最终目标是将指针传递给AndDevice_GetList,并使用参数outdevs留下一个由DLL填充的数组 让我知道如果你需要任何进一步的信息或有任何想法让我尝试 编辑: 这是我试图调用的函数 头文件: An_DLL AnError AnDevice_GetList(

我试图使用下面的C#代码创建并传递指向非托管DLL函数的指针数组

然而,在我最后一次通话时,我收到了一个
AccessViolationException
。我认为这与我传递的数组指针有关,但是我还没有找到解决方案

我在这里试图实现的最终目标是将指针传递给AndDevice_GetList,并使用参数
outdevs
留下一个由DLL填充的数组

让我知道如果你需要任何进一步的信息或有任何想法让我尝试

编辑:

这是我试图调用的函数

头文件:

An_DLL AnError AnDevice_GetList(AnCtx *ctx, AnDeviceInfo ***outdevs,
                            size_t *outndevs);
typedef struct AnDevice AnDevice;
typedef int AnError;
typedef struct AnCtx AnCtx;
和执行:

AnError AnDevice_GetList(AnCtx *ctx, AnDeviceInfo ***outdevs, size_t *outndevs)
{
    An_LOG(ctx, AnLog_DEBUG, "enumerate devices...");
    libusb_device **udevs;
    ssize_t ndevs = libusb_get_device_list(ctx->uctx, &udevs);
    if (ndevs < 0) {
        An_LOG(ctx, AnLog_ERROR, "libusb_get_device_list: %s",
               libusb_strerror(ndevs));
       return AnError_LIBUSB;
    }
    AnDeviceInfo **devs = malloc((ndevs + 1) * sizeof *devs);
    if (!devs) {
        An_LOG(ctx, AnLog_ERROR, "malloc: %s", strerror(errno));
        return AnError_MALLOCFAILED;
    }
    memset(devs, 0, (ndevs + 1) * sizeof *devs);
    size_t j = 0;
    for (ssize_t i = 0; i < ndevs; ++i) {
        libusb_device *udev = udevs[i];
        AnDeviceInfo info;
        An_LOG(ctx, AnLog_DEBUG, "device: bus %03d addr %03d",
           libusb_get_bus_number(udev), libusb_get_device_address(udev));
        if (populate_info(ctx, &info, udev))
            continue;
        An_LOG(ctx, AnLog_DEBUG, "vid 0x%04x pid 0x%04x",
               info.devdes.idVendor, info.devdes.idProduct);
        if (!match_vid_pid(info.devdes.idVendor, info.devdes.idProduct)) {
            An_LOG(ctx, AnLog_DEBUG, "  does not match Antumbra VID/PID");
            continue;
        }
        devs[j] = malloc(sizeof *devs[j]);
        if (!devs[j]) {
            An_LOG(ctx, AnLog_ERROR, "malloc: %s", strerror(errno));
            continue;
        }
        libusb_ref_device(udev);
        *devs[j] = info;
        ++j;
    }
    libusb_free_device_list(udevs, 1);
    *outdevs = devs;
    *outndevs = j;
    return AnError_SUCCESS;
}
a错误和设备列表(AnCtx*ctx、AnDeviceInfo***outdevs、size\u t*outndevs)
{
日志(ctx、AnLog调试,“枚举设备…”);
libusb_设备**udevs;
ssize_t ndevs=libusb_get_device_list(ctx->uctx,&udevs);
如果(无损检测值<0){
日志(ctx,日志错误,“libusb获取设备列表:%s”,
利布斯特罗(ndevs);
返回一个错误的LIBUSB;
}
AnDeviceInfo**devs=malloc((ndevs+1)*大小*devs);
如果(!devs){
日志(ctx,AnLog错误,“malloc:%s”,strerror(errno));
返回一个错误\u MALLOCFAILED;
}
成员集(开发者,0,(NDEV+1)*大小*DEV);
尺寸j=0;
对于(ssize_t i=0;i
在您的示例中,有些事情没有意义。您可以创建
ptr2
并为其分配空间,但从不将任何内容复制到该空间中,也不会将其传递给AndDevice\u GetList函数,因此这似乎完全没有必要。您创建了
ptArray
,但也从不在任何地方使用它

在这段代码中,您正在创建一个IntPtr结构的托管数组,并为每个结构分配内存,它们所指向的大小是单个指针的大小:

IntPtr[] ptArray = new IntPtr[] {
    Marshal.AllocHGlobal(IntPtr.Size),
    Marshal.AllocHGlobal(IntPtr.Size)
};
为了真正提供帮助,我们需要清楚地了解
和vice\u GetList
将要做什么。如果
andvice\u GetList
正在填充指针数组,它们指向什么?它们是否指向由
和device\u GetList
分配的结构?如果是这样,那么您要做的是创建一个
IntPtr
数组,并在进行非托管调用时将其固定。因为您正在为要填充的调用创建一个数组,所以不要将该数组作为out参数传递

[DllImport("libsomething.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern uint AnDevice_GetList(IntPtr outdevs);

IntPtr[] ptArray = new IntPtr[numberOfPointersRequired];
GCHandle handle = GCHandle.Alloc(ptArray);

try
{
    AnDevice_GetList(handle.AddrOfPinnedObject());
}
finally
{
    handle.Free();
}

我省略了其他参数,因为我不知道您在用它们做什么,也不知道您希望如何处理它们。

您的非托管函数声明如下:

AnError AnDevice_GetList(AnCtx *ctx, AnDeviceInfo ***outdevs, size_t *outndevs)
IntPtr ctx = ...; // create a context somehow
IntPtr devs;
IntPtr ndevs;
int retval = AnDevice_GetList(ctx, out devs, out ndevs);
if (retval != AnError_SUCCESS)
    // handle error
IntPtr ctx;
int retval = AnCtx_Init(out ctx);
if (retval != AnError_SUCCESS)
    // handle error
你应该把它翻译成:

[DllImport("libantumbra.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int AnDevice_GetList(IntPtr ctx, out IntPtr outdevs, 
    out IntPtr outndevs);
[DllImport("libantumbra.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int AnCtx_Init(out IntPtr octx);
这几乎和你做的一样。唯一的区别是返回值是
int
,而
outndevs
参数的类型是
IntPtr
。这是因为
size\u t
在我所知道的平台上是指针大小的

可以这样称呼:

AnError AnDevice_GetList(AnCtx *ctx, AnDeviceInfo ***outdevs, size_t *outndevs)
IntPtr ctx = ...; // create a context somehow
IntPtr devs;
IntPtr ndevs;
int retval = AnDevice_GetList(ctx, out devs, out ndevs);
if (retval != AnError_SUCCESS)
    // handle error
IntPtr ctx;
int retval = AnCtx_Init(out ctx);
if (retval != AnError_SUCCESS)
    // handle error
那么,你的代码哪里会出错呢?一种可能的解释是,您传递的上下文无效。另一种可能是您执行64位代码,翻译中的
outndevs
大小不正确导致了错误

这是一个很难使用p/invoke调用的API。使用
devs
现在可以做什么。您可以很容易地将值复制到
IntPtr[]
数组中。想必库中有一些函数可以在这些不透明的设备指针上运行。但是您必须保留
devs
,并将其传递回库以取消分配。想必库导出了一个函数来实现这一点


根据您的评论和各种更新,您似乎没有获得正确的上下文。我们只能猜测,但我希望
AnCtx\u Init
被声明为

AnError AnCtx_Init(AnCtx **octx)
这是指向不透明上下文的指针
AnCtx*
。将其翻译为:

[DllImport("libantumbra.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int AnDevice_GetList(IntPtr ctx, out IntPtr outdevs, 
    out IntPtr outndevs);
[DllImport("libantumbra.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int AnCtx_Init(out IntPtr octx);
可以这样称呼:

AnError AnDevice_GetList(AnCtx *ctx, AnDeviceInfo ***outdevs, size_t *outndevs)
IntPtr ctx = ...; // create a context somehow
IntPtr devs;
IntPtr ndevs;
int retval = AnDevice_GetList(ctx, out devs, out ndevs);
if (retval != AnError_SUCCESS)
    // handle error
IntPtr ctx;
int retval = AnCtx_Init(out ctx);
if (retval != AnError_SUCCESS)
    // handle error

现在你必须做的一件大事是开始检查错误。非托管代码不会引发异常。您需要自己进行错误检查。这是一项艰巨的任务,但必须完成。一次完成一个功能。一旦确定某个函数调用正在工作,请转到下一个。

未损坏的DLL始终是最好的使用方法:-)哎呀,我的糟糕,修复了。这是完全错误的。然而,没有人知道什么是正确的,因为我们看不到接口的另一面,也不知道如何调用它。因此,目前没有任何细节,你只能靠自己。首先,问问自己,除了它们被泄露之外,
ptArray
ptr2
会发生什么。任何地方都没有传递数组。可能你只是对非托管函数的翻译有误,不管它是什么。顺便说一句,adam nathans book.NET和COM是这类问题的圣经谢谢你的回答,我会尝试你的方法,因为它有意义。我已经用getList的标题和实现参考更新了我的帖子。我已经更新了我的帖子,包括了你的建议,但是我仍然收到了例外