C# C“用于导入.dll的包装器”;试图读取或写入受保护内存“;

C# C“用于导入.dll的包装器”;试图读取或写入受保护内存“;,c#,.net,dll,vb6,pinvoke,C#,.net,Dll,Vb6,Pinvoke,经过大量的研究和实验,我仍然无法解决从外部库访问未管理函数的问题 快速相关的后台:我在Visual C++中编写了一个应用程序来驱动一个外部仪表,它通过USB连接到系统,但是虚拟化了一个串口,我注意到奇怪的输出行为。为了证明自己的正确性,制造商希望我使用他们的.dll从我的应用程序控制仪表。很好,但是 我无法将此.dll直接包含为引用(已删除名称和路径): 所以,为了使用它,我想必会去德林波特。我没有将代码直接包含到我的应用程序中,而是决定制作自己的程序集作为驱动程序的包装器,以便通过类访问功能

经过大量的研究和实验,我仍然无法解决从外部库访问未管理函数的问题

快速相关的后台:我在Visual C++中编写了一个应用程序来驱动一个外部仪表,它通过USB连接到系统,但是虚拟化了一个串口,我注意到奇怪的输出行为。为了证明自己的正确性,制造商希望我使用他们的.dll从我的应用程序控制仪表。很好,但是

我无法将此.dll直接包含为引用(已删除名称和路径):

所以,为了使用它,我想必会去德林波特。我没有将代码直接包含到我的应用程序中,而是决定制作自己的程序集作为驱动程序的包装器,以便通过类访问功能。在.dll上执行dumpbin/exports之后,我找到了所有函数的入口点,并制作了一个C#类库,如下所示,仅包括相关示例:

namespace Meter
{
    public class PortDrv
    {

        [DllImport("PortDrv.dll", EntryPoint = "SERIALNUMBER",
            CallingConvention = CallingConvention.StdCall,
            CharSet = CharSet.Auto)]
        public static extern long SerialNumber(Byte Index);

        [DllImport("PortDrv.dll", EntryPoint = "OPENPORT",
            CallingConvention = CallingConvention.StdCall,
            CharSet = CharSet.Auto)]
        public static extern int OpenPort();

    };
}
函数原型是从他们发给我的描述其库的.pdf文件中提取的:

SERIALNUMBER (ByVal Index As Byte) As Long
OPENPORT () As Integer
并在其示例VB程序中使用:

Private Declare Function SerialNumber Lib "PortDrv" Alias "SERIALNUMBER" (Index As Byte) As Long
Private Declare Function OpenPort Lib "PortDrv" Alias "OPENPORT" () As Integer
还和我在一起吗?好啊因此,在编译我自己的程序集之后,我将引用添加到我的应用程序中,并访问包装器:

int port_return = PortDrv::OpenPort(); 
Byte bite = 0x31;
__int64 serial = PortDrv::SerialNumber(bite);
但它在试图检索序列号后爆炸:

我也不确定我到底错在哪里。有些函数返回正确的信息,但似乎我必须传递信息才能失败。我已经尝试了所有不同的字符集和调用约定组合,我已经将ExactSpelling设置为true,等等。是否有明显的错误,或者我可以在当前环境中不使用此库


编辑:我忘了提到,我将“1”传递到函数中的原因是,如果只有一个仪表连接到系统,“索引”将是1。如果有2米,我可以通过输入'2'访问第二个。

您提供的示例VB程序:

Private Declare Function SerialNumber Lib "PortDrv" Alias "SERIALNUMBER" (Index As Byte) As Long  
不说
ByVal
。VB中的默认值是
ByRef
。这是你的错别字还是问题所在?如果是这样,您需要在序列号签名中说
ref Byte


寓意:总是说
ByRef
ByVal

哎哟。我认为制造商既不能为您提供.NET包装器,也不能为.NET环境提供工作示例代码?考虑到明显的困难,这似乎不是一个不合理的要求。你确定0x31是有效输入吗?@Cameron:我想是的。我也试过输入'1'和'1'。我想通过明确说明角色来排除所有可能的错误解释。或者您是在暗示我应该传入0x01,访问C#包装器类的代码似乎是C++/CLI代码。为什么要创建一个访问C/C++代码的C#包装器类。我猜C++/CLU的调用约定不是StdCall。VB中的整数数据类型大小为16位,长数据类型大小为32位。因此,我认为您必须更改互操作签名。对于SerialNumber,使用short代替int(OpenPort)和int代替long。上面这一行包含在他们使用驱动程序的示例程序中。看起来你可能认为那是我的代码,但不,我逐字逐句地写了出来,所以它是正确的。在他们的原型中,字节由val:
SERIALNUMBER(ByVal索引为byte)传递,长度为
。这是他们的问题吗?我将签名更改为ref Byte,内存故障已经消失,但函数仍然不返回任何内容(使用int和long)。我想标记你的答案是正确的,因为这是主题的重点,但由于我的问题还没有解决,我想暂时不谈。是的,我想原型是错的。谢谢你敏锐的目光,本。