zoukankan      html  css  js  c++  java
  • CLR寄宿——C++调用C# dll

    在看到CLR寄宿的内容的时候,研究了一下非托管C++启用CLR的过程。在MSDN sample gallary中看到了一个很好的例子。直接把代码贴到下面(略作了一些修改)。生怕以后找不到了。另外,从C++传送到C#方法的参数只试验过int, double, wchar_t*(字符串)。其他的没有做过实验。


    C++代码 

    //
    //   FUNCTION: RuntimeHostV4Demo1(PCWSTR, PCWSTR)
    //
    //   Invoking way: RuntimeHostV4Demo1(L"v4.0.30319", L"CSNET2ClassLibrary", L"CSNET2ClassLibrary.CSSimpleObject");
    //
    //   PURPOSE: The function demonstrates using .NET Framework 4.0 Hosting 
    //   Interfaces to host a .NET runtime, and use the ICorRuntimeHost interface
    //   that was provided in .NET v1.x to load a .NET assembly and invoke its 
    //   type. 
    //   
    //   If the .NET runtime specified by the pszVersion parameter cannot be 
    //   loaded into the current process, the function prints ".NET runtime <the 
    //   runtime version> cannot be loaded", and return.
    //   
    //   If the .NET runtime is successfully loaded, the function loads the 
    //   assembly identified by the pszAssemblyName parameter. Next, the function 
    //   instantiates the class (pszClassName) in the assembly, calls its 
    //   ToString() member method, and print the result. Last, the demo invokes 
    //   the public static function 'int GetStringLength(string str)' of the class 
    //   and print the result too.
    //
    //   PARAMETERS:
    //   * pszVersion - The desired DOTNETFX version, in the format “vX.X.XXXXX”. 
    //     The parameter must not be NULL. It’s important to note that this 
    //     parameter should match exactly the directory names for each version of
    //     the framework, under C:\Windows\Microsoft.NET\Framework[64]. The 
    //     current possible values are "v1.0.3705", "v1.1.4322", "v2.0.50727" and 
    //     "v4.0.30319". Also, note that the “v” prefix is mandatory.
    //   * pszAssemblyName - The display name of the assembly to be loaded, such 
    //     as "CSClassLibrary". The ".DLL" file extension is not appended.
    //   * pszClassName - The name of the Type that defines the method to invoke.
    //
    //   RETURN VALUE: HRESULT of the demo.
    //
    HRESULT RuntimeHostV4Demo1(PCWSTR pszVersion, PCWSTR pszAssemblyName, 
        PCWSTR pszClassName)
    {
        HRESULT hr;

        ICLRMetaHost *pMetaHost = NULL;
        ICLRRuntimeInfo *pRuntimeInfo = NULL;

        // ICorRuntimeHost and ICLRRuntimeHost are the two CLR hosting interfaces
        
    // supported by CLR 4.0. Here we demo the ICorRuntimeHost interface that 
        
    // was provided in .NET v1.x, and is compatible with all .NET Frameworks. 
        ICorRuntimeHost *pCorRuntimeHost = NULL;

        IUnknownPtr spAppDomainThunk = NULL;
        _AppDomainPtr spDefaultAppDomain = NULL;

        // The .NET assembly to load.
        bstr_t bstrAssemblyName(pszAssemblyName);
        _AssemblyPtr spAssembly = NULL;

        // The .NET class to instantiate.
        bstr_t bstrClassName(pszClassName);
        _TypePtr spType = NULL;
        variant_t vtObject;
        variant_t vtEmpty;

        // The static method in the .NET class to invoke.
        bstr_t bstrStaticMethodName(L"GetStringLength");
        SAFEARRAY *psaStaticMethodArgs = NULL;
        variant_t vtStringArg1(L"HelloWorld");
        variant_t vtStringArg2(18);
        variant_t vtStringArg3(123.321);
        variant_t vtLengthRet;

        // The instance method in the .NET class to invoke.
        bstr_t bstrMethodName(L"ToString");
        SAFEARRAY *psaMethodArgs = NULL;
        variant_t vtStringRet;

        // 
        
    // Load and start the .NET runtime.
        
    // 

        wprintf(L"Load and start the .NET runtime %s \n", pszVersion);

        hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost));
        if (FAILED(hr))
        {
            wprintf(L"CLRCreateInstance failed w/hr 0x%08lx\n", hr);
            goto Cleanup;
        }

        // Get the ICLRRuntimeInfo corresponding to a particular CLR version. It 
        
    // supersedes CorBindToRuntimeEx with STARTUP_LOADER_SAFEMODE.
        hr = pMetaHost->GetRuntime(pszVersion, IID_PPV_ARGS(&pRuntimeInfo));
        if (FAILED(hr))
        {
            wprintf(L"ICLRMetaHost::GetRuntime failed w/hr 0x%08lx\n", hr);
            goto Cleanup;
        }

        // Check if the specified runtime can be loaded into the process. This 
        
    // method will take into account other runtimes that may already be 
        
    // loaded into the process and set pbLoadable to TRUE if this runtime can 
        
    // be loaded in an in-process side-by-side fashion. 
        BOOL fLoadable;
        hr = pRuntimeInfo->IsLoadable(&fLoadable);
        if (FAILED(hr))
        {
            wprintf(L"ICLRRuntimeInfo::IsLoadable failed w/hr 0x%08lx\n", hr);
            goto Cleanup;
        }

        if (!fLoadable)
        {
            wprintf(L".NET runtime %s cannot be loaded\n", pszVersion);
            goto Cleanup;
        }

        // Load the CLR into the current process and return a runtime interface 
        
    // pointer. ICorRuntimeHost and ICLRRuntimeHost are the two CLR hosting  
        
    // interfaces supported by CLR 4.0. Here we demo the ICorRuntimeHost 
        
    // interface that was provided in .NET v1.x, and is compatible with all 
        
    // .NET Frameworks. 
        hr = pRuntimeInfo->GetInterface(CLSID_CorRuntimeHost, 
            IID_PPV_ARGS(&pCorRuntimeHost));
        if (FAILED(hr))
        {
            wprintf(L"ICLRRuntimeInfo::GetInterface failed w/hr 0x%08lx\n", hr);
            goto Cleanup;
        }

        // Start the CLR.
        hr = pCorRuntimeHost->Start();
        if (FAILED(hr))
        {
            wprintf(L"CLR failed to start w/hr 0x%08lx\n", hr);
            goto Cleanup;
        }

        // 
        
    // Load the NET assembly. Call the static method GetStringLength of the 
        
    // class CSSimpleObject. Instantiate the class CSSimpleObject and call 
        
    // its instance method ToString.
        
    // 

        
    // The following C++ code does the same thing as this C# code:
        
    // 
        
    //   Assembly assembly = AppDomain.CurrentDomain.Load(pszAssemblyName);
        
    //   object length = type.InvokeMember("GetStringLength", 
        
    //       BindingFlags.InvokeMethod | BindingFlags.Static | 
        
    //       BindingFlags.Public, null, null, new object[] { "HelloWorld", 18, 123.321 });
        
    //   object obj = assembly.CreateInstance("CSClassLibrary.CSSimpleObject");
        
    //   object str = type.InvokeMember("ToString", 
        
    //       BindingFlags.InvokeMethod | BindingFlags.Instance | 
        
    //       BindingFlags.Public, null, obj, new object[] { });

        
    // Get a pointer to the default AppDomain in the CLR.
        hr = pCorRuntimeHost->GetDefaultDomain(&spAppDomainThunk);
        if (FAILED(hr))
        {
            wprintf(L"ICorRuntimeHost::GetDefaultDomain failed w/hr 0x%08lx\n", hr);
            goto Cleanup;
        }

        hr = spAppDomainThunk->QueryInterface(IID_PPV_ARGS(&spDefaultAppDomain));
        if (FAILED(hr))
        {
            wprintf(L"Failed to get default AppDomain w/hr 0x%08lx\n", hr);
            goto Cleanup;
        }

        // Load the .NET assembly.
        wprintf(L"Load the assembly %s\n", pszAssemblyName);
        hr = spDefaultAppDomain->Load_2(bstrAssemblyName, &spAssembly);
        if (FAILED(hr))
        {
            wprintf(L"Failed to load the assembly w/hr 0x%08lx\n", hr);
            goto Cleanup;
        }

        // Get the Type of CSSimpleObject.
        hr = spAssembly->GetType_2(bstrClassName, &spType);
        if (FAILED(hr))
        {
            wprintf(L"Failed to get the Type interface w/hr 0x%08lx\n", hr);
            goto Cleanup;
        }

        // Call the static method of the class: 
        
    //   public static int GetStringLength(string str);

        
    // Create a safe array to contain the arguments of the method. The safe 
        
    // array must be created with vt = VT_VARIANT because .NET reflection 
        
    // expects an array of Object - VT_VARIANT. There is only one argument, 
        
    // so cElements = 1.
        psaStaticMethodArgs = SafeArrayCreateVector(VT_VARIANT, 03);
        LONG index = 0;
        hr = SafeArrayPutElement(psaStaticMethodArgs, &index, &vtStringArg1);
        index = 1;
        hr = SafeArrayPutElement(psaStaticMethodArgs, &index, &vtStringArg2);
        index = 2;
        hr = SafeArrayPutElement(psaStaticMethodArgs, &index, &vtStringArg3);
        if (FAILED(hr))
        {
            wprintf(L"SafeArrayPutElement failed w/hr 0x%08lx\n", hr);
            goto Cleanup;
        }

        // Invoke the "GetStringLength" method from the Type interface.
        hr = spType->InvokeMember_3(bstrStaticMethodName, static_cast<BindingFlags>(
            BindingFlags_InvokeMethod | BindingFlags_Static | BindingFlags_Public), 
            NULL, vtEmpty, psaStaticMethodArgs, &vtLengthRet);
        if (FAILED(hr))
        {
            wprintf(L"Failed to invoke GetStringLength w/hr 0x%08lx\n", hr);
            goto Cleanup;
        }

        // Print the call result of the static method.
        wprintf(L"Call %s.%s(\"%s\") => %d\n"
            static_cast<PCWSTR>(bstrClassName), 
            static_cast<PCWSTR>(bstrStaticMethodName), 
            static_cast<PCWSTR>(vtStringArg1.bstrVal), 
            vtLengthRet.lVal);

        // Instantiate the class.
        hr = spAssembly->CreateInstance(bstrClassName, &vtObject);
        if (FAILED(hr))
        {
            wprintf(L"Assembly::CreateInstance failed w/hr 0x%08lx\n", hr);
            goto Cleanup;
        }

        // Call the instance method of the class.
        
    //   public string ToString();

        
    // Create a safe array to contain the arguments of the method.
        psaMethodArgs = SafeArrayCreateVector(VT_VARIANT, 00);

        // Invoke the "ToString" method from the Type interface.
        hr = spType->InvokeMember_3(bstrMethodName, static_cast<BindingFlags>(
            BindingFlags_InvokeMethod | BindingFlags_Instance | BindingFlags_Public),
            NULL, vtObject, psaMethodArgs, &vtStringRet);
        if (FAILED(hr))
        {
            wprintf(L"Failed to invoke ToString w/hr 0x%08lx\n", hr);
            goto Cleanup;
        }

        // Print the call result of the method.
        wprintf(L"Call %s.%s() => %s\n"
            static_cast<PCWSTR>(bstrClassName), 
            static_cast<PCWSTR>(bstrMethodName), 
            static_cast<PCWSTR>(vtStringRet.bstrVal));

    Cleanup:

        if (pMetaHost)
        {
            pMetaHost->Release();
            pMetaHost = NULL;
        }
        if (pRuntimeInfo)
        {
            pRuntimeInfo->Release();
            pRuntimeInfo = NULL;
        }
        if (pCorRuntimeHost)
        {
            // Please note that after a call to Stop, the CLR cannot be 
            
    // reinitialized into the same process. This step is usually not 
            
    // necessary. You can leave the .NET runtime loaded in your process.
            
    //wprintf(L"Stop the .NET runtime\n");
            
    //pCorRuntimeHost->Stop();

            pCorRuntimeHost->Release();
            pCorRuntimeHost = NULL;
        }

        if (psaStaticMethodArgs)
        {
            SafeArrayDestroy(psaStaticMethodArgs);
            psaStaticMethodArgs = NULL;
        }
        if (psaMethodArgs)
        {
            SafeArrayDestroy(psaMethodArgs);
            psaMethodArgs = NULL;
        }

        return hr; }

    C#代码 

    namespace CSNET2ClassLibrary
    {
        public class CSSimpleObject
        {
            /// <summary>
            
    /// Constructor
            
    /// </summary>
            public CSSimpleObject()
            {
            }

            private float fField = 0F;

            /// <summary>
            
    /// This is a public Property. It allows you to get and set the value 
            
    /// of a float field.
            
    /// </summary>
            public float FloatProperty
            {
                get { return fField; }
                set
                {
                    // Fire the event FloatPropertyChanging
                    bool cancel = false;
                    if (FloatPropertyChanging != null)
                    {
                        FloatPropertyChanging(value, out cancel);
                    }

                    // If the change is not canceled, make the change.
                    if (!cancel)
                    {
                        fField = value;
                    }
                }
            }

            /// <summary>
            
    /// Returns a String that represents the current Object. Here, we 
            
    /// return the string form of the float field fField.
            
    /// </summary>
            
    /// <returns>the string form of the float field fField.</returns>
            public override string ToString()
            {
                return this.fField.ToString("F2");
            }

            /// <summary>
            
    /// This is a public static method. It returns the number of 
            
    /// characters in a string.
            
    /// </summary>
            
    /// <param name="str">a string</param>
            
    /// <returns>the number of characters in the string</returns>
            public static int GetStringLength(string str, string length)
            {
                return (str.Length + Int32.Parse(length));
            }

            public static int GetStringLength(string str, int length, double somevalue)
            {
                Console.WriteLine(str + " " + length.ToString() + " " + somevalue.ToString() );
                return (str.Length + length + (int)somevalue);
            }

            /// <summary>
            
    /// This is an event. The event is fired when the float property is 
            
    /// set.
            
    /// </summary>
            public event PropertyChangingEventHandler FloatPropertyChanging;
        }


        /// <summary>
        
    /// Property value changing event handler
        
    /// </summary>
        
    /// <param name="NewValue">the new value of the property</param>
        
    /// <param name="Cancel">
        
    /// Output whether the change should be cancelled or not.
        
    /// </param>
        public delegate void PropertyChangingEventHandler(object NewValue, out bool Cancel); }


  • 相关阅读:
    zookeeper 分布式锁
    mysql linux 安装
    分布式配置中心Apollo
    分布式任务调度平台xxl-job
    Java并发编程笔记之ThreadLocalRandom源码分析
    Java并发编程笔记之ThreadLocal源码分析
    SpringCloud实战10-Sleuth
    SpringCloud实战9-Stream消息驱动
    SpringCloud实战8-Bus消息总线
    SpringCloud实战7-Config分布式配置管理
  • 原文地址:https://www.cnblogs.com/aicro/p/2555249.html
Copyright © 2011-2022 走看看