Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/284.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 通过IPC向跨进程的COM对象传递引用?_C#_Com_Ipc - Fatal编程技术网

C# 通过IPC向跨进程的COM对象传递引用?

C# 通过IPC向跨进程的COM对象传递引用?,c#,com,ipc,C#,Com,Ipc,我有一个对COM对象的引用,希望将该引用传递给另一个进程。 因此,我需要某种方法来序列化有关此引用的信息,以便在另一个过程中再次恢复它 对于任意类型的COM对象,有没有办法做到这一点 我对COM不太了解;据我所知,某些类型的对象可能有名字对象(例如,Excel.Workbook等COM引用可能通过其.FullName属性还原,该属性似乎用作名字对象),但到目前为止,我还没有发现任何类型的COM对象是否可能有类似的情况 在服务器进程中,使用CoMarshalInterface封送 流的接口。将写入

我有一个对COM对象的引用,希望将该引用传递给另一个进程。 因此,我需要某种方法来序列化有关此引用的信息,以便在另一个过程中再次恢复它

对于任意类型的COM对象,有没有办法做到这一点

我对COM不太了解;据我所知,某些类型的对象可能有名字对象(例如,Excel.Workbook等COM引用可能通过其.FullName属性还原,该属性似乎用作名字对象),但到目前为止,我还没有发现任何类型的COM对象是否可能有类似的情况

  • 在服务器进程中,使用
    CoMarshalInterface
    封送 流的接口。将写入流的字节转换为base-64 字符串(或任何其他编码)。将编码的字符串传递给 客户
  • 在客户端进程中,从服务器接收字符串。解码 将字符串转换为字节。将这些字节包装到流中。拆封 小溪
  • 服务器端:

    #include <windows.h>
    #include <comdef.h>
    #include <shlwapi.h>
    #include <vector>
    // link: crypt32.lib (for CryptBinaryToStringW)
    // link: shlwapi.lib (for SHCreateMemStream)
    
    /// <summary>
    /// Gets a token that can be used to unmarshal an interface in another process.
    /// </summary>
    HRESULT GetInterfaceToken(LPUNKNOWN pUnk, REFIID riid, LPBSTR pbstrOut)
    {
        // validate output parameters
        if (pbstrOut == nullptr)
            return E_POINTER;
    
        // set default values for output parameters
        *pbstrOut = nullptr;
    
        // validate input parameters
        if (pUnk == nullptr)
            return E_INVALIDARG;
    
        // create a stream
        IStreamPtr stream;
        stream.Attach(SHCreateMemStream(nullptr, 0));
        if (!stream)
            return E_FAIL;
    
        // marshal interface into stream
        auto hr = CoMarshalInterface(stream, riid, pUnk, MSHCTX_LOCAL, nullptr, MSHLFLAGS_NORMAL);
        if (FAILED(hr))
            return hr;
    
        // get stream length
        ULONG stream_length;
        {
            STATSTG stat;
            hr = stream->Stat(&stat, STATFLAG_NONAME);
            if (FAILED(hr))
                return hr;
            stream_length = static_cast<ULONG>(stat.cbSize.QuadPart);
        }
    
        // read data from stream
        std::vector<BYTE> raw_data;
        {
            hr = stream->Seek({ 0 }, STREAM_SEEK_SET, nullptr);
            if (FAILED(hr))
                return hr;
            raw_data.resize(stream_length);
            ULONG bytes_read;
            hr = stream->Read(&raw_data.front(), stream_length, &bytes_read);
            if (FAILED(hr))
                return hr;
            if (bytes_read != stream_length)
                return E_FAIL;
        }
    
        // encode bytes as base-64 string
        std::vector<WCHAR> encoded_bytes;
        {
            DWORD encoded_length_with_null = 0;
            if (!CryptBinaryToStringW(&raw_data.front(), stream_length, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, nullptr, &encoded_length_with_null))
                return E_FAIL;
            encoded_bytes.resize(encoded_length_with_null);
            auto encoded_length = encoded_length_with_null;
            if (!CryptBinaryToStringW(&raw_data.front(), stream_length, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, &encoded_bytes.front(), &encoded_length))
                return E_FAIL;
            if (encoded_length != encoded_length_with_null - 1)
                return E_FAIL;
        }
    
        // create result
        const auto result = SysAllocStringLen(&encoded_bytes.front(), encoded_bytes.size() - 1);
        if (result == nullptr)
            return E_OUTOFMEMORY;
    
        // set output parameters
        *pbstrOut = result;
    
        // success
        return S_OK;
    }
    
    #包括
    #包括
    #包括
    #包括
    //链接:crypt32.lib(用于CryptBinaryToString)
    //链接:shlwapi.lib(用于SHCreateMemStream)
    /// 
    ///获取可用于在另一个进程中解组接口的令牌。
    /// 
    HRESULT GetInterfaceToken(LPUNKNOWN朋克、REFIID riid、LPBSTR pbstrOut)
    {
    //验证输出参数
    如果(pbstrOut==nullptr)
    返回E_指针;
    //设置输出参数的默认值
    *pbstrOut=空PTR;
    //验证输入参数
    如果(朋克==nullptr)
    返回E_INVALIDARG;
    //创建流
    IStreamPtr流;
    Attach(SHCreateMemStream(nullptr,0));
    如果(!流)
    返回E_失败;
    //将接口封送到流中
    auto hr=CoMarshalInterface(流、riid、朋克、MSHCTX_LOCAL、nullptr、MSHLFLAGS_NORMAL);
    如果(失败(小时))
    返回人力资源;
    //获取流长度
    乌龙溪长度;
    {
    STATSTG stat;
    hr=流->统计(&Stat,STATFLAG\u NONAME);
    如果(失败(小时))
    返回人力资源;
    流长度=静态浇铸(stat.cbSize.QuadPart);
    }
    //从流中读取数据
    std::矢量原始数据;
    {
    hr=流->搜索({0},流搜索集,空ptr);
    如果(失败(小时))
    返回人力资源;
    原始数据。调整大小(流长度);
    ULONG字节\ u读取;
    hr=流->读取(&raw\u data.front(),流长度,&bytes\u读取);
    如果(失败(小时))
    返回人力资源;
    if(字节数\u读取!=流长度)
    返回E_失败;
    }
    //将字节编码为base-64字符串
    std::矢量编码的字节;
    {
    DWORD编码的_长度_,_null=0;
    if(!CryptBinaryToStringW(&raw_data.front(),stream_length,CRYPT_STRING_BASE64,CRYPT_STRING_NOCRLF,nullptr,&encoded_length_with_null))
    返回E_失败;
    编码的字节。调整大小(编码的长度为空);
    自动编码的长度=编码的长度为空;
    if(!CryptBinaryToStringW(&raw_data.front(),stream_length,CRYPT_STRING_BASE64,CRYPT_STRING_NOCRLF,&encoded_bytes.front(),&encoded_length))
    返回E_失败;
    if(encoded_length!=带_null的编码_length_-1)
    返回E_失败;
    }
    //创造结果
    const auto result=SysAllocStringLen(&encoded_bytes.front(),encoded_bytes.size()-1);
    如果(结果==nullptr)
    返回E_OUTOFMEMORY;
    //设置输出参数
    *pbstrOut=结果;
    //成功
    返回S_OK;
    }
    
    客户端:

    #include <windows.h>
    #include <comdef.h>
    #include <shlwapi.h>
    #include <vector>
    // link: crypt32.lib (for CryptStringToBinaryW)
    // link: shlwapi.lib (for SHCreateMemStream)
    
    /// <summary>
    /// Unmarshals an interface from a token.
    /// </summary>
    HRESULT UnmarshalInterfaceFromToken(BSTR token, REFIID riid, LPVOID* ppv)
    {
        // validate output parameters
        if (ppv == nullptr)
            return E_POINTER;
    
        // set default values for output parameters
        *ppv = nullptr;
    
        // validate input parameters
        if (token == nullptr)
            return E_INVALIDARG;
    
        // decode base-64 string as bytes
        std::vector<BYTE> decoded_bytes;
        {
            DWORD decoded_length = 0;
            if (!CryptStringToBinaryW(token, 0, CRYPT_STRING_BASE64, nullptr, &decoded_length, nullptr, nullptr))
                return E_FAIL;
            decoded_bytes.resize(decoded_length);
            if (!CryptStringToBinaryW(token, 0, CRYPT_STRING_BASE64, &decoded_bytes.front(), &decoded_length, nullptr, nullptr))
                return E_FAIL;
            if (decoded_length != decoded_bytes.size())
                return E_FAIL;
        }
    
        // wrap the bytes in an IStream
        IStreamPtr stream;
        stream.Attach(SHCreateMemStream(&decoded_bytes.front(), decoded_bytes.size()));
        if (!stream)
            return E_FAIL;
    
        // unmarshal interface from stream
        return CoUnmarshalInterface(stream, riid, ppv);
    }
    
    #包括
    #包括
    #包括
    #包括
    //链接:crypt32.lib(用于CryptStringToBinaryW)
    //链接:shlwapi.lib(用于SHCreateMemStream)
    /// 
    ///从令牌解组接口。
    /// 
    HRESULT UnmarshalInterfaceFromToken(BSTR令牌、REFIID riid、LPVOID*ppv)
    {
    //验证输出参数
    如果(ppv==nullptr)
    返回E_指针;
    //设置输出参数的默认值
    *ppv=nullptr;
    //验证输入参数
    if(令牌==nullptr)
    返回E_INVALIDARG;
    //将base-64字符串解码为字节
    std::矢量解码的字节;
    {
    DWORD解码_长度=0;
    if(!CryptStringToBinaryW(令牌,0,CRYPT_STRING_BASE64,nullptr,&decoded_length,nullptr,nullptr))
    返回E_失败;
    解码字节。调整大小(解码字节长度);
    if(!CryptStringToBinaryW(令牌,0,CRYPT_STRING_BASE64,&decoded_bytes.front(),&decoded_length,nullptr,nullptr))
    返回E_失败;
    if(解码的\u长度!=解码的\u字节.size())
    返回E_失败;
    }
    //将字节包装到IStream中
    IStreamPtr流;
    附加(SHCreateMemStream(&decoded_bytes.front(),decoded_bytes.size());
    如果(!流)
    返回E_失败;
    //从流中解组接口
    返回接口(流、riid、ppv);
    }
    
    名字对象类似于URL,只要代码理解其含义,您就可以在其中传递任何内容。否则,传递引用通常会很复杂,特别是如果您是COM新手,请检查以下内容:谢谢!CoMarshalInterface正是我所希望的,在我的案例中实现了这一点,并且似乎工作得很好!