Using VS2013, I created a Visual C++ CLR class library, made no changes to project settings. Targeted Framework = .NET 4.5.2.
Referenced System.Windows.Forms and added string to stdafx.h.
ClassLibrary1.h:
#pragma once
#if defined DO_EXPORT
#define DECLDIR __declspec(dllexport)
#else
#define DECLDIR __declspec(dllimport)
#endif
using namespace System;
extern "C"
{
DECLDIR void Foo();
DECLDIR void Foo2a();
DECLDIR void Foo2b(std::string s);
}
ClassLibary1.cpp:
#define DO_EXPORT
#include "stdafx.h"
#include "ClassLibrary1.h"
using namespace System::Windows::Forms;
void FooImp()
{
}
void FooImp2(std::string s)
{
}
extern "C"
{
void Foo()
{
::FooImp();
}
void Foo2a()
{
MessageBox::Show("Entered Foo2a");
::FooImp2("");
MessageBox::Show("Exited Foo2a");
}
void Foo2b(std::string s)
{
MessageBox::Show("Entered Foo2b");
::FooImp2(s);
MessageBox::Show("Exited Foo2b");
}
}
The above code works fine when built into a VS2013 C++ Win32 console app (with string and windows.h added to stdafx.h, and no changes to project settings):
typedef void(*VoidFuncVoid)(void);
typedef void(*VoidFuncStr)(std::string);
int _tmain(int argc, _TCHAR* argv[])
{
VoidFuncVoid _Foo;
VoidFuncVoid _Foo2a;
VoidFuncStr _Foo2b;
HINSTANCE hInstLibrary1 = LoadLibrary(_T("ClassLibrary1.dll"));
if (hInstLibrary1)
{
_Foo = reinterpret_cast<VoidFuncVoid>(GetProcAddress(hInstLibrary1, "Foo"));
_Foo();
_Foo2a = reinterpret_cast<VoidFuncVoid>(GetProcAddress(hInstLibrary1, "Foo2a"));
_Foo2a();
_Foo2b = reinterpret_cast<VoidFuncStr>(GetProcAddress(hInstLibrary1, "Foo2b"));
_Foo2b("");
FreeLibrary(hInstLibrary1);
}
}
All Foo calls work great and I get the four message prompts.
But when the same code is built into a VS2008 C++ Win32 console app (with string and windows.h added to stdafx.h, and no changes to project settings), the app crashes in between the two Foo2b message prompts, reporting:
Unhandled exception at 0x0f5433be in ConsoleApp1.exe: 0xC0000005: Access violation reading location 0x002d1000.
What did I miss? What is wrong with the ::FooImp2(s); statement?
To use a library built in Visual Studio that has exported C++ functions with standard library parameters or classes that have standard library members, you essentially must use the same version of Visual Studio for the client. This is because each new version of Visual Studio makes changes to the standard library (and thus the client's idea of what a std::string
or std::vector
is different from what was compiled into the library).
If you need to have the client and library built with different versions of Visual Studio, the only safe way to do this would be to expose the code you need with a strict C interface (const char *
instead of std::string
, int ar[], int arCount
instead of std::vector<int>
).