Пока Lain побеждает меня писать пример, я все равно выложу его на всякий случай ...
Процесс написания оболочки для доступа к вашей собственной библиотеке аналогичен обращению к одной из стандартных библиотек .Net.
Пример кода класса C # в проекте с именем CsharpProject:
using System;
namespace CsharpProject {
public class CsharpClass {
public string Name { get; set; }
public int Value { get; set; }
public string GetDisplayString() {
return string.Format("{0}: {1}", this.Name, this.Value);
}
}
}
Вы должны создать управляемый проект библиотеки классов C ++ (например, CsharpWrapper) и добавить свой проект C # в качестве ссылки на него. Чтобы использовать один и тот же заголовочный файл для внутреннего использования и в ссылочном проекте, вам нужен способ использовать правильный declspec. Это может быть сделано путем определения директивы препроцессора (в данном случае CSHARPWRAPPER_EXPORTS
) и использования #ifdef
для установки макроса экспорта в вашем интерфейсе C / C ++ в заголовочном файле. Заголовочный файл неуправляемого интерфейса должен содержать неуправляемый материал (или должен быть отфильтрован препроцессором).
Файл заголовка неуправляемого интерфейса C ++ (CppInterface.h):
#pragma once
#include <string>
// Sets the interface function's decoration as export or import
#ifdef CSHARPWRAPPER_EXPORTS
#define EXPORT_SPEC __declspec( dllexport )
#else
#define EXPORT_SPEC __declspec( dllimport )
#endif
// Unmanaged interface functions must use all unmanaged types
EXPORT_SPEC std::string GetDisplayString(const char * pName, int iValue);
Затем вы можете создать файл внутреннего заголовка, чтобы иметь возможность включать его в файлы управляемой библиотеки. Это добавит операторы using namespace
и может включать необходимые вспомогательные функции.
Файл заголовка управляемого C ++ интерфейса (CsharpInterface.h):
#pragma once
#include <string>
// .Net System Namespaces
using namespace System;
using namespace System::Runtime::InteropServices;
// C# Projects
using namespace CsharpProject;
//////////////////////////////////////////////////
// String Conversion Functions
inline
String ^ ToManagedString(const char * pString) {
return Marshal::PtrToStringAnsi(IntPtr((char *) pString));
}
inline
const std::string ToStdString(String ^ strString) {
IntPtr ptrString = IntPtr::Zero;
std::string strStdString;
try {
ptrString = Marshal::StringToHGlobalAnsi(strString);
strStdString = (char *) ptrString.ToPointer();
}
finally {
if (ptrString != IntPtr::Zero) {
Marshal::FreeHGlobal(ptrString);
}
}
return strStdString;
}
Затем вы просто пишете код интерфейса, который выполняет перенос.
Исходный файл управляемого интерфейса C ++ (CppInterface.cpp):
#include "CppInterface.h"
#include "CsharpInterface.h"
std::string GetDisplayString(const char * pName, int iValue) {
CsharpClass ^ oCsharpObject = gcnew CsharpClass();
oCsharpObject->Name = ToManagedString(pName);
oCsharpObject->Value = iValue;
return ToStdString(oCsharpObject->GetDisplayString());
}
Затем просто включите неуправляемый заголовок в неуправляемый проект, скажите компоновщику использовать сгенерированный файл .lib при компоновке и убедитесь, что библиотеки .Net и оболочки находятся в той же папке, что и ваше неуправляемое приложение.
#include <stdlib.h>
// Include the wrapper header
#include "CppInterface.h"
void main() {
// Call the unmanaged wrapper function
std::string strDisplayString = GetDisplayString("Test", 123);
// Do something with it
printf("%s\n", strDisplayString.c_str());
}