zoukankan      html  css  js  c++  java
  • COM技术内幕第十章笔记EXE中的服务器

    “不同EXE中的组件和客户将在不同的进程中运行,这是因为每一个EXE都有其自己的进程空间。这样一来,客户和组件之间的交互就会跨越进程边界了。”

    每个EXE都有自己的不同进程,DLL将被映射到链接它们的EXE文件的进程空间中。
    因此DLL被称作进程中服务器,EXE则被称作进程外服务器。
    某些情况下,EXE也被称作是本地服务器以同另一种进程外服务器“远程服务器”相区别。
    远程服务器也就是运行在另外一台机器上的进程外服务器。

    组件调用,其实是将接口指针返回给客户,如果客户和组件位于不同的进程、使用的不是同一地址空间,那么接口指针(地址空间内的逻辑地址)的物理地址将是不同的。这样一来组件调用即成空谈。

    SO,解决进程间的通信是多么重要啊!

    本地过程调用LPC

    进程间通信有几种方法:动态数据交换(DDE)命名管道以及共享内存等。COM所用的方法则为本地过程调用(LPC),它是基于远程过程调用RPC的用于单机上的进程通信的专利技术。RPC是在分布式计算环境(DCE)RPC规范中定义的,使得不同机器上的进程可以使用各种网络传输技术进程通信。

    LPC实际上是由操作系统实现的。操作系统当然知道每个进程的逻辑地址空间和对应的物理地址空间,他当然可以调用任何想调用的东东。(操作系统为什么是男的?)(笔者你忘记了吗,这是你自己写的嘛)

    得到了EXE中的函数也就是某个地址以后,第二步就是要在不同进程间传递数据,将函数调用的参数传入。俺们使用一种被称为“调整”的方法。如果倆进程在同一单机上,淡然只需要将参数复制到另一进程的地址空间就OK了;如果倆进程在不同的机器上,就要考虑到二者在数据表示方面的不同,例如字节顺序啊之类的,必须要将参数转换成标准的格式。(虾米标准?谁定的标准?不是类似W3C的标准吧?啊)

    为对组件进行调整,可以实现一个IMarshal的接口。在COM创建组件的过程中,它将查询组件IMarshal接口,然后调用IMarshal的成员函数,以在客户调用函数的前后调整或反调整有关参数。COM库中实现了一个可以供大多数接口使用的IMarshal的标准版本。(又是一个标准)
    关于IMarshal的问题,Krarig。。。所著《Inside OLE》有详细讨论

    代理/残根DLL

    一直都在说的一件事是通过一个IUnknown或其他什么接口就可以调用组件,但到底怎么做的也不知道,就知道是通过LPC做的。LPC,当然,实际上是操作系统在做。因此,此时得知几乎所有Win32函数都会用到LPC也就不奇怪了。调用Win32函数,也就是操作系统调用一个DLL中的函数,也就是会通过LPC调用Windows中的实际代码。

    COM使用的结构与此类似(嗷~什么?类似?难道前面说的不就是COM所使用的结构吗?细细回味ing),客户将同一个模仿组件的DLL进行通信,这个DLL可以为客户完成参数的调整和LPC调用,在COM中,这个DLL,当然这个DLL也是一个组件,这个DLL这个组件被称作是一个代理

    以COM的专业说法,一个代理就是同另外一个组件行为相同的组件。代理必须是DLL的!(为什么捏?)自然是因为代理就是要完成参数的调整,如果不是DLL不能正确获取地址空间内的数据,那就是白搭。通过代理DLL,组件能对输出的参数进行调整,对客户返回的数据调整是由另一个被称作残根的DLL来做的。

    IDL/MIDL简介

    不要被代理和残根吓到,借助一种名为IDL(接口定义语言),我们只需要描述一个接口,然后MIDL编译器就会自己生成代理和残根。当然,如果感兴趣、愿意和有能力去做,你也可自己去写这个代理和残根。(真想知道残根一词的英文原词是虾米

    IDL语言,同UUID设计和RPC规范一样,都是从开放软件基金会(OSF)的分布式计算机环境(DCE)借用来的,“语法同C和C++是一样的”(那还何必叫劳什子IDL呢?),可以细致地描述接口和组件所共享的接口和数据。COM只用到了IDL的一个子集,Microsoft为了更好的支持COM对它做了一些扩展。

    MIDL,微软的IDL编译器。

    一个idl例子:

    import "unknown.idl"
    // Interface IX
    [
           object,
           uuid(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx),
           helpstring("IX Interface"),
           pointer _default(unique)
    ]
    interface IX:IUnknown
    {
           HRESULT FxStringIn([in,string] wchar _t *szIn);
           HRESULT FxStringOut([out,string] wchar _t ** szOut);
    };

    在C++中相应的函数应是:

    virtual HRESULT __stdcall FxStringIn(wchar _t * szIn);
    virtual HRESULT __stdcall FxStringOut(wchar _t ** szOut);

    IDL用方括号[]来作为信息分隔符,在每个接口定义前,都有一个属性列表或称接口头
    object表示定义的接口为一个COM接口,关键字object即是Microsft对IDL的扩展之一。
    uuid,就是接口IID了。
    helpstring,将一个帮助字符串放到类型库中。类型库的事情,咱下回再说
    pointer _default,此处的重点。

    pointer _default

    用来告诉MIDL编译器在没有为指针指定其他属性时,如何处理该指针。

    ref               将指针当成引用。此时表示指针总是指向一个合法地址,并可被反引用??
                       这种指针不能为空。在调用前后它们指向同一内存地址。
                       在函数内部,不能为它们指定别名。
    unique         此类指针可以为空,并且函数内部可以修改它们的值,但不能为之指定别名。
    ptr                此指针就是一个个C指针。可以有一个别名(强调一个?)可以NULL,值可被修改。

    in、out和string

    MIDL会根据in和out属性对代理及残根代码进行优化。in,表示残根DLL不需返回值,out表示代理DLL不需调整值,不需将值传送给组件。

    string告诉MIDL该参数是一个字符串(末尾以一空字符结束)。COM中对字符串的标准约定是Unicode字符即wchar _t。

    HRESULT

    MIDL要求,用object修饰的接口必须返回HRESULT值。因为object修饰的接口是COM接口么,COM接口都是返回HRESULT?断然不是。“因为任何函数调用都会由于网络传输问题失败,因此应该有一种让所有函数都只是网络错误的方法,也就是让所有函数都返回HRESULT。”由此,COM接口都是返回HRESULT——这是果,而非因。

    import

    用于将其他idl文件中的定义包含到当前文件。类似……你知道的。但又和……你知道的……有所不同,import可以任意多次,不会引起重复定义问题。所有COM及OLE现在叫ActiveX的标准接口都定义在相应的IDL文件中,这些文件位于C++编译器的\include中。闲得疼时可浏览之研究之以图level up。

    size _is

    先看一个在客户和组件之间船体数组的接口的IDL描述。

    // Interface IY
    [
             object,
              uuid(XXXXXXXX-xxxx-xxxx-xxxx-xxxxxxxxxxxx),
             helpstring("IY Interface"),
             pointer _default(unique)
    ]
    interface IY:IUnknown
    {
             HRESULT FyCount( [out] long * sizeArray);
             HRESULT FyArrayIn( [In] long sizeIn,
                                               [in, size _is(sizeIn)] long arrayIn[] );
             HRESULT FyArrayOut( [Out, in ] long* psizeInOut,
                                                   [out, size _is(* psizeInOut)] long arrayOut[] );
    };

    size _is 就是用来告诉MIDL,数组中的元素的个数。可以大胆的预料到,只是out参数,是不会用size_is修饰的。嗯。太傻了。

    IDL的结构体

    IDL说,struct可以有!于是IDL中struct就有了。

    作者不愧是做OpenGL的,我刚想到可以在IDL定义Point、Vector啥的,就看到

    // Structure for interface IZ
    typedef struct
    {
            double x;
            double y;
            double z;
    } Point3d;

    具体的实现。。。。。。略!-__-b

  • 相关阅读:
    DataTable四个方法
    c++面向对象编程必备“良方”(转)
    函数调用约定
    AFX_IDW_PANE_FIRST(转)
    CString.Format的详细用法(转)
    ID的分配 (转)
    CString用法整理(转载)
    jquery之效果
    JS 水仙数
    CSS 文本换行
  • 原文地址:https://www.cnblogs.com/mumuliang/p/1873480.html
Copyright © 2011-2022 走看看