I need to call a function from C++ Dll (BVRelate.dll) through Visual Basic (VBWpf).
C++ dll code:
//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);
}
Then I try to call this function from VB (wpf project)
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
And I got an exception:
"MarshalDirectiveException was unhandled". An unhandled exception of type 'System.Runtime.InteropServices.MarshalDirectiveException' occurred in VBWpf.exe
Then I used dumpbin:
dumpbin /exports "M:\VBRelate.dll">M:\VBRelate.txt
and in VBRelate.txt was this:
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
Then I was trying to use def file, but not really fully understand how to use it (where should it be - with dll file, with project files or somewhere else) and why should I use it while using __declspec (not __stdcall). So I put the def file in the directory with dll file, and also with dll projects files:
; VBRelate.def - defines the exports for VBRelate.dll
LIBRARY VBRelate.dll
DESCRIPTION 'A C++ dll that can be called from VB'
EXPORTS
DoSomething
Then I rebuilt dll. It didn't work. The same exception appeared. And dumpbin returned the same dump, nothing was changed.
SOLVED
Adding extern "C" in dll function declaration and definition made it work.
//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);
}
}
so as I think the problem was in decorated name. After adding extern "C" the dump file looked like this:
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
So the function name now is right, but it was ?DoSomething@@YAXXZ