Com ISequentialStream的RemoteRead和RemoteWrite成员是什么?

Com ISequentialStream的RemoteRead和RemoteWrite成员是什么?,com,com-interop,atl,midl,Com,Com Interop,Atl,Midl,我正在开发一个COM库,它使用该接口读取和写入数据。我的MIDL代码如下所示: 接口IParser:IUnknown { HRESULT加载([in]IStream*流,[out,retval]IParsable**pVal); }; 由于IStream及其基本接口ISequentialStream未在类型库中定义,因此它们在我的中定义。到现在为止,一直都还不错。但是,当我使用OLEView查看我的类型库时,ISequentialStream仅定义成员RemoteRead和RemoteWrit

我正在开发一个COM库,它使用该接口读取和写入数据。我的MIDL代码如下所示:

接口IParser:IUnknown
{
HRESULT加载([in]IStream*流,[out,retval]IParsable**pVal);
};
由于
IStream
及其基本接口
ISequentialStream
未在类型库中定义,因此它们在我的中定义。到现在为止,一直都还不错。但是,当我使用OLEView查看我的类型库时,
ISequentialStream
仅定义成员
RemoteRead
RemoteWrite
,而我预期的是
Read
Write
,因为它们是我实际调用的。更奇怪的是,列表中列出了这两个成员(除原始成员外),但表示不支持这两个成员

问题

那么,这些成员是什么?我如何从客户端使用它们(例如,托管应用程序为
IStream
创建托管
包装器)

长话短说

我想在客户端实现一个包装器,它将
IStream
调用转发到.NET流,比如
System.IO.FileStream
。此包装器可以继承自
IStream
,如下所示:

公共类流:Lib.IStream
{
public System.IO.Stream BaseStream{get;private set;}
公共流(System.IO.Stream)
{
this.BaseStream=流;
}
//这里的所有IStream成员。。。
公共无效读取(字节[]缓冲区,int bufferSize,IntPtr bytesReadPtr)
{
//进一步实施。。。
this.BaseStream.Read();
}
}
然后,我想用这个包装器调用我的服务器:

var包装器=新流(baseStream);
var parsable=parser.Load(包装器);

问题是,在前面的示例中,
Lib.Stream
只提供了
RemoteRead
RemoteWrite
,因此服务器对
Stream->Read()
的调用将以无人区结束。据我所知,托管COM服务器有
System.Runtime.InteropServices.ComTypes.IStream
,但在我的示例中,我有一个非托管COM服务器和一个托管客户端,应该提供
IStream
实例。

实际上,
ISequentialStream
v表布局中没有
RemoteRead
RemoteWrite
。它们仅存在于
ObjIdl.Idl
中,作为RPC代理/存根代码生成器的辅助工具。查看SDK中的
ObjIdl.h

MIDL_INTERFACE("0c733a30-2a1c-11ce-ade5-00aa0044773d")
ISequentialStream : public IUnknown
{
public:
    virtual /* [local] */ HRESULT STDMETHODCALLTYPE Read( 
        /* [annotation] */ 
        __out_bcount_part(cb, *pcbRead)  void *pv,
        /* [in] */ ULONG cb,
        /* [annotation] */ 
        __out_opt  ULONG *pcbRead) = 0;

    virtual /* [local] */ HRESULT STDMETHODCALLTYPE Write( 
        /* [annotation] */ 
        __in_bcount(cb)  const void *pv,
        /* [in] */ ULONG cb,
        /* [annotation] */ 
        __out_opt  ULONG *pcbWritten) = 0;

};
很难猜测为什么您的类型库最终会有
RemoteRead
/
RemoteWrite
名称,而不是
Read
/
Write
。如果需要帮助,您可能希望将IDL上传到某个地方并发布一个链接

但是,只要您的typelib中的v-table布局、方法签名和接口GUID与
ISequentialStream
IStream
中的
ObjIdl.h
匹配,方法名称就无关紧要。

无论如何,我会按照伊戈尔在评论中的建议去做。在类型库中根本不要暴露
IStream
。在IDL中使用
IUnknown
,并在C#client方法实现中将其强制转换为
System.Runtime.InteropServices.ComTypes.IStream
,实际执行读/写操作时,即:

IDL:

C#:

[UPDATE]我想我看到了方法名称的变化。你的情况就是这样的:


再一次,我建议不要拖到类型库中,我并不是唯一一个提出这个建议的人。实际上,您会将更多不需要的内容拖到typlib中,而typlib也会投影到C#端。坚持使用
IUnknown
并使您的类型库整洁。或者,最后,从头开始定义自己的二进制/GUID兼容版本。

说来话长。Read()仅针对非封送调用进行了优化,RemoteRead()是远程调用的后备方法。这是代理的实现细节,客户端代码仅使用Read()。究竟出了什么问题?
IStream
与自动化不兼容;试图在类型库中定义它是不明智的。如果需要
IParser
实现自动化兼容,请将
IUnknown*
作为第一个参数,并在实现中查询它以查找
IStream
。或者,从
IParser
中删除
Load
方法,让对象实现
IPersistStreamInit
(及其
Load
方法),并添加一个返回
IParsable
@igortandenik的属性:除了设计原因之外,在这里,我不能使用
IPersistStreamInit
,它还使用
IStream
作为参数,这会导致与上述相同的结果(
IStream
被添加到我的类型库中)。据我所知,这是MIDL的默认行为,不是吗@HansPassant:我想在客户端实现一个包装器(将服务器的
读取
/
写入
调用转发到
System.IO.FileStream
),但我没有
读取
/
写入
。我的类型库中的
IStream
接口(代理,你是说?!)只定义了
RemoteRead
RemoteWrite
。我更新了这个问题,对我试图实现的目标做了更多解释。好吧,这听起来是朝着正确方向迈出的一步。然而,我希望在接口定义中使用
IStream
能够让我感到舒适,因为这样更便于客户机开发,使事情变得正确。但从我目前所读到的来看,我认为我最终会成为最好的“拳击”选手。谢谢!:)顺便说一句:接口的Guid等于预期的Guid,但我不知道方法签名是否正确(根据我的记忆;无法检查atm)。@Aschratt,它是g
interface IParser : IUnknown
{
    HRESULT Load([in] IUnknown* stream, [out, retval] IParsable** pVal);
};
IParsable Load(object stream)
{
    // ...
    var comStream = (System.Runtime.InteropServices.ComTypes.IStream)stream;
    comStream.Read(...);
    // ...
}