C++ плагин для Unity "EntryPointNotFoundExeption"
Мне нужна серьезная помощь здесь... Я пытаюсь либо экспортировать свои функции-члены, чтобы я мог вызывать их в C#
WMIWrapper.h
#ifndef _WMIWRAPPER_H_
#define _WMIWRAPPER_H_
#include <Windows.h>
#include <sstream>
#include <iostream>
#include <WbemCli.h>
using std::endl;
using std::wstring;
using std::wstringstream;
#pragma comment(lib, "wbemuuid.lib")
static class WMIWrapper
{
public:
__declspec(dllexport) WMIWrapper();
__declspec(dllexport) ~WMIWrapper();
__declspec(dllexport) wstring CreateCOM();
__declspec(dllexport) wstring CreateService();
__declspec(dllexport) wstring GetMonitors();
private:
IWbemLocator* _locator;
IWbemServices* _service;
IEnumWbemClassObject* _monitors;
};
#endif
WMIWrapper.cpp
#include "WMIWrapper.h"
extern "C" {
WMIWrapper::WMIWrapper()
{
_locator = NULL;
_service = NULL;
}
WMIWrapper::~WMIWrapper()
{
if(_service != NULL)
_service->Release();
if(_locator != NULL)
_locator->Release();
}
wstring WMIWrapper::CreateCOM()
{
wstringstream ERRStream (wstringstream::in | wstringstream::out);
HRESULT hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if(FAILED(hRes))
{
ERRStream << "Unable to launch COM: 0x" << std::hex << hRes << endl;
return L"";
}
hRes = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, 0);
if(FAILED(hRes))
{
ERRStream << "Unable to set security level for COM: " << std::hex << hRes << endl;
return L"";
}
if(FAILED(hRes = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_ALL, IID_PPV_ARGS(&_locator))))
{
ERRStream << "Unable to create a WbemLocator: " << std::hex << hRes << endl;
return L"";
}
const std::wstring& myWString = ERRStream.str();
const LPCWSTR p = myWString.c_str();
return p;
}
wstring WMIWrapper::CreateService()
{
wstringstream ERRStream (wstringstream::in | wstringstream::out);
HRESULT hRes;
if(_locator == NULL || FAILED(hRes = _locator->ConnectServer(L"root\\CIMV2", NULL, NULL, NULL, WBEM_FLAG_CONNECT_USE_MAX_WAIT, NULL, NULL, &_service)))
{
ERRStream << "Unable to connect to \"CIMV2\": " << std::hex << hRes << endl;
return L"";
}
const std::wstring& myWString = ERRStream.str();
const LPCWSTR p = myWString.c_str();
return p;
}
wstring WMIWrapper::GetMonitors()
{
HRESULT hRes;
wstringstream ssMonitorDescription;
if(_locator == NULL
|| _service == NULL
|| FAILED(hRes = _service->ExecQuery(L"WQL", L"SELECT * FROM Win32_DesktopMonitor", WBEM_FLAG_FORWARD_ONLY, NULL, &_monitors)))
{
//ERRStream << "Unable to retrieve desktop monitors: " << std::hex << hRes << endl;
return L"";
}
IWbemClassObject* clsObj = NULL;
int numElems;
while((hRes = _monitors->Next(WBEM_INFINITE, 1, &clsObj, (ULONG*)&numElems)) != WBEM_S_FALSE)
{
if(FAILED(hRes))
break;
VARIANT vRet;
VariantInit(&vRet);
if(SUCCEEDED(clsObj->Get(L"Description", 0, &vRet, NULL, NULL)) && vRet.vt == VT_BSTR)
{
//std::wcout << L"Description: " << vRet.bstrVal << endl;
ssMonitorDescription << "Description: " << vRet.bstrVal << endl;
VariantClear(&vRet);
}
}
clsObj->Release();
return ssMonitorDescription.str();
}
}
Interface.cpp
#include "WMIWrapper.h"
extern "C"
{
__declspec( dllexport ) wstring GetMonitor()
{
WMIWrapper* wmiWrapper = new WMIWrapper();
wmiWrapper->CreateCOM();
wmiWrapper->CreateServiceW();
return wmiWrapper->GetMonitors();
}
}
Unity Script
using UnityEngine;
using System.Runtime.InteropServices;
using System;
public class HardwareDiagnostics : MonoBehaviour {
//[DllImport("WMIWrapper", EntryPoint="CreateCOM", CharSet = CharSet.Unicode)]
//static extern String CreateCOM();
//
//[DllImport("WMIWrapper", EntryPoint="CreateService", CharSet = CharSet.Unicode)]
//static extern String CreateService();
//
//[DllImport("WMIWrapper", EntryPoint="GetMonitors", CharSet = CharSet.Unicode)]
//static extern String GetMonitors();
[DllImport("WMIWrapper", EntryPoint = "GetMonitor", CharSet = CharSet.Unicode)]
static extern string GetMonitor();
// Use this for initialization
void Start () {
Debug.Log(GetMonitor());
Debug.Log ("Cock");
}
// Update is called once per frame
void Update () {
}
}
Поэтому я пытаюсь вызвать эти функции-члены из сценария Unity и получаю ошибку EntryPointNotFoundExeption. Я подумал, может быть, это потому, что вы не можете экспортировать функции-члены, поэтому я попытался написать этот "Interface.cpp" для выполнения этих функций и возврата результата, но он возвращает ту же ошибку.
ОБНОВИТЬ
По предложению я изменил свои функции C++ на этот формат
void WMIWrapper::CreateCOM(wchar_t* err, int errLength)
{
.../Determine wstringstream ERRStream
wcscpy_s(err, errLength, ERRStream.str().c_str());
}
А мой C# вроде так:
public class HardwareDiagnostics : MonoBehaviour {
[DllImport( "WMIWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
private static extern void CreateCOM(StringBuilder str, int length);
[DllImport( "WMIWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
private static extern void CreateService(StringBuilder str, int length);
[DllImport( "WMIWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
private static extern void GetMonitors(StringBuilder str, int length);
// Use this for initialization
void Start () {
StringBuilder buffer = new StringBuilder(255);
CreateCOM(buffer, buffer.Capacity);
Debug.Log(buffer.ToString());
CreateService(buffer, buffer.Capacity);
Debug.Log(buffer.ToString());
GetMonitors(buffer, buffer.Capacity);
Debug.Log(buffer.ToString());
}
// Update is called once per frame
void Update () {
}
}
ОДНАКО, я все еще получаю "EntryPointNotFoundExeption" при вызове первой функции, CreateCOM();
3 ответа
Это окна? Потому что ты скучаешь по
Bool WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID);
определение, если это окна.
См. Главу 21 "Программирование Windows: пятое издание" Чарльза Петцольда.
Если у вас его нет. Возьми. Все программисты Windows должны прочитать это.
Функция DllMain вызывается, когда библиотека сначала начинается и когда она заканчивается. Первый параметр DllMain - это дескриптор экземпляра библиотеки. Если ваша библиотека использует ресурсы, для которых требуется дескриптор экземпляра (например, DialogBox), вы должны сохранить hInstance в качестве глобальной переменной. Последний параметр для DllMain зарезервирован системой...
Значение fdwReason DLL_PROCESS_ATTACH указывает, что библиотека динамической компоновки была сопоставлена с адресным пространством процесса. Это сигнал для библиотеки, чтобы он выполнял любые задачи инициализации, необходимые для обслуживания последующих запросов от процесса....
Если инициализация прошла успешно, DllMain должен вернуть ненулевое значение. Возвращение 0 приведет к тому, что Windows не запустит программу.
Когда fdwReason имеет значение DLL_PROCESS_DETACH, это означает, что DLL больше не нужен процессу.. очистить...
Более поздние версии Visual Studio могут сделать это для вас - я не уверен насчет этой части.
Кроме того, вы получите исключение EntryPointNotFound, если имена ваших функций искажены. Причина, по которой имена ваших функций искажаются даже при объявлении extern "C", заключается в том, что вы поместили extern "C" вокруг методов класса. Для того, чтобы это работало без искаженных имен, вы должны сделать объявления функций в стиле C.
т.е.
#ifdef _cplusplus
extern "C" {
#endif
__declspec(dllexport) wstring CreateCOM();
...
вне контекста класса. Если они будут объявлены как члены класса, имена все равно будут искажены, даже с объявлением extern "C".
Ошибка произошла из-за того, что имя функции искажалось компилятором C++. Я думал, что завершение объявлений функций в.cpp с помощью extern "C" {} решило эту проблему, но я думаю, что нет.
[DllImport( "WMIWrapper", EntryPoint = "?CreateCOM@WMIWrapper@1@SAXPA_WH@Z", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
private static extern void CreateCOM(StringBuilder str, int length);
[DllImport( "WMIWrapper", EntryPoint = "?CreateServiceW@WMIWrapper@1@SAXPA_WH@Z", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
private static extern void CreateService(StringBuilder str, int length);
[DllImport( "WMIWrapper", EntryPoint = "?GetMonitors@WMIWrapper@1@SAXPA_WH@Z", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
private static extern void GetMonitors(StringBuilder str, int length);
Если кто-нибудь знает, как правильно использовать extern "C" в этом контексте, это было бы очень полезно.