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

时间:2012-05-03 18:11:37

标签: c# .net dll vb6 pinvoke

经过大量的研究和实验,我仍然无法弄清楚我从外部库中访问未管理的函数时遇到的问题。

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

我无法直接将此.dll作为参考(名称和路径已删除):enter image description here

所以为了使用它,我想起了DllImport。我决定将自己的程序集作为驱动程序的包装器,而不是将代码直接包含在我的应用程序中,因此我可以通过类访问该功能。在.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);

但是在尝试检索序列号后发生了炸弹:enter image description here

而且我不太确定我哪里出错了。某些函数会返回正确的信息,但看起来我必须将信息传递给失败。我尝试过CharSets&的所有不同组合。 CallingConventions,我已经将ExactSpelling设置为true,等等。有什么明显我做错了,或者我可以在当前环境中不使用这个库吗?

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

1 个答案:

答案 0 :(得分:5)

您提供的示例VB程序:

Private Declare Function SerialNumber Lib "PortDrv" Alias "SERIALNUMBER" (Index As Byte) As Long  

不说ByVal。 VB中的默认值为ByRef。这是你的错字还是问题?如果是这样,您需要在签名中将ref Byte说成SerialNumber。

道德:总是说ByRefByVal