Pinvoke与GCC在VB.net 2010中编译的c++dll有关
Pinvoke issues with GCC compiled c++ dll in VB.net 2010
好吧,我试着自己解决这个问题。这是我遇到的问题:
为了使函数在dll中工作,我必须在vb代码中发送一个结构的指针,因为我需要用文件中的数据填充结构,反之亦然。将函数编译为dll,然后尝试在vb中重写本机C函数会更容易,我从未像memmove()那样使用过这些函数。
Dll文件是有效的,因为我还编写了一个c++应用程序,它从Dll调用函数,从指针填充内存中的结构,然后在命令提示符中显示数据。我只需要弄清楚事物的视觉基础方面出了什么问题。
导出函数的c++标头信息
#define MAX_CHEATS 150
struct SCheat
{
uint32_t address;
uint8_t byte1;
uint8_t saved_byte;
bool enabled;
bool saved;
char name[22];
};
struct SCheatData
{
struct SCheat c[MAX_CHEATS];
uint32_t num_cheats;
};
__declspec(dllexport) int __cdecl S9xLoadCheatFile (const char *, struct SCheatData *Cheat);
__declspec(dllexport) int __cdecl S9xSaveCheatFile (const char *, struct ScheatData *Cheat);
我写了一个c++应用程序来测试dll的功能,它运行得很完美。
我还应该提到在github上找到的c++代码的原始版本。我只需要函数来加载/保存Snes9x的cht文件。如果我能弄清楚这一点,我可以很容易地添加其余的模拟器欺骗文件结构和加载/保存功能,我的应用程序将为任何模拟器生成cht文件,同时将所有欺骗保存在中央数据库中。
现在我们进入vb部分。
以下是我在应用程序中定义的结构和调用。
<StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)> _
Public Structure SCheat
<MarshalAs(UnmanagedType.U4)> Public address As UInteger
<MarshalAs(UnmanagedType.U4)> Public byte1 As Byte
<MarshalAs(UnmanagedType.U4)> Public saved_byte As Byte
<MarshalAs(UnmanagedType.U4)> Public enabled As Integer
<MarshalAs(UnmanagedType.U4)> Public saved As Integer
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=22)> Public name() As Char
End Structure
<StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)> _
Public Structure SCheatData
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=150)> Public Shared c() As SCheat = Arrays.InitializeWithDefaultInstances(Of SCheat)(150)
<MarshalAs(UnmanagedType.U4)> Public num_cheats As UInteger
End Structure
下面是我如何定义函数的。
<DllImport("c:minGWbinCheat_Functions.dll", CallingConvention:=CallingConvention.Cdecl)> _
Public Function _Z16S9xLoadCheatFilePKcP10SCheatData(ByVal filename As String, ByVal cheat As IntPtr) As Integer
End Function
Declare Function S9xLoadCheatFile Lib "c:minGWbinCheat_Functions.dll" Alias "_Z16S9xLoadCheatFilePKcP10SCheatData" (ByVal filename As String, ByRef cheat As IntPtr) As Integer
Declare Function S9xSaveCheatFile Lib "c:minGWbinCheat_Functions.dll" Alias "_Z16S9xSaveCheatFilePKcP10SCheatData" (ByVal filename As String, ByRef cheat As SCheatData) As Integer
我曾尝试通过ref传递该结构,但它崩溃了,出现了一条关于读/写受保护内存的非描述性消息。我尝试封送structuretoptr的一个变量,它走得更远了一点,但会破坏应用程序中的所有内存。我认为这是一个不完全理解pinvoke和编组实际工作方式的问题,或者可能我的结构与dll所寻找的不匹配。
如有任何帮助,我们将不胜感激。
编辑:很抱歉,我忘了你的目标是VB,不过你应该没有太大问题将我的代码翻译成它:D
以下对我有效:
using System;
using System.Runtime.InteropServices;
using System.Windows;
namespace WpfApplication3
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var intPtr = GetData();
var ptrToStructure = Marshal.PtrToStructure<SCheatData>(intPtr);
}
[DllImport("mydll.dll")]
private static extern IntPtr GetData();
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct SCheat
{
public uint address;
public byte byte1;
public byte saved_byte;
[MarshalAs(UnmanagedType.I1)] public bool enabled;
[MarshalAs(UnmanagedType.I1)] public bool saved;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 22)] public string name;
}
[StructLayout(LayoutKind.Sequential)]
public struct SCheatData
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 150, ArraySubType = UnmanagedType.Struct)] public SCheat[]
c;
public uint num_cheats;
}
}
}
和:
// mydll.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
typedef unsigned char uint8_t;
typedef unsigned int uint32_t;
#define MAX_CHEATS 150
struct SCheat
{
uint32_t address;
uint8_t byte1;
uint8_t saved_byte;
bool enabled;
bool saved;
char name[22];
};
struct SCheatData
{
struct SCheat c[MAX_CHEATS];
uint32_t num_cheats;
};
extern "C" __declspec(dllexport) SCheatData* GetData()
{
SCheatData* data = new SCheatData();
data->num_cheats = MAX_CHEATS;
for (size_t i = 0; i < MAX_CHEATS; i++)
{
SCheat c;
c.address = 1234;
c.byte1 = 0xAB;
c.saved_byte = 0xCD;
c.enabled = true;
c.saved = true;
strcpy(c.name, "abcdefghijklmnopqrstu");
data->c[i] = c;
}
return data;
}
我使用了PInvoke互操作助手,它对生成签名很有帮助,也要小心Marshal.PtrToStructure
的不同重载,因为并非所有风格都适用于任何情况。
好的,谢谢你的帮助,它做得不太好,但方向是我需要的答案。:)
代码修复。
C++标题:
__declspec(dllexport) int __cdecl S9xLoadCheatFile (const char *);
__declspec(dllexport) int __cdecl S9xSaveCheatFile (const char *);
__declspec(dllexport) SCheatData* __cdecl GetData();
struct SCheatData data1;
Dll.cpp:
SCheatData* __cdecl GetData()
{
return &data1;
}
在保存和加载函数中直接与structdata1交互。
VB代码。
<StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
Public Structure SCheat
Public address As UInteger
Public byte1 As Byte
Public saved_byte As Byte
<MarshalAs(UnmanagedType.I1)> Public enabled As Boolean
<MarshalAs(UnmanagedType.I1)> Public saved As Boolean
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=22, ArraySubType:=UnmanagedType.Struct)> Public name() As Char
End Structure
<StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
Public Structure SCheatData
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=150)> Public c() As SCheat
Public num_cheats As UInteger
End Structure
<DllImport("c:minGWbinCheat_Functions.dll", CallingConvention:=CallingConvention.Cdecl)> _
Public Function _Z16S9xLoadCheatFilePKc(ByVal filename As String) As Integer
End Function
<DllImport("c:minGWbinCheat_Functions.dll", CallingConvention:=CallingConvention.Cdecl)> _
Public Function _Z7GetDatav() As IntPtr
End Function
Private sub try()
Dim tryv As String = "C:\Users\Diane\Desktop\snes9x\Cheats\Super Mario World (U) [!].cht"
Dim anotherP As New SCheatData
MsgBox(_Z16S9xLoadCheatFilePKc(tryv))
anotherP = System.Runtime.InteropServices.Marshal.PtrToStructure(_Z7GetDatav(), GetType(SCheatData))
MsgBox(anotherP.num_cheats)
end sub
这适用于加载,从而验证结构是否正确。我认为这也适用于保存函数。至少我知道,如果我真的有问题,问题不会出在结构上。:)如果我在使用此保存功能时遇到问题,我会回复。
Edit,刚刚用System.Runtime.InteropServices.Marshal.StructeToPtr(anotherP,_Z7GetDatav,True)测试了反向,它成功了。所以我想我是做了一些正确定义结构的事情,而structuretoptr需要在dll中制作一个指针。要是我3天前知道这些事情就好了。谢谢你的帮助,尽管为了达到我的目的,我仍然需要把它弄得一团糟,但它给了我一个新的方向,这实际上很有帮助。
现在,我只需要为所有其他模拟器做同样的事情。哈哈。:)现在我有点明白了,应该不会花太长时间。
- 我可以将Visual Studio 2015头文件编译成dll并在VS2013中使用它吗?
- 编译 C++ dll Visual Studio 与 crt 库的链接错误
- 在SWIG和Visual Studio 2015中使用Java中编译的DLL
- swig c 预编译了DLL
- 在Visual Studio中使用Cygwin编译的dll的库函数时出错
- 在 Windows 8 中编译的 DLL 在 Windows 7 中不起作用
- 使用Linux C代码和标头文件来编译Windows DLL
- 如何从Delphi编译的DLL中调用C 中的功能
- 编译 TCL-DLL 包装器时出现的问题
- 在Windows 7下编译的Dll在Windows XP中不起作用
- 如何使用 mwArray 将字符串向量发送到 MATLAB 编译的 DLL
- Cython代码可以编译成dll吗?这样C++应用程序就可以调用它了
- 如何从预编译的dll中删除清单
- 名称篡改如何与使用不同编译器编译的DLL和LIB一起工作
- 使用Visual Studio 2010中使用Cygwin编译的DLL
- 将 CPP 库编译为 DLL,找不到 stdlib
- 在Visual Studio 2015中编译的DLL抛出0xc000007b错误
- 反编译文件.dll
- 编译C dll部署MATLAB代码时出现C2371错误
- 我如何用R和RCPP编译一个dll