好吧,我已经试着自己解决这个问题了。这是我遇到的问题:
为了让函数在dll中工作,我必须在我的vb代码中发送一个指向结构的指针,因为我需要用来自文件的数据填充结构,反之亦然。将函数编译为dll会更容易,然后尝试用vb重写本机C函数,而我从来没有用过像memmove()这样的函数。
动态链接库文件可以工作,因为我还编写了一个c++应用程序,它从动态链接库调用函数,从指针填充内存中的结构,然后在命令提示符中显示数据。我只需要找出visual basic方面的问题所在。
导出函数的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++应用程序来测试动态链接库的功能,它工作得很完美。
我还应该提到在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:\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正在寻找的不匹配。
任何帮助都将不胜感激。
发布于 2015-03-24 23:24:48
EDIT:对不起,我忘了你的目标是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 Interop Assistant,它对生成签名非常有帮助,同时也要注意Marshal.PtrToStructure的不同重载,因为并不是所有的版本都适用于任何情况。
发布于 2015-03-25 04:53:58
好的,谢谢你的帮助,它并没有做到这一点,但方向是我需要的答案。:)
代码修复。
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;
}在save和load函数中直接与结构data1交互。
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:\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。:)不会花太长时间的,现在我有点明白了。
https://stackoverflow.com/questions/29221946
复制相似问题