In MFC there are no methods defined as CWnd::SetWindowTextA/CWnd::SetWindowTextW, yet the following code will compile and run correctly depending on Unicode settings:
//UNICODE is defined
BOOL CMyDialog::OnInitDialog()
{
CDialogEx::OnInitDialog();
//this line won't compile as expected
//SetWindowTextA(L"ANSI");
//this line compiles, but CWnd::SetWindowTextW doesn't exits
//SetWindowTextW ends up calling CWnd::SetWindowText
SetWindowTextW(L"Unicode");
return TRUE;
}
//UNICODE is not defined
BOOL CMyDialog::OnInitDialog()
{
CDialogEx::OnInitDialog();
//this line compiles, but CWnd::SetWindowTextA doesn't exits!
//SetWindowTextA ends up calling CWnd::SetWindowText
SetWindowTextA("ANSI");
//this line won't compile as expected
//SetWindowTextW(L"Unicode");
return TRUE;
}
It makes sense that SetWindowText is mapped in to SetWindowTextA/SetWindowTextW depending on the macro. But I don't understand how wnd->SetWindowTextA/wnd->SetWindowTextW get mapped back in to CWnd::SetWindowText.
It's a side effect of the macro declaration in WinUser.h. It applies not only to the global function declaration for the Windows API, but also any other identifier named SetWindowText that appears in code: global, local, or class scope.
#ifdef UNICODE
#define SetWindowText SetWindowTextW
#else
#define SetWindowText SetWindowTextA
#endif // !UNICODE
So any C++ class that declares a method called SetWindowText gets all that method implicitly converted by the preprocessor.
I don't have MFC installed, but I do know this method exists for the CWindow class on ATL and is defined as follows.
class CWindow
{
public:
...
BOOL SetWindowText(_In_z_ LPCTSTR lpszString) throw()
{
ATLASSERT(::IsWindow(m_hWnd));
return ::SetWindowText(m_hWnd, lpszString);
}
...
};
But at compile time, the above code (for a debug build) is going to get converted by the preprocessor into something like the following:
BOOL SetWindowTextW( LPCTSTR lpszString) throw()
{
(void)( (!!((::IsWindow(m_hWnd)))) || (1 != _CrtDbgReportW(2, L"c:\\program files...
return ::SetWindowTextW(m_hWnd, lpszString);
}
Ironically, the LPCTSTR method parameter is typedef'd instead of being a macro replacement, but you get the idea.
If you have a large enough Windows application, chances are very high that one of your existing C++ classes that you defined yourself has a method or member variable that matches a Windows API. And it's getting the same treatment.
Related
I write a Unicode DLL in Visual C++ 6.0. Then try to invoke the DLL function from Delphi XE3.
When I debug in Delphi, when step over the line to invoke the DLL function, I will always get an Access violation exception.
However, when I debug in Visual C++, I can see all parameters passed from Delphi are correct and I can step over all codelines without any exceptions.
If running outside the debugger, then I will not see any "access violation exceptions.
I try many methods but still cannot figure out how to eliminate the exception when debuggin in Delphi.
Below is the code in Visual C++ 6.0 part:
TestDLL.cpp:
extern "C" VOID WINAPI Test(CONST MESSAGEPROC lpMessageProc, LPVOID lParam)
{
if (lpMessageProc != NULL)
(*lpMessageProc)(1500, (const LPVOID)(LPCTSTR)CString((LPCSTR)IDS_MYTEST), lParam);
/*
if (lpMessageProc != NULL)
(*lpMessageProc)(1500, (const LPVOID)(LPCTSTR)CString(_T("Test")), lParam);*/
}
TestDLL.h:
// TestDLL.h : main header file for the TESTDLL DLL
//
#if !defined(AFX_TESTDLL_H__38054A53_5CEE_4ABF_9BA8_BCE427FCB8E1__INCLUDED_)
#define AFX_TESTDLL_H__38054A53_5CEE_4ABF_9BA8_BCE427FCB8E1__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif
#include "resource.h" // main symbols
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef BOOL (CALLBACK* MESSAGEPROC)(CONST DWORD dwMessageId, CONST LPVOID lp, LPVOID lParam);
VOID WINAPI Test(CONST MESSAGEPROC lpMessageProc, LPVOID lParam);
#ifdef __cplusplus
}
#endif
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_TESTDLL_H__38054A53_5CEE_4ABF_9BA8_BCE427FCB8E1__INCLUDED_)
Below is the codes in Delphi XE3 part:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
public
{ Public declarations }
end;
PForm1 = ^TForm1;
TMessageProc = function (const dwMessageId: DWORD; const lp: Pointer; lParam: Pointer): BOOL; stdcall;
{$EXTERNALSYM TMessageProc}
var
Form1: TForm1;
procedure Test(const lpMessageProc: TMessageProc; lParam: Pointer); stdcall;
implementation
{$R *.dfm}
procedure Test; external 'TestDLL.dll' index 2;
function MessageProc(const dwMessageId: DWORD; const lp: Pointer; lParam: Pointer): BOOL; stdcall;
begin
Result := True;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Test(MessageProc, #Self); // <---- This code line will cause "access violation
end;
I belive the problem occurs in DLL test function, when it try to load string from resource using CString((LPCSTR)IDS_MYTEST). If I change the code to CString(_T("Test")), then problem disappears.
Thanks
As you surmised, this statement will not work:
CString((LPCSTR)IDS_MYTEST)
Although this constructor of CString does allow you to pass it a resource ID, it will try to find the resource in the calling process's (ie, the Delphi EXE's) resources, not in the DLL's resources. You need to use the HINSTANCE of the DLL, as provided by the DLL's DllMain(), when loading strings from the DLL's resources. You can use the CString::LoadString() method for that, eg:
HINSTANCE hInst;
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
hInst = hinstDLL;
return TRUE;
}
extern "C" VOID WINAPI Test(CONST MESSAGEPROC lpMessageProc, LPVOID lParam)
{
if (lpMessageProc != NULL)
{
CString str;
str.LoadString(hInst, IDS_MYTEST);
(*lpMessageProc)(1500, (LPCTSTR)str, lParam);
}
}
I finally figure out this is a bug of MFC codes(VC6.0 version).
I don't know if I can post MFC source codes so I will just paste the function headers and related parts only.
In Microsoft Visual Studio\VC98\MFC\SRC\STRCORE.CPP, we can see the following 3 functions:
//////////////////////////////////////////////////////////////////////////////
// More sophisticated construction
CString::CString(LPCTSTR lpsz) // Function 1
{
Init();
if (lpsz != NULL && HIWORD(lpsz) == NULL)
{
UINT nID = LOWORD((DWORD)lpsz);
if (!LoadString(nID))
TRACE1("Warning: implicit LoadString(%u) failed\n", nID);
}
else
{
// Construct string normally
}
}
/////////////////////////////////////////////////////////////////////////////
// Special conversion constructors
#ifdef _UNICODE
CString::CString(LPCSTR lpsz) // Function 2
{
// Construct string normally
}
#else //_UNICODE
CString::CString(LPCWSTR lpsz) // Function 3
{
// Construct string normally
}
#endif //!_UNICODE
As we can see in the above code snippet, only function 1 contains codes that will take special process on lpsz and check if it is a string resource ID, if yes, then load the string from the resource. Both function 2 & 3 have no such special processes.
When we create a project in VS6, the default settings for a project is _MBCS, in such a case, function 1 will become
CString::CString(LPCSTR lpsz)
so CString((LPCSTR)nResID) will actually invoke function 1 and load string resource properly.
Function 2 will be disabled since _UNICODE is not defined. And function 3 works with wide char strings.
Therefore, for _MBCS project, everything works perfectly and consistently with the MSDN document.
However, when I change _MBCS to _UNICODE, function 1 will become
CString::CString(LPCWSTR lpsz)
Fucntion 2 will be enabled and function 3 will be disabled.
So CString((LPCSTR)nResID) will actually invoke function 2, which does NOT have special process to load string resource, which makes the problem.
There are two solutions for this problem:
Always use CString((LPCTSTR)nResID) instead of CString((LPCSTR)nResID) to load a string from resource. However, this usage is inconsistent with MSDN document so we have to call it as an undocumented usage.
Always use LoadString to load a string resource.
Though solution 1 is a little simpler, it is an undocumented usage so I finally opt solution 2 to solve my problem.
Many thanks to all your helps in solving this issue.
i am trying to make a c++ DLL project in VS2017 to use in a VB.NET VS2017 project.
the c++ code;
MyCudaLib.h
#ifndef DLL3_H
#define DLL3_H
#ifdef DLL3_EXPORTS
#define DLL3_API __declspec(dllexport)
#else
#pragma message("automatic link to MyCudaLib.LIB")
//#pragma comment(lib, "MyCudaLib.lib")
#define DLL3_API __declspec(dllimport)
#endif
int* __stdcall test_array();
#endif //DLL3_H
MyCudaLib.cpp
#include <stdio.h>
#include "MyCudaLib.h"
#include <Windows.h>
#include <stdexcept>
#include <sstream>
using namespace std;
#define DLL3_EXPORTS
BOOL APIENTRY DllMain(HANDLE /*hModule*/,
DWORD ul_reason_for_call,
LPVOID /*lpReserved*/
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
int* __stdcall test_array()
{
int arr[]{ 30,50,60,70 };
return arr;
}
in VB part of the code
Private Declare Function test_array Lib "MyCudaLib.dll" () As Integer()
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Console.WriteLine(test_array(0))
End Sub
is my exporting part of code is wrong? c++ part compiled wtihout error but VB part of the code wont work gives error.
System.Runtime.InteropServices.MarshalDirectiveException: ''return value' cannot arranged.
Note: My point to make a proper working function in c++ is to write a CUDA code to program the GPU. I can write and compile code in CUDA in c++ without problem. But students in my class cannot program in c++ and i can't write more complex code with c++. So, i thought, if i can use the cuda function outside the c++ environment, we all can code it with vb or other languages.
Sure your function compiles fine - it is defined as a function returning a single int and does so as well (return *arr; is equivalent to return arr[0];).
From MarshalDirectiveException
The exception that is thrown by the marshaler when it encounters a MarshalAsAttribute it does not support.
As you did not provide an English error message, I can only guess what's happening now, but there are only few options available:
You have yet another error with your marshaling not visible here.
The function is not recognised due to C++ name mangling (see below).
Incompatibility between int returned in function and expected array is recognised.
The int is interpreted as pointer – but pointer size does not match and the type cannot be marshaled at all.
If you want to return an array, you need to define your function as such:
int* getArray()
// ^
{
static int a[] = {1, 2, 3};
// ^^^^^^ we cannot return an array with local storage duration, so make it
// static, global, or allocate one on heap (new int[]; but assure the
// array to be delete[]d appropriately again to avoid memory leak)
return a; // NOT dereferenced!
}
Be aware that you have C++ name mangling applied. You might possibly prefer a C-kompatible interface:
extern "C" int* getArray();
However, you cannot return C++ data types this way like std::vector – which in most cases even is preferrable, though, as those types usually are incompatible across different implementations (DLL compiled with MSVS, EXE with GCC/MinGW) anyway.
Finally be aware that via a pointer, you lose information about array size! You need to find other means to provide this information to the user of your library.
I am trying to port a 32-bit dll (and application) to 64-bit and I have managed to build it without errors. When trying to load it with my 64-bit application I noticed that the exported function names differ. This is how I export the functions:
#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllexport) long __stdcall Connect(char * name, long size);
#ifdef __cplusplus
}
#endif
In Dependency Walker the exported functions have the following format:
32-bit: _Connect#8
64-bit: Connect
In the application using the dll I explicitly load the dll (LoadLibrary is successful) but GetProcAddress fails for 64-bit because it cannot find a function with the provided name.
In our application I keep the function names as follows:
#define ConnectName "_Connect#8"
...
GetProcAddress(Dll, ConnectName);
So I was wondering if it is possible to export the same function names for both 32-bit and 64-bit dlls or is this a bad idea? Or do I need to do the following in my applications:
#if _WIN64
#define ConnectName "Connect"
#else
#define ConnectName "_Connect#8"
#endif
I appreciate any help.
An option you have to export function names without any decoration (independently from the particular calling convention you used in x86, __stdcall, __cdecl, or other) and with the same undecorated name in both x86 and x64 builds, is to export your DLL functions using DEF files.
E.g. you could add a .DEF file like this to your project:
LIBRARY YOURDLL
EXPORTS
Connect #1
AnotherFunction #2
... etc. ...
Repro Follows
Create an empty solution in Visual Studio (I used VS2013), and inside that create an empty Win32 console project (the test client) and an empty Win32 DLL project (the test DLL).
Add this NativeDll.def .DEF file in the DLL project:
LIBRARY NATIVEDLL
EXPORTS
SayHello #1
Add this NativeDll.cpp C++ source code in the DLL project:
///////////////////////////////////////////////////////////////////////////////
//
// NativeDll.cpp -- DLL Implementation Code
//
///////////////////////////////////////////////////////////////////////////////
#include <Windows.h>
#include <atldef.h>
#include <atlstr.h>
//
// Test function exported from the DLL
//
extern "C" HRESULT WINAPI SayHello(PCWSTR name)
{
//
// Check for null input string pointer
//
if (name == nullptr)
{
return E_POINTER;
}
try
{
//
// Build a greeting message and show it in a message box
//
CString message;
message.Format(L"Hello %s from the native DLL!", name);
MessageBox(nullptr, message, L"Native DLL Test", MB_OK);
// All right
return S_OK;
}
//
// Catch exceptions and convert them to HRESULT codes
//
catch (const CAtlException& ex)
{
return static_cast<HRESULT>(ex);
}
catch (...)
{
return E_FAIL;
}
}
Add this NativeClient.cpp C++ source code in the client test project:
///////////////////////////////////////////////////////////////////////////////
//
// NativeClient.cpp -- EXE Test Client Code
//
///////////////////////////////////////////////////////////////////////////////
#include <Windows.h>
//
// Prototype of the function to be loaded from the DLL
//
typedef HRESULT (WINAPI *SayHelloFuncPtr)(PCWSTR /* name */);
//
// Simple RAII wrapper on LoadLibrary()/FreeLibrary().
//
class ScopedDll
{
public:
//
// Load the DLL
//
ScopedDll(PCWSTR dllFilename) throw()
: m_hDll(LoadLibrary(dllFilename))
{
}
//
// Unload the DLL
//
~ScopedDll() throw()
{
if (m_hDll)
{
FreeLibrary(m_hDll);
}
}
//
// Was the DLL loaded successfully?
//
explicit operator bool() const throw()
{
return (m_hDll != nullptr);
}
//
// Get the DLL handle
//
HINSTANCE Get() const throw()
{
return m_hDll;
}
//
// *** IMPLEMENTATION ***
//
private:
//
// The wrapped raw DLL handle
//
HINSTANCE m_hDll;
//
// Ban copy
//
private:
ScopedDll(const ScopedDll&) = delete;
ScopedDll& operator=(const ScopedDll&) = delete;
};
//
// Display an error message box
//
inline void ErrorMessage(PCWSTR errorMessage) throw()
{
MessageBox(nullptr, errorMessage, L"*** ERROR ***", MB_OK | MB_ICONERROR);
}
//
// Test code calling the DLL function via LoadLibrary()/GetProcAddress()
//
int main()
{
//
// Return codes
//
static const int kExitOk = 0;
static const int kExitError = 1;
//
// Load the DLL with LoadLibrary().
//
// NOTE: FreeLibrary() automatically called thanks to RAII!
//
ScopedDll dll(L"NativeDll.dll");
if (!dll)
{
ErrorMessage(L"Can't load the DLL.");
return kExitError;
}
//
// Use GetProcAddress() to access the DLL test function.
// Note the *undecorated* "SayHello" function name!!
//
SayHelloFuncPtr pSayHello
= reinterpret_cast<SayHelloFuncPtr>(GetProcAddress(dll.Get(),
"SayHello"));
if (pSayHello == nullptr)
{
ErrorMessage(L"GetProcAddress() failed.");
return kExitError;
}
//
// Call the DLL test function
//
HRESULT hr = pSayHello(L"Connie");
if (FAILED(hr))
{
ErrorMessage(L"DLL function call returned failure HRESULT.");
return kExitError;
}
//
// All right
//
return kExitOk;
}
Build the whole solution (both the .EXE and the .DLL) and run the native .EXE client.
This is what I get on my computer:
It works without modifications and with the undecorated function name (just SayHello) on both x86 and x64 builds.
__stdcall is not supported (and is ignored) on x64. Quoting MSDN:
On ARM and x64 processors, __stdcall is accepted and ignored by the compiler; on ARM and x64 architectures, by convention, arguments are passed in registers when possible, and subsequent arguments are passed on the stack.
The calling convention on x64 is pretty much __fastcall.
Since the calling conventions and name decoration rules on x86 and x64 differ, you have to abstract this somehow. So your idea with #if _WIN64 goes in the right direction.
You can examine x86 calling conventions and your needs and perhaps devise a macro which could automate the name selection process.
As you can tell, in 64-bit Windows names are not decorated.
In 32-bit __cdecl and __stdcall symbols, the symbol name is prepended by an underscore. The trailing '#8' in the exported name for the 32-bit version of your example function is the number of bytes in the parameter list. It is there because you specified __stdcall. If you use the __cdecl calling convention (the default for C/C++ code), you won't get that. If you use __cdecl, it makes it much easier to wrap GetProcAddress() with something like:
#if _WIN64
#define DecorateSymbolName(s) s
#else
#define DecorateSymbolName(s) "_" ## s
#endif
then just call with
pfnConnect = GetProcAddress(hDLL, DecorateSymbolName("Connect"));
pfnOtherFunc = GetProcAddress(hDLL, DecorateSymbolName("OtherFunc"));
or something similar (error checking omitted in example).
To do this, remember to declare your exported functions as:
__declspec(dllexport) long __cdecl Connect(char * name, long size);
__declspec(dllexport) long __cdecl OtherFunc(int someValue);
In addition to being easier to maintain, if during development the signature of an exported function changes, you don't have to screw around with your #define wrappers.
Downside: if during development the number of bytes in a given function's parameter list changes, it will not be caught by the application importing the function because the changing the signature will not change the name. Personally, I don't think this is an issue because the 64-bit build would blow up under the same circumstances anyway as the names are not decorated. You just have to make sure your application is using the right version of the DLL.
If the user of the DLL is using C++, you can wrap things in a better way using C++ capabilities (wrap the entire explicitly-loaded library in a wrapper class, e.g.):
class MyDLLWrapper {
public:
MyDLLWrapper(const std::string& moduleName); // load library here
~MyDLLWrapper(); // free library here
FARPROC WINAPI getProcAddress(const std::string& symbolName) const {
return ::GetProcAddress(m_hModule, decorateSymbolName(symbolName));
}
// etc., etc.
private:
HMODULE m_hModule;
// etc.
// ...
};
There's actually a lot more you can do with a wrapper class like this, it's just an example.
On edit: since OP mentioned using PInvoke in the comments - if anyone decides to do this, do not forget to add CallingConvention = CallingConvention.Cdecl in the [DllImport] declaration when using PInvoke. __cdecl might be the default for unmanaged C/C++, but is not the default for managed code.
For Win32 build:
If you use __stdcall, you will get something like this (dumped with dumpbin /exports):
__declspec(dllexport) int __stdcall
->
ordinal hint RVA name
1 0 00001240 _F1#0 = _F1#0
2 1 0000124D _F2#0 = _F2#0
And you have to use GetProcAddress("_F1#0") to locate the function pointer.
If you use __cdecl, you will get something like this:
__declspec(dllexport) int __cdecl
->
ordinal hint RVA name
1 0 00001240 F1 = _F1
2 1 0000124D F2 = _F2
And you can use GetProcAddress("F1") to locate the function pointer.
BTW, if you add a XXX.def file to your Visual Studio project. One more link option will be silently added to your linker command line /DEF:"XXX.def" in the All Options window. And if you change your .def file name later for whatever reason, this link option doesn't change accordingly. You need to manually change the def file name in the project properties window.
I am new to the DLL world. I have been given a Win32 DLL which has a lot of functions. Need to call these DLL functions from C++
I want to call CreateNewScanner which creates a new scanner object and get the results in C++.
Function mentioned in the DLL is:
BOOL CreateNewScanner(NewScanner *newScan);
and NewScanner is a struct, as below,
// Structure NewScanner is defined in "common.h" .
typedef struct{
BYTE host_no; // <- host_no =0
LONG time; // <- command timeout (in seconds)
BYTE status; // -> Host adapter status
HANDLE obj; // -> Object handle for the scanner
}NewScanner;
How will I call this function? Started with C++ and here is what I managed,
#include <iostream>
#include <windows.h>
using namespace std;
int main(){
HINSTANCE hInstance;
if(!(hInstance=LoadLibrary("WinScanner.dll"))){
cout << "could not load library" << endl;
}
/* get pointer to the function in the dll*/
FARPROC handle = GetProcAddress(HMODULE(hInstance), "CreateNewScanner");
if(!handle){
// Handle the error
FreeLibrary(hInstance);
return "-1";
}else{
// Call the function
//How to call here??
}
}
First of all, return "-1" is no good. You are expected to return an integer. So you surely mean return -1.
Now to the question. Instead of declaring the function pointer as FARPROC, it's easier to declare it as a function pointer type.
typedef BOOL (*CreateNewScannerProc)(NewScanner*);
Then call GetProcAddress like this:
HMODULE hlib = LoadLibrary(...);
// LoadLibrary returns HMODULE and not HINSTANCE
// check hlib for NULL
CreateNewScannerProc CreateNewScanner =
(CreateNewScannerProc) GetProcAddress(hlib, "CreateNewScanner");
if (CreateNewScanner == NULL)
// handle error
// now we can call the function
NewScanner newScan;
BOOL retval = CreateNewScanner(&newScan);
Having said all of that, usually a library will come with a header file (yours clearly does so you should include it) and a .lib file for load-time linking. Make sure that you pass the .lib file to your linker and you can simply do this:
#include "NameOfTheHeaderFileGoesHere.h"
....
NewScanner newScan;
BOOL retval = CreateNewScanner(&newScan);
No need to mess around with LoadLibrary, GetProcAddress and so on.
If you want to follow the LoadLibrary/GetProcAddress/FreeLibrary approach, consider the following "code path" (note that if you have the DLL public header file and the corresponding .lib file, just #include the public DLL header, and link with the .lib file, and just use the function whose prototype is defined in the DLL header as you would do with an ordinary C function called from C++ code).
Define a typedef for a pointer to the function exported from the DLL.
Note that the calling convention is specified (usually, Win32 DLLs with pure-C interfaces use __stdcall calling convention):
//
// Prototype of the DLL function, with *calling convention* specified
// (usually it's __stdcall for DLL with pure-C interface).
//
typedef BOOL (__stdcall *CreateNewScannerPtr)(NewScanner *);
Then you try loading the DLL using LoadLibrary:
//
// Try loading the DLL.
//
HMODULE hDll = LoadLibrary(L"WinScanner.dll"); // <--- Note the use of L"..." for Unicode
if (! hDll)
{
.... error
}
Note that the file name of the DLL is a Unicode string (note the L"..." decoration). In general, you should use Unicode in modern C++/Win32 code.
Then you can try getting the function pointer using GetProcAddress:
//
// Try getting the pointer to CreateNewScanner DLL function.
//
auto pCreateNewScanner = reinterpret_cast<CreateNewScannerPtr>
(
GetProcAddress
(
hDll, // DLL handle
"CreateNewScanner" // Function name
)
);
if (! pCreateNewScanner)
{
.... error
// Release the DLL
FreeLibrary(hDll);
// Avoid dangling references
hDll = nullptr;
}
Note that since you are using C++, it's better using C++-style casts (like reinterpret_cast<> in this case), instead of old C-style casts.
Moreover, since the type of the function pointer is specified in reinterpret_cast, it's useless to repeat it at the beginning of the statement, so the new C++11's keyword auto can be used.
You can use the returned function pointer to call the DLL function:
BOOL retCode = pCreateNewScanner( .... );
// Note: some other common prefix used in this case is "pfn"
// as "pointer to function" (e.g. pfnCreateNewScanner).
Once you have finished using the DLL, you can release it, calling FreeLibrary:
//
// Release the DLL
//
FreeLibrary(hDll);
hDll = nullptr;
In addition, note that you can use the C++ RAII pattern, and define a class with a destructor that automatically frees the DLL (this simplifies the code that manages the library loading/releasing parts).
e.g.
class RaiiDll
{
public:
// Load the DLL.
explicit RaiiDll(const std::wstring& filename) // may also provide an overload
// with (const wchar_t*)
{
m_hDll = ::LoadLibrary(filename.c_str());
if (! m_hDll)
{
// Error
throw std::runtime_error("Can't load the DLL - LoadLibrary() failed.");
// .... or use some other exception...
}
}
// Safely and automatically release the DLL.
~RaiiDll()
{
if (m_hDll)
{
::FreeLibrary(m_hDll);
m_hDll = nullptr;
}
}
// Get DLL module handle.
HMODULE Get() const
{
return m_hDll;
}
private:
HMODULE m_hDll; // DLL instance handle
//
// Ban copy (if compiler supports new C++11 =delete, use it)
//
private:
RaiiDll( RaiiDll & );
RaiiDll & operator=( RaiiDll & );
};
Then, in some code block, you can have:
{
// Load the library (throws on error).
RaiiDll scannerDll(L"WinScanner.dll");
// Get DLL function pointer
auto pCreateNewScanner = reinterpret_cast<CreateNewScannerPtr>(
GetProcAddress(scannerDll.Get(), "CreateNewScanner"));
if (! pCreateNewScanner)
{
.... error.
}
.... use the function
} // <--- DLL automatically released thanks to RaiiDll destructor!!!
Note how code is simplified thanks to automatic invocation of RaiiDll destrutor (and so of FreeLibrary), also in the error path case.
I am told to import my writen class in C++ into a dll and then use that dll in a c# application. Following this guide I created the dll, but I can't simply use it in a C# application since there are some issues concerning it:
What should I place for the return type of my factory function?
What is the equivalent of const wchar_t* which is my constructors argument type?
How can I retrieve and use my functions return type which is of type vector< wstring>?
These are the problems that prevent me from using my C++ DLL inside my C# applications. I was told that I need to create a wrapper with C++/CLI and then use that inside my C#. But sadly I have no idea about it, I don't know C++.net.
The only thing that currently seems to be a bit more sensational to me is to make it somehow compatible with C and then create a C DLL and use that in my C# application. I have read that in C, class object pointers are accessible through HANDLEs, so I thought that would be good idea to get things going without a lot of changes.
So the question is how can I use Handles to access my class objects in C and use them? And how can I convert a vector<wstring> to its C counterpart?
If I want to use CLI to create a wrapper (DLL?) for my C++ DLL, to be used in other dotnet apps what should I do?
In order to make a C wrapper for a C++ class to be used in for example a C# application you can do the following.
In Visual Studio choose Win32 Console Application and Enter a name, Then click next and on the next pane choose DLL and click finish. When you are done you are represented with a DLL project including 3 files.
testdll.h
testdll.cpp
dllmain
Delete everything that exists inside your testdll.h and testdll.cpp files and copy the following contents to each respectively. Add these lines to your testdll.h
// Our C wrapper for creating a dll to be used in C# apps
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the TESTDLL_EXPORTS
// symbol defined on the command line. This symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// TESTDLL_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef TESTDLL_EXPORTS
#define TESTDLL_API __declspec(dllexport)
#else
#define TESTDLL_API __declspec(dllimport)
#endif
extern "C"
{
TESTDLL_API int OurTestFunction(int x, int y);
}
It is inside this extern "C" block where you define your interface, functions to access your class member functions.Note the TESTDLL before the function prototype. All of your functions must be proceeded by that.
Add these to your testdll.cpp file:
#include "testdll.h"
#include "ourClass.h"
#define DLL_EXPORT
extern "C"
{
OurClass ourObject;
TESTDLL_API int OurTestFunction(int x, int y)
{
return ourObject.Add(x,y);
}
}
You compile this and get a C based dll which can be used in a C# application.
There are couple of things to notice though, The more important ones are:
You need to understand that the code you use as a proxy- i mean
function definition inside your testdll.h, must only use C
compatible types, it is C after all not C++.
is that you would want to be able to allocate new objects of your
class instead of just using one global object to access all methods.
For this, if you need to pass your class objects between member functions, you need to first convert it to a void* which C can understand and then pass it and use it to access your member functions of whatever.
For example I would have something like this inside my testdll.h in order to make user capable of managing the objects indirectly:
#ifdef TESTDLL_EXPORTS
#define TESTDLL_API __declspec(dllexport)
#else
#define TESTDLL_API __declspec(dllimport)
#endif
extern "C"
{
TESTDLL_API int OurTestFunction(int x, int y);
TESTDLL_API void* CreateHandle();
TESTDLL_API void* GetCurrentHandle();
TESTDLL_API void DisposeCurrentHandle();
TESTDLL_API void SetCurrentHandle(void* handle);
TESTDLL_API void* GetHandle();
TESTDLL_API void DisposeHandle(void*);
TESTDLL_API void DisposeArrayBuffers(void);
}
And inside my testdll.cpp I would define them as :
#include "testdll.h"
#include "ourClass.h"
#define DLL_EXPORT
extern "C"
{
OurClass *ourObject;
TESTDLL_API int OurTestFunction(int x, int y)
{
//return ourObject.Add(x,y); -- not any more !!
ourObject = reinterpret_cast<OurClass *>(GetHandle());
}
//Handle operations
TESTDLL_API void* CreateHandle()
{
if (ourObject == nullptr)
{
ourObject = new OurClass ;
}
else
{
delete ourObject ;
ourObject = new OurClass ;
}
return reinterpret_cast<void*>(ourObject);
}
TESTDLL_API void* GetCurrentHandle()
{
return reinterpret_cast<void*>(ourObject );
}
TESTDLL_API void DisposeCurrentHandle()
{
delete ourObject ;
ourObject = nullptr;
}
TESTDLL_API void SetCurrentHandle(void* handle)
{
if (handle != nullptr)
{
ourObject = reinterpret_cast<OurClass *>(handle);
}
else
{
ourObject = new OurClass ;
}
}
//factory utility function
TESTDLL_API void* GetHandle()
{
void* handle = GetCurrentHandle();
if (handle != nullptr)
{
return handle;
}
else
{
ourObject = new OurClass ;
handle = reinterpret_cast <void*>(ourObject );
}
return handle;
}
CDLL_API void DisposeHandle(void* handle)
{
OurClass * tmp = reinterpret_cast<OurClass *>(handle);
delete tmp;
}
TESTDLL_API void DisposeArrayBuffers(void)
{
ourObject = reinterpret_cast<OurClass *>(GetHandle());
return ourObject ->DisposeBuffers();//This is a member function defined solely for this purpose of being used inside this wrapper to delete any allocated resources by our class object.
}
}
And when we compile this Dll, we can easily work with it inside our C# application. Before being able to use our functions defined in this dll we need to use appropriate [ImportDll()]. So for our TestDll we would write:
[DllImport(#"TestDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int OurTestFunction(int firstNumber,int secondNumber);
And finally use it like:
private void btnReadBigram_Click(object sender, EventArgs e)
{
int x = OurTestFunction(10,50);
MessageBox.Show(x.ToString());
}
This is all I did to make my C++ class member functions accessible inside a C# application without any hassle.
Note:
When compiling your C# application make sure you have chosen the x86 Platform for compiling your project not AnyCpu.You can change your platform through properties.
Note 2:
For knowing how to create a C++/CLI wrapper for your native C++ class read this: C++/CLI wrapper for your native C++ class.
Using a native C++ class directly from C# is technically possible, but it's not trivial, and it's rarely even a good idea. For starters, you have to know the names to use to import from the DLL, which will be the names after C++ name-mangling. You also can't directly access things like vector from C#.
There are basically two good options:
The first is to write a DLL with a C interface that uses only types that can be marshalled into CLR types. You may use pointers along with the IntPtr type, but you can't really dereference those pointers. You can pretty much just store them in your C# code and then pass them back to the native DLL when needed. And you can also use simple struct types as long as you don't need deep copy to work on them. This option involves using P/Invoke.
The second option is to write a mixed-mode C++/CLI assembly that implements all the logic that needs to access your native code. This assembly can directly access classes and data from your C# code and also directly access your native code, although you should be forewarned that there are annoying breaks where you can't mix the two. For example, a ref class in C++/CLI can't have a shared_ptr member. However, it can have a raw C++ pointer as a member. A (mixed-mode) native class can also have access to a CLR handle type and make calls into the C# code through this. This option involves using C++ Interop.
It's worth noting that you could also go the other way with C++ Interop. You could have your C# code access a mixed-mode C++/CLI assembly that provides a .NET interface to some native code. However, you will still have to do some translation in this case so it's not hugely better than the first option.
A full tutorial on C++ Interop would be rather lengthy. I suggest you read up here and do some further investigation of C++ Interop on Google.
C++/CLI introduces managed objects, for which the pointer token * should be replaced with a ^, and a 'new' should be replaced with 'gcnew', you don't need to delete these objects when you're done with them, they'll be garbage collected, [edit] managed classes have a ref keyword in their definition [/edit].
Wrapping the C++ MyClass class in a C++/CLI wrapper class WrapperCLass could look something like this:
#include <stdio.h>
class MyClass
{
public:
void ShowStuff(const wchar_t *a)
{
wprintf(a);
}
};
public ref class WrapperClass
{
MyClass *wrapped;
public:
WrapperClass()
{
wrapped = new MyClass;
}
~WrapperClass()
{
delete wrapped;
}
void ShowStuff(IntPtr string)
{
wrapped->ShowStuff((const wchar_t *)string.ToPointer());
}
};
If you generate a dll with this, you'll be able to use it as a reference in your C# project
and you won't have to use the factory function mechanism.
In C++/CLI are available, so const wchar_t * is as wel.
To convert a System::String to a const wchar_t * you could use something like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Client
{
class Program
{
static void Main(string[] args)
{
WrapperClass w = new WrapperClass();
IntPtr tmp;
w.ShowStuff(tmp = System.Runtime.InteropServices.Marshal.StringToHGlobalUni("Test"));
System.Runtime.InteropServices.Marshal.FreeHGlobal(tmp);
}
}
}
(There could very well be better ways to do this...)
For your return type you'll have to do the conversion in your wrapper class. Make some .net collection, iterate through your vector, convert the wstring to a System::String, and add it to the .net collection, and return that.