如何从 VB 调用 C++ DLL 函数?
How to call C++ DLL function from VB?
我需要通过 Visual Basic (VBWpf) 从 C++ Dll (BVRelate.dll) 调用函数。
C++ dll代码:
//VBRelate.h
#ifdef VBRELATE_EXPORTS
#define VBRELATE_API __declspec(dllexport)
#else
#define VBRELATE_API __declspec(dllimport)
#endif
extern VBRELATE_API void DoSomething();
//VBRelate.cpp
#include <atlstr.h>
#include "VBRelate.h"
VBRELATE_API void DoSomething()
{
CString strOutput("Hello world");
MessageBox(NULL, strOutput, L"Got a message", MB_OK);
}
然后我尝试从 VB(wpf 项目)
调用这个函数
Imports System.Runtime.InteropServices
Class MainWindow
Declare Function DoSomething Lib "M:\VBRelate.dll" ()
Private Sub button_Click(sender As Object, e As RoutedEventArgs) Handles button.Click
DoSomething()
End Sub
End Class
我遇到了一个例外:
"MarshalDirectiveException was unhandled"。 'System.Runtime.InteropServices.MarshalDirectiveException' 类型的未处理异常发生在 VBWpf.exe
中
然后我用了dumpbin:
dumpbin /exports "M:\VBRelate.dll">M:\VBRelate.txt
在 VBRelate.txt 中是这样的:
Microsoft (R) COFF/PE Dumper Version 10.00.40219.01
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file M:\VBRelate.dll
File Type: DLL
Section contains the following exports for VBRelate.dll
00000000 characteristics
57E3DDA6 time date stamp Thu Sep 22 16:33:26 2016
0.00 version
1 ordinal base
1 number of functions
1 number of names
ordinal hint RVA name
1 0 00011299 ?DoSomething@@YAXXZ = @ILT+660(?DoSomething@@YAXXZ)
Summary
1000 .00cfg
4000 .data
1000 .gfids
1000 .idata
4000 .rdata
1000 .reloc
1000 .rsrc
10000 .text
10000 .textbss
1000 .tls
然后我尝试使用 def 文件,但并没有真正完全理解如何使用它(它应该在哪里 - 使用 dll 文件,使用项目文件或其他地方)以及为什么我应该在使用时使用它 __declspec(不是 __stdcall)。所以我把 def 文件放在 dll 文件和 dll 项目文件的目录中:
; VBRelate.def - defines the exports for VBRelate.dll
LIBRARY VBRelate.dll
DESCRIPTION 'A C++ dll that can be called from VB'
EXPORTS
DoSomething
然后我重建了dll。
它没有用。出现了同样的异常。 dumpbin 返回相同的转储,没有任何改变。
问题似乎不在 DLL/native C++ 代码中,尽管如果您将其设为托管 C++ dll 可能会怎样?异常是说处理托管 (VB) 和非托管 (C++) 代码之间的数据有问题:MarshalDirectiveException on MSDN
可以使用 MarshalAsAttribute()
msdn
更改属性
已解决
在 dll 函数声明和定义中添加 extern "C" 使其工作。
//VBRelate.h
#ifdef VBRELATE_EXPORTS
#define VBRELATE_API __declspec(dllexport)
#else
#define VBRELATE_API __declspec(dllimport)
#endif
extern "C" VBRELATE_API void DoSomething();
//VBRelate.cpp
extern "C"
{
VBRELATE_API void DoSomething()
{
CString strOutput("Hello world");
MessageBox(NULL, strOutput, L"Got a message", MB_OK);
}
}
所以我认为问题出在修饰名上。添加 extern "C" 后,转储文件如下所示:
Microsoft (R) COFF/PE Dumper Version 10.00.40219.01
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file M:\VBRelate.dll
File Type: DLL
Section contains the following exports for VBRelate.dll
00000000 characteristics
57E52794 time date stamp Fri Sep 23 16:01:08 2016
0.00 version
1 ordinal base
1 number of functions
1 number of names
ordinal hint RVA name
1 0 000112C1 DoSomething = @ILT+700(_DoSomething)
Summary
1000 .00cfg
4000 .data
1000 .gfids
1000 .idata
4000 .rdata
1000 .reloc
1000 .rsrc
10000 .text
10000 .textbss
1000 .tls
所以函数名现在是正确的,但它是?DoSomething@@YAXXZ
我需要通过 Visual Basic (VBWpf) 从 C++ Dll (BVRelate.dll) 调用函数。
C++ dll代码:
//VBRelate.h
#ifdef VBRELATE_EXPORTS
#define VBRELATE_API __declspec(dllexport)
#else
#define VBRELATE_API __declspec(dllimport)
#endif
extern VBRELATE_API void DoSomething();
//VBRelate.cpp
#include <atlstr.h>
#include "VBRelate.h"
VBRELATE_API void DoSomething()
{
CString strOutput("Hello world");
MessageBox(NULL, strOutput, L"Got a message", MB_OK);
}
然后我尝试从 VB(wpf 项目)
调用这个函数Imports System.Runtime.InteropServices
Class MainWindow
Declare Function DoSomething Lib "M:\VBRelate.dll" ()
Private Sub button_Click(sender As Object, e As RoutedEventArgs) Handles button.Click
DoSomething()
End Sub
End Class
我遇到了一个例外:
"MarshalDirectiveException was unhandled"。 'System.Runtime.InteropServices.MarshalDirectiveException' 类型的未处理异常发生在 VBWpf.exe
中然后我用了dumpbin:
dumpbin /exports "M:\VBRelate.dll">M:\VBRelate.txt
在 VBRelate.txt 中是这样的:
Microsoft (R) COFF/PE Dumper Version 10.00.40219.01
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file M:\VBRelate.dll
File Type: DLL
Section contains the following exports for VBRelate.dll
00000000 characteristics
57E3DDA6 time date stamp Thu Sep 22 16:33:26 2016
0.00 version
1 ordinal base
1 number of functions
1 number of names
ordinal hint RVA name
1 0 00011299 ?DoSomething@@YAXXZ = @ILT+660(?DoSomething@@YAXXZ)
Summary
1000 .00cfg
4000 .data
1000 .gfids
1000 .idata
4000 .rdata
1000 .reloc
1000 .rsrc
10000 .text
10000 .textbss
1000 .tls
然后我尝试使用 def 文件,但并没有真正完全理解如何使用它(它应该在哪里 - 使用 dll 文件,使用项目文件或其他地方)以及为什么我应该在使用时使用它 __declspec(不是 __stdcall)。所以我把 def 文件放在 dll 文件和 dll 项目文件的目录中:
; VBRelate.def - defines the exports for VBRelate.dll
LIBRARY VBRelate.dll
DESCRIPTION 'A C++ dll that can be called from VB'
EXPORTS
DoSomething
然后我重建了dll。 它没有用。出现了同样的异常。 dumpbin 返回相同的转储,没有任何改变。
问题似乎不在 DLL/native C++ 代码中,尽管如果您将其设为托管 C++ dll 可能会怎样?异常是说处理托管 (VB) 和非托管 (C++) 代码之间的数据有问题:MarshalDirectiveException on MSDN
可以使用 MarshalAsAttribute()
msdn
已解决
在 dll 函数声明和定义中添加 extern "C" 使其工作。
//VBRelate.h
#ifdef VBRELATE_EXPORTS
#define VBRELATE_API __declspec(dllexport)
#else
#define VBRELATE_API __declspec(dllimport)
#endif
extern "C" VBRELATE_API void DoSomething();
//VBRelate.cpp
extern "C"
{
VBRELATE_API void DoSomething()
{
CString strOutput("Hello world");
MessageBox(NULL, strOutput, L"Got a message", MB_OK);
}
}
所以我认为问题出在修饰名上。添加 extern "C" 后,转储文件如下所示:
Microsoft (R) COFF/PE Dumper Version 10.00.40219.01
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file M:\VBRelate.dll
File Type: DLL
Section contains the following exports for VBRelate.dll
00000000 characteristics
57E52794 time date stamp Fri Sep 23 16:01:08 2016
0.00 version
1 ordinal base
1 number of functions
1 number of names
ordinal hint RVA name
1 0 000112C1 DoSomething = @ILT+700(_DoSomething)
Summary
1000 .00cfg
4000 .data
1000 .gfids
1000 .idata
4000 .rdata
1000 .reloc
1000 .rsrc
10000 .text
10000 .textbss
1000 .tls
所以函数名现在是正确的,但它是?DoSomething@@YAXXZ