C++ DLL - WMI auslesen - Dll in C#



  • Guten morgen,

    ich habe ein Problem.
    Ich habe als Ansatz zum Auslesen der WMI diese Seite genommen:
    http://msdn.microsoft.com/en-us/library/windows/desktop/aa390423(v=vs.85).aspx

    In einer eigenständigen Applikation läuft das soweit auch ganz gut. Nun habe ich aber eine C++ DLL daraus gebaut die dann in C# verwendet werden soll.

    #define _WIN32_DCOM
    #include <string>
    #include <sstream>
    #include <iostream>
    #include <Windows.h>
    #include <comdef.h>
    #include <Wbemidl.h>
    using namespace std;
    
    # pragma comment(lib, "wbemuuid.lib")
    
    extern "C" __declspec(dllexport) char* CreateUID()
    {
    	HRESULT hres;
    
    	#pragma region COM initialisieren
    	//hres = CoInitializeEx(NULL, COINIT_MULTITHREADED); 
    	//if (hres != S_OK)
    	//{
    	//	return "1";
    	//}
    	#pragma endregion
    
    	#pragma region COM Security initialisieren
    	//hres = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
    	//if (hres != S_OK)
    	//{
    	//	CoUninitialize();
    	//	return "2";
    	//}
    	#pragma endregion
    
    	#pragma region COM Instanz initialisieren
    	IWbemLocator *pLoc = NULL;
    	hres = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&pLoc);
    	if (hres != S_OK)
    	{
    		CoUninitialize();
    		return "3";
    	}
    	#pragma endregion
    
    	#pragma region COM Connect Server initialisieren
    	IWbemServices *pSvc = NULL;
    	hres = pLoc->ConnectServer(_bstr_t("ROOT\\CIMV2"), NULL, NULL, NULL, NULL, NULL, NULL, &pSvc);
    	if (hres != WBEM_S_NO_ERROR)
    	{
    		pLoc->Release();     
    		CoUninitialize();
    		return "4";
    	}
    	#pragma endregion
    
    	#pragma region CoSetProxyBlanket
    	hres = CoSetProxyBlanket(pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
    	if (hres != S_OK)
    	{
    		pSvc->Release();
    		pLoc->Release();     
    		CoUninitialize();
    		return "5";
    	}
    	#pragma endregion
    
    	#pragma region ExecQuery
    	IEnumWbemClassObject* pEnumerator = NULL;
    	hres = pSvc->ExecQuery(_bstr_t("WQL"), _bstr_t("SELECT * FROM Win32_OperatingSystem"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
    	if (FAILED(hres))
    	{
    		pSvc->Release();
    		pLoc->Release();
    		CoUninitialize();
    		return "6";
    	}
    	#pragma endregion
    
    	#pragma region Werte lesen
    	IWbemClassObject *pclsObj;
    	ULONG             uReturn = 0;
    	stringstream      ss;
    
    	while (pEnumerator)
    	{
    		hres = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
    		if(uReturn == 0)
    		{
    			break;
    		}
    
    		VARIANT vtProp;
    		CIMTYPE vtType;
    		hres = pclsObj->Get(L"Name", 0, &vtProp, &vtType, NULL);
    
    		std::wstring ws(vtProp.bstrVal, SysStringLen(vtProp.bstrVal));
    		ss << ws.c_str();
    		ss << vtType;
    
    		VariantClear(&vtProp);
    		pclsObj->Release();
    	}
    	#pragma endregion
    
    	#pragma region Aufräumen
    	pSvc->Release();
    	pLoc->Release();
    	pEnumerator->Release();
    	//pclsObj->Release();
    	//CoUninitialize();
    	#pragma endregion
    
    	return (char*)ss.str().c_str();
    }
    

    Das Initialisieren von COM ist natürlich auskommentiert da ich schon im Kontext meiner .NET Anwendung Zugriff darauf habe.

    Nun aber zu meinem Problem:
    Ich kann mich drehen und wenden wie ich will. Ich schaffe es einfach nicht alle Werte in eine Zeichenkette zu pressen und dann zurück zu geben. Ich bekomme nur seltsame Zeichen:

    VARIANT vtProp;
    		CIMTYPE vtType;
    		hres = pclsObj->Get(L"Name", 0, &vtProp, &vtType, NULL);
    
    		std::wstring ws(vtProp.bstrVal, SysStringLen(vtProp.bstrVal));
    		ss << ws.c_str();
    		ss << vtType;
    

    Diese Stelle treibt mich in den Wahnsinn. Ich habe auch mal einen wstringstream genutzt. Ebenso einen stringstream usw.
    Wenn ich jedoch die ursprüngliche Anwendung laufen lasse, dann sieht alles natürlich sauber aus. Ich hab irgendwie das Gefühl, dass das was mit dem Kontext zu tun hat?



  • Warum greifst Du in C# nicht direkt auf WMI zu? Es ist möglich und auch sehr einfach.



  • Weil ich dann mein Problem in ein Forum hätte posten müssen;-)

    Ne im Ernst, ich weiß dass es in .NET möglich ist und mir wäre das auch lieber gewesen eben weil es so einfach dort ist. Wir haben jedoch eine Sammelsurium DLL in die dieser Kram rein soll. Und nicht zuletzt damit wir das nachher obfuscaten können(ja .NET kann das auch, kostet aber ne Menge Kohle).

    Bleiben wir einfach dabei. Das ganze wird in C++ umgesetzt.



  • Stichwort DllImportAttribut. http://msdn.microsoft.com/de-de/library/system.runtime.interopservices.dllimportattribute(v=vs.80).aspx

    Du musst im DllImportAttribut den dll namen angeben und anschließend kanns schon losgehen.
    Deklaration sieht so aus: [zugriff] static extern [Typ] FunktionsName(Parameter...).
    Funktionsname kann auch abweichen, dann muss er aber im DllImportAttribut via EntryPoint gesetzt werden. Die Parameter sind das schwierigste. Je nach Parameter musst du schauen wie du sie marshalen musst. Für Standartdinge gibt es jedoch schon genug Marshaler und das solltest ihr hinbekommen. Falls es wirklich komische eigene Datentypen sind müsst ihr halt einen CustomMarshaler verwenden das habe ich jedoch erst einmal gebraucht.


Anmelden zum Antworten