首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在VB.net 2010中使用GCC编译的c++动态链接库的Pinvoke问题

在VB.net 2010中使用GCC编译的c++动态链接库的Pinvoke问题
EN

Stack Overflow用户
提问于 2015-03-24 06:54:26
回答 2查看 221关注 0票数 0

好吧,我已经试着自己解决这个问题了。这是我遇到的问题:

为了让函数在dll中工作,我必须在我的vb代码中发送一个指向结构的指针,因为我需要用来自文件的数据填充结构,反之亦然。将函数编译为dll会更容易,然后尝试用vb重写本机C函数,而我从来没有用过像memmove()这样的函数。

动态链接库文件可以工作,因为我还编写了一个c++应用程序,它从动态链接库调用函数,从指针填充内存中的结构,然后在命令提示符中显示数据。我只需要找出visual basic方面的问题所在。

导出函数的c++头信息

代码语言:javascript
运行
复制
#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++应用程序来测试动态链接库的功能,它工作得很完美。

我还应该提到在github上找到的c++代码的原始版本。我只需要为Snes9x加载/保存cht文件的函数。如果我能弄清楚这一点,我就可以很容易地添加其余的仿真器作弊文件结构和加载/保存函数,我的应用程序将为任何仿真器生成cht文件,同时将所有作弊保存在中央数据库中。

现在我们来看看vb部分。

以下是我在应用程序中定义的结构和调用。

代码语言:javascript
运行
复制
<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

下面是我定义函数的方式。

代码语言:javascript
运行
复制
<DllImport("c:\minGW\bin\Cheat_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:\minGW\bin\Cheat_Functions.dll" Alias "_Z16S9xLoadCheatFilePKcP10SCheatData" (ByVal filename As String, ByRef cheat As IntPtr) As Integer


Declare Function S9xSaveCheatFile Lib "c:\minGW\bin\Cheat_Functions.dll" Alias "_Z16S9xSaveCheatFilePKcP10SCheatData" (ByVal filename As String, ByRef cheat As SCheatData) As Integer

我尝试通过ref传递结构,但它崩溃了,并显示了一条关于读/写受保护内存的非描述性消息。我尝试封送structuretoptr的一个变量,它走得有点远,但会损坏应用程序中的所有内存。我认为这是一个没有完全理解pinvoke和封送是如何工作的问题,或者可能我的结构与dll正在寻找的不匹配。

任何帮助都将不胜感激。

EN

回答 2

Stack Overflow用户

发布于 2015-03-24 23:24:48

EDIT:对不起,我忘了你的目标是VB,不过把我的代码翻译成它应该没什么问题:D

下面的方法对我很有效:

代码语言:javascript
运行
复制
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;
        }
    }
}

和:

代码语言:javascript
运行
复制
// 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 Interop Assistant,它对生成签名非常有帮助,同时也要注意Marshal.PtrToStructure的不同重载,因为并不是所有的版本都适用于任何情况。

票数 1
EN

Stack Overflow用户

发布于 2015-03-25 04:53:58

好的,谢谢你的帮助,它并没有做到这一点,但方向是我需要的答案。:)

代码修复。

C++报头:

代码语言:javascript
运行
复制
__declspec(dllexport) int __cdecl S9xLoadCheatFile (const char *);
__declspec(dllexport) int __cdecl S9xSaveCheatFile (const char *);

__declspec(dllexport) SCheatData* __cdecl GetData();
struct SCheatData data1;

Dll.cpp:

代码语言:javascript
运行
复制
SCheatData* __cdecl GetData()
{
   return &data1;
}

在save和load函数中直接与结构data1交互。

VB代码。

代码语言:javascript
运行
复制
<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:\minGW\bin\Cheat_Functions.dll", CallingConvention:=CallingConvention.Cdecl)> _
Public Function _Z16S9xLoadCheatFilePKc(ByVal filename As String) As Integer
End Function
<DllImport("c:\minGW\bin\Cheat_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

这适用于加载,它验证结构是正确的。我认为这也应该适用于save函数。至少我知道,如果我真的对它有问题,问题不会出在结构上。:)如果我在使用此保存功能时遇到问题,我会发回。

编辑,刚刚用System.Runtime.InteropServices.Marshal.StructureToPtr(anotherP,_Z7GetDatav测试了反转,它工作了。所以我猜我做的是一些事情,正确地定义了结构,而structuretoptr需要在dll中创建一个指针。如果我3天前就知道这些事情就好了。谢谢你的帮助,尽管我仍然需要对它进行一点修改才能达到我的目的,但它给了我一个新的方向去寻找,这实际上是有帮助的。

现在,我只需要对所有其他仿真器执行相同的操作。LOL。:)不会花太长时间的,现在我有点明白了。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29221946

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档