0

ここで深刻な助けが必要です...メンバー関数をエクスポートして、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スクリプト

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 () {

    }


}

ただし、最初の関数CreateCOM()を呼び出すと、まだ「EntryPointNotFoundExeption」が表示されます。

4

3 に答える 3

2

これは窓ですか?あなたがあなたを逃しているので

Bool WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID);

Windowsの場合の定義。

Charles Petzoldによる「ProgrammingWindows:FifthEdition」の第21章を参照してください。

あなたがそれを持っていない場合。それを得る。すべてのWindowsプログラマーはそれを読む必要があります。

DllMain関数は、ライブラリが最初に開始したときと終了したときに呼び出されます。DllMainの最初のパラメーターは、ライブラリのインスタンスハンドルです。ライブラリでインスタンスハンドルを必要とするリソース(DialogBoxなど)を使用する場合は、hInstanceをグローバル変数として保存する必要があります。DllMainの最後のパラメータは、システムによって予約されています...

DLL_PROCESS_ATTACHのfdwReason値は、ダイナミックリンクライブラリがプロセスのアドレス空間にマップされていることを示します。これは、ライブラリがプロセスからの後続の要求を処理するために必要な初期化タスクを実行するための手がかりです。

初期化が成功した場合、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"宣言があっても、名前は引き続きマングルされます。

于 2012-07-24T14:29:13.193 に答える
-1

エラーは、関数名が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"を適切に使用する方法を誰かが知っているなら、それは非常に役に立ちます。

于 2012-07-24T18:14:07.380 に答える