• 属性化ATL,DCOM,SIM,IID


    //==============================================================================
    要不要从IUnknown接口派生?
    1 是否要使用GetService,是则要从IUnkown接口派生, 否则往下看:
    2 是否为回调,不是回调就不用从IUnkown接口派生,是回调往下看:
    3 回调是采用继承方式还是采用复合形式:
    继承方式: 不用从IUnkown接口派生(不过这里一般会发生多继承)
    复合方式: 为了编码方便,灵活(使用ComSink),最好从IUnkown接口派生。也可以不从IUnown派生,
             不过麻烦,基本上需要做一个comsink<为模板类>类似的具体类来,只不过不处理IUnkown部分

    要不要token:
    token是用于区别输入的,如果输入的参数已经可以区别自已,就不用token了
    //==============================================================================
    SIM工程注意事项(如果不Embeded IDL文件并且不注册则不用处理这些注意事项)
    1, Embeded IDL设置项:工程/属性/链接/Embeded IDL下面的ingore embeded idl(/ignoreidl)
    2, 注册dll设置项: 工程/属性/链接/Genneral 下面的Register Output
    3, SIM是属性化ATL工程(dll),从 c/c++ / preprocessor中可以看出来:     

    WIN32;_WINDOWS;_DEBUG;_USRDLL;_ATL_ATTRIBUTES
    4, 如果要跨套间使用SimDll里提供的接口,则必须嵌入idl并注册dll;否则可不用。
    5, SIM工程并没有默认添加rgs资源("REGISTRY"),会导致注册失败,需手工添加.
    6, 如果注册失败,可用exeScope.exe查看资源,其中的REGISTRY、TYPELIB资源是否存在以及格式是否正确,用Dependes.exe工具查看DllMain、DllRegisterServer等函数是否正常导出。
    7,如果发现SimDll没有导出DllRegisterServer等函数,不要去添加.Def文件导出,在适当文件里包含下列文件即可,然后[module(dll)]属性会自动生成这些函数并导出现:
    #include <atlbase.h>
    #include <atlcom.h>
    #include <atlwin.h>
    #include <atltypes.h>
    #include <atlctl.h>
    #include <atlhost.h>
    8, 导出[export]属性用于enum要特别注册,导出后,enum外面的namespace将会失去作用,因为任何属性生成的都是纯C代码,而C语言中没有namespace,这样会很容易产生名字冲突情况。
    9, 导出的接口中,不要使用bool类型,因为导出后生成的是纯C代码,没有bool类型,应该用BOOL类型代替。
    10,对于Exe的DCOM工程,Exe工程Build后并不会自动注册,也不要自动Build PS工程并注册,所以一定要手工做这两注册,否则调试时会白费工夫:
    一、***.exe /RegServer
    二、Build ***ps project, 再regsvr32 ***ps.dll (在正常的工程,即非SIM工程,这一步会自动进行,参见2)

    注1:对于一般的DCOM,好像主工程和ps工程注册其一就能正常工作,待再确定?
    注2:对于同一进程内不同套间传递COM接口,可用使用CoMarshalInterfaceInStream以及

    CoGetInterfaceAndReleaseStream,但是不知这两个API背后是否有使用proxy stub.
    注3:对于不同进程(跨进程了就一定会跨套间),只能依赖DCOM机制利用***ps.dll及注册来来传递(列集,散集)接口,此时如果在DCOM服务端QueryInterface则意味着**ps.dll里没有这个接口。另外清寒要注册参数的in/out属性。如果是从IDispatch派生的接口,则相应的方法都要正确实现。
    注4,对于不跨套间情况,和纯C++接口比较类似,这种情况下没有用到的接口函数都可以不“假实现”,因为实际上不会调用或者不依赖方法调用的结果,只要随便实现以通过编译即可。

    //==============================================================================

     属性化接口属性:

    o,udp(object,uuid,dual,pointer_default(ref,unique,ptr)).  

    在实现接口的时间,如果参数中有用到其它接口,需要看到对应接口的全部实现,这点好像很不方便,在非属性化时,可以在idl文件中用import 避免.

     属性化类属性: 

    ct,udp(coclass, threading(apartment,free,both,neutal);  uuid, default, progid(vi_progid, version))  

    ref,unique,ptr:

    顶层指针默认是ref, 嵌套指针默认unique;

    ref指针不充许为null,如果是null则调用直接返回达不到服务器,

    ptr指针最类似C,会作重复性检查,如果在client是相同的指针,rpc到服务端后仍然是相同的指针, 如果unique指针则会是不同的;

    unique指针充许为null, 但pointer_default(ref,unique,ptr)属性影响不了接口里的顶层指针.

    [in][out][in,out] 指针内存:

    顶层的话,内存都是由调用者管理;

     [out]的内嵌指针内存则是由被调用者管理(CoTaskMemAlloc),由调用者释放(CoTaskMemFree);除非有专门文档说明,否则当调失败时,caller可以假定该方法没有分配任何内存;

    [in,out] 的内嵌指针内存除了有以上特点外,caller还可以先给内嵌指针CoTaskMemAlloc, server端再使用CoTaskMemRealloc/CoTaskMemFree, 最后返回caller时caller再调用CoTaskMemFree. (p.s. CoTaskMemFree可以接受空指针并且不出错)
    ====================================
    ReamMe:

    DllNoProp.idl
        This file contains the IDL definitions of the type library, the interfaces
        and co-classes defined in your project.
        This file will be processed by the MIDL compiler to generate:
            C++ interface definitions and GUID declarations (DllNoProp.h)
            GUID definitions                               (DllNoProp_i.c)
            A type library                                   (DllNoProp.tlb)
            Marshaling code                                (DllNoProp_p.c and dlldata.c)

     ====================================

    手工添加接口(非属性化, DECLARE_REGISTRY_RESOURCEID):
    1,添加IDL文件;
    2,在IDL中写接口,如果这个接口在当前工程要单独实现,则还要考虑是否要写coclass;
    3,修改IDL文件属性,控制成生的头文件、IID文件、代理文件的名称;
    4,写RGS文件;

    5,生成工程注册(产生 interface.h[有iid,clsid,libid的声明及coclass,interface,interface_ps的声明]; interface_i.c[有iid,clsid,libid的实现]; interface_p.c[代理存根]等文件)。
    6,生成PS工程,并注册(如果没有发生跨套间的行为,则projectnameps.dll用不行,列集&散集时,只处理*ps.dll中出现的接口)。

    注1:project的rgs文件内容有:interface, appid。参见 rgs示例2。

    注2:interface的rgs文件内容有:clsid, progid, vi_progid。参见 rgs示例1。

    手工添加接口(属性化,resource_name = "IDR_DLLPROP"):
    1,头加头文件(接口,o, udp);

    2,添加头文件&实现文件(接口的实现类, ct, udp);
    3,编译并注册。

    注1:接口本身无需rgs文件,但是模块还是需要一个RGS文件的,如果没有则会注册失败。

    注2:编译工程时,会产生_projectname.idl文件,midl.exe处理这个文并生成 _projectname.h,  _projectname_i.c, _projectname_p.c, dlldata.c文件。
    //============================================
    rgs示例:

    HKCR
    {

     simsvc.svcmgr.1 = s 'svcmgr Class'
     {
      CLSID = s '{359DF5E3-3B95-40D0-971C-7A7B98057566}'
     }
     simsvc.svcmgr = s 'svcmgr Class'
     {
      CLSID = s '{359DF5E3-3B95-40D0-971C-7A7B98057566}'
      CurVer = s 'simsvc.svcmgr.1'
     }
     NoRemove CLSID
     {
      ForceRemove {359DF5E3-3B95-40D0-971C-7A7B98057566} = s 'svcmgr Class'
      {
       ProgID = s 'simsvc.svcmgr.1'
       VersionIndependentProgID = s 'simsvc.svcmgr'
       ForceRemove 'Programmable'
       LocalServer32 = s '%MODULE%'
       val AppID = s '%APPID%'
       'TypeLib' = s '{EF8C3909-361A-4EB4-8A19-8E9ED017157A}'
      }
     }
    }

    ----------------------------------
    HKCR
    {
     NoRemove Interface
     {
      '%IID_IIMAppManager%'
      {
       TypeLib = s '%APPID%'
       {
        val Version = s '1.0'
       }
      }
      '%IID_IIMStdApp%'
      {
       TypeLib = s '%APPID%'
       {
        val Version = s '1.0'
       }
      } 
     }
     
     NoRemove AppID
     {
      '%APPID%' = s 'simsvc'
      'simsvc.exe'
      {
       val AppID = s '%APPID%'
      }
     }
    }
    //============================================

    interface(IID):

    1, ProxyStubClsid/ProxyStubClsid32. 多个interface指向同一个clsid(非标准代理存根,如果接口实现了IDispatch,代理存根DLL可以不注册而使用系统标准的PS_CLSID).

    2, TypeLib(可选, 非属性化工程对应于DECLARE_REGISTRY_APPID_RESOURCEID宏参数中定义的uuid,对于属性化工程则对应于module属性的uuid值; 类型库最后存放在exe/dll的TYPELIB资源中);

    3, NumMethods(可选);


    clsid:

    1, InprocServer32/LocalServer/RemoteServer(Apartment, 默认modulename).

    2,ProgID & VersionIndependentProgID.

    3,TypeLib(同interface, 类型库最后存放在exe/dll的TYPELIB资源中, 另外如果这个资源不存在则注册会失败,如果不完整则会有部iid/clsid没有注册).

    4,Version

    appid:
    1, {appid} -> 默认(module name without suffix).

    2, module name with suffix -> appid键值对.
    注:非属性化工程对应于idl文件中的library的uuid属性,对于属性化工程则对应于module属性的uuid值;  另外还需要REGISTRY类型的资源,资源里的%appid%替换成这个值。
     

    typelib:

    1, HKCR > TypeLib > {libid} > 1.0 > 0 > win32 .

    2, HKCR > TypeLib > {libid} > 1.0 > flags.

    3, HKCR > TypeLib > {libid} > 1.0 > helpdir(可选).
    注:属性化工程,APPID与{libid}共用一个,即module属性里的uuid;
    非属性化工程,DECLARE_REGISTRY_APPID_RESOURCEID(IDR_EXECOMSVRTEST, "{3C31F58A-2FAF-463A-9292-AE95726B9794}") 声明APPID; DECLARE_LIBID(LIBID_ExeComSvrTestLib) 声明LIBID_XXXX。
    #define DECLARE_LIBID(libid) \
     static void InitLibId() throw() \
     { \
      ATL::CAtlModule::m_libid = libid; \
     }

    //============================================  

    C++ 类:

    类的声明,可以在同一cpp文件中出现多次;

    类的定义,同一工程内可以出现多次,但一个cpp内只能出现一次; 

    类的静态数据成员/类的成员函数 的实现(非内联),在一个工程里面只能出现一次或者0次(从DLL中引入,不过需要.lib文件)。

    C++ 类和类的定义 

    http://www.yesky.com/22/194022.shtml 

    类的定义格式
      类的定义格式一般地分为说明部分实现部分。说明部分是用来说明该类中的成员,包含数据成员的说明和成员函数的说明。成员函数是用来对数据成员进行操作的,又称为“方法”。实现部分是用来对成员函数的定义。概括说来,说明部分将告诉使用者“干什么”,而实现部分是告诉使用者“怎么干”。

    //============================================ 

    属性化ATL接口中,如果参数中有另外一个接口的指针,则必须看到这个接口的实现,而不是声明。这点和纯C++不一致,在纯C++中,有类的声明就可以使用类的指针。

  • 相关阅读:
    20145202 《信息安全系统设计基础》课程总结
    20145234黄斐《网络对抗技术》实验六-信息搜集与漏洞扫描
    20145234黄斐《Java程序设计》实验二—Java面向对象程序设计
    20145234黄斐《Java程序设计》第九周
    20145234黄斐《网络对抗技术》实验五,MSF基础应用
    20145234黄斐《Java程序设计》第八周
    20145234黄斐《Java程序设计》实验一—Java开发环境的熟悉(Linux + Eclipse)
    20145234黄斐《Java程序设计》第七周
    20145234黄斐《网络对抗技术》实验四,恶意代码分析
    20145234黄斐《java程序设计》第六周
  • 原文地址:https://www.cnblogs.com/gakusei/p/2551908.html
Copyright © 2020-2023  润新知