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