C++ 非托管 程序调用托管程序

This is a sample native console application which will query the registry to verify if a specific version of the .NET Framework is installed. It will then use the CorBindToRuntimeEx API to load a specific version of the Common Language Runtime (CLR). Finally, it uses the Interfaces and methods exposed in mscorlib.tlb to load an assembly and type and execute methods.

Create a new C++ Console application named CheckCLR and replace the code in CheckCLR.cpp with the following code:

/*
    CheckCLR.cpp - A Native Code CLR Host Sample

    CheckCLR is a native console application which queries the registry to
    determine if a specific version of the .NET runtime is installed on the
    machine. It then loads the specific CLR required.

    It will then load a managed console app and execute the Main method.
    It then loads a managed assembly and executes a method.
*/
#include "stdafx.h"
#include <windows.h>
#include <mscoree.h>
#include <assert.h>
#include <stdio.h>
#include <tchar.h>

// Import mscorlib typelib. Using 1.0 for maximum backwards compatibility
#import "C:\windows\Microsoft.NET\Framework\v1.0.3705\mscorlib.tlb" auto_rename
// Link with mscoree.dll import lib.
#pragma comment(lib,"mscoree.lib")

using namespace mscorlib;

int _tmain(int argc, _TCHAR* argv[])
{
    //
    // Query 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5\Install' DWORD value
    // See http://support.microsoft.com/kb/318785/ (http://support.microsoft.com/kb/318785/) for more information on .NET runtime versioning information
    //
    HKEY key = NULL;
    DWORD lastError = 0;
    lastError = RegOpenKeyEx(HKEY_LOCAL_MACHINE,TEXT("SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v3.5"),0,KEY_QUERY_VALUE,&key);
    if(lastError!=ERROR_SUCCESS) {
        _putts(TEXT("Error opening HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v3.5"));
        return 1;
    }

    DWORD type;
    BYTE data[4];
    DWORD len = sizeof(data);
    lastError = RegQueryValueEx(key,TEXT("Install"),NULL,&type,data,&len);
 
    if(lastError!=ERROR_SUCCESS) {
        RegCloseKey(key);
        _putts(TEXT("Error querying HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v3.5\\Install"));
        return 2;
    }

    RegCloseKey(key);

    // Was Install DWORD key value == 1 ??
    if(data[0]==1)
        _putts(TEXT(".NET Framework 3.5 is installed"));
    else {
        _putts(TEXT(".NET Framework 3.5 is NOT installed"));
        return 3;
    }

    // 
    // Load the runtime the 3.5 Runtime (CLR version 2.0)
    //
    LPWSTR pszVer = L"v2.0.50727";  // .NET Fx 3.5 needs CLR 2.0
    LPWSTR pszFlavor = L"wks";
    ICorRuntimeHost *pHost = NULL;

    HRESULT hr = CorBindToRuntimeEx( pszVer,       
                                                       pszFlavor,    
                                                       STARTUP_LOADER_OPTIMIZATION_SINGLE_DOMAIN | STARTUP_CONCURRENT_GC, 
                                                       CLSID_CorRuntimeHost, 
                                                       IID_ICorRuntimeHost,
                                                       (void **)&pHost);

    if (!SUCCEEDED(hr)) {
        _tprintf(TEXT("CorBindToRuntimeEx failed 0x%x\n"),hr);
        return 1;
    }
 
    _putts(TEXT("Loaded version 2.0.50727 of the CLR\n"));
 
    pHost->Start(); // Start the CLR

    //
    // Get a pointer to the default domain in the CLR
    //
    _AppDomainPtr pDefaultDomain = NULL;
    IUnknownPtr   pAppDomainPunk = NULL;

    hr = pHost->GetDefaultDomain(&pAppDomainPunk);
    assert(pAppDomainPunk); 
 
    hr = pAppDomainPunk->QueryInterface(__uuidof(_AppDomain),(void**) &pDefaultDomain);
    assert(pDefaultDomain);

    //
    // Load an Exe Assembly and call Main()
    //
    _bstr_t bstrExeName = L"ConsoleApplication1.exe";
    try {
        hr = pDefaultDomain->ExecuteAssembly_2(bstrExeName);
    }
    catch(_com_error& error) {
        _tprintf(TEXT("ERROR: %s\n"),(_TCHAR*)error.Description());
        goto exit;
    }

    /*
        Load a type from a DLL Assembly and call it

        Doing the same thing from native code as this C# code:

            System.Runtime.Remoting.ObjectHandle objptr;
            objptr = AppDomain.CurrentDomain.CreateInstanceFrom("ClassLibrary1.dll",
                                                                                           "ClassLibrary1.Class1");
            object obj = objptr.Unwrap();
            Type t = obj.GetType();
            t.InvokeMember("Test",
                                   BindingFlags.InvokeMethod,
                                   null,
                                   obj,
                                   new object[0]);
    */
    try {
        _ObjectHandlePtr pObjectHandle; 
        _ObjectPtr pObject; 
        _TypePtr pType;
        SAFEARRAY* psa;

        // Create an instance of a type from an assembly
        pObjectHandle = pDefaultDomain->CreateInstanceFrom(L"ClassLibrary1.dll",     // no path -- local directory
                                                                                      L"ClassLibrary1.Class1");
  
        variant_t vtobj = pObjectHandle->Unwrap();                                     // Get an _Object (as variant) from the _ObjectHandle
        vtobj.pdispVal->QueryInterface(__uuidof(_Object),(void**)&pObject);  // QI the variant for the Object iface
        pType = pObject->GetType();                                                         // Get the _Type iface
        psa = SafeArrayCreateVector(VT_VARIANT,0,0);                                // Create a safearray (0 length)
        pType->InvokeMember_3("Test",                                                     // Invoke "Test" method on pType
                                            BindingFlags_InvokeMethod,
                                            NULL,
                                            vtobj,
                                            psa );
        SafeArrayDestroy(psa);                                                                   // Destroy safearray
    }
    catch(_com_error& error) {
        _tprintf(TEXT("ERROR: %s\n"),(_TCHAR*)error.Description());
        goto exit;
    }

exit:
    pHost->Stop();
    pHost->Release();

    return 0;
}

/*** End of file CheckCLR.cpp ***/

Create a C# Console Application named ConsoleApplication1. Add a Console.WriteLine call in the Main method and output a simple string message. Build ConsoleApplication1. Copy the ConsoleApplication1.exe build target to the ouput directory where CheckCLR.exe is built. Alternatively, you can change the code above to have the full path name to where ConsoleApplication1.exe is built.

Create a C# Class Library named ClassLibrary1. In the Class1 class, add a public method named Test. In Test, add a Console.WriteLine call and output a simple string message. Build ClassLibrary1.dll. Copy the ClassLibrary1.dll build target to the outut directory where CheckCLR.exe is built. Alternatively, you can change the code above to have the full path name to where ClassLibrary1.dll is built.

After building CheckCLR, you should should be able to run CheckCLR.exe from a command prompt and see the output of the Console.WriteLine calls:

    .NET Framework 3.5 is installed
    Loaded version 2.0.50727 of the CLR


    Hello World from ConsoleApplication1.Main
    Hello World from ClassLibrary1.Class1


If running CheckCLR.exe under the debugger from your Visual C++ project, you may get could not load file or assembly error messages. In that case, copy ConsoleApplication1.exe and ClassLibrary1.dll to the folder containing the CheckCLR.sln solution file. The debugger uses that folder as the application default directory.

posted on 2010-01-26 13:43  酸辣大白菜  阅读(663)  评论(0编辑  收藏  举报

导航