以COM组建的形式写出来的DLL可以给几乎任何语言调用,包括脚本语言,并且提供面向对象的接口,并且接口参数类型一般都是统一的。
而普通DLL,只有部分语言可以调用,很多脚本语言都无法调用,并且提供的是面向过程的接口,接口参数类型不统一,比如有一些结构体作参数、指针作参数甚至C++类对象作参数的函数,在其它没有指针的语言中调用起来很麻烦甚至无法调用。如果不是工作中需要你用C++开发COM组件,那么还是别花多少时间去学了,ATL的书籍为什么难找,因为和ATL/COM相关的书籍在10年前就绝版了,为什么10年前就绝版了,10年以来再没有新书了,为什么VisualStudio中的ATL10年来不仅没有更新,反而被微软裁剪的越来越小了,肯定是有原因的

解决方案 »

  1.   

    《COM本质论》、《深入解析ATL》 
    都已经绝版了。
      

  2.   

    COM 已经很成熟了, 再写书, 也是重复, 并且很难超过那些经典
    去淘宝买复印的吧.com 继续存在
      

  3.   

    为了OPCServer,不得不学下com,不容易啊
      

  4.   

    ATL 7.0 字符串转换类和宏
    ATL 7.0介绍了一些新的转换类和宏,为现有的宏提供了重要的改进。
    新的字符串转换类和名称宏的形式是:C 源类型 2[C] 目标类型[EX]
    其中:
    •源类型和目标类型描述如下表.
    • [C]是目标类型必须是只读的.
    •[EX]是缓冲器的初始大小必须被指定为一个模板参数。源类型/目标类型 描述
    A ANSI字符串
    W Unicode字符串
    T 通用字符串(如果定义了_UNICODE)则等同于W,否则等同于A
    OLE OLE字符串(等同于W)
     
    例如,从一个Unicode字符串转换为普通字符串不改变转换后的字符串,使用CW2CT。
    小心:
    上面的一些组合是不支持的。CA2CW和CW2CA(以及CA2CWEX和CW2CAEX)是不支持的。
    对于OLE字符串的转换,只支持COLE2T和CT2OLE(以及COLE2CT,COLE2TEX,COLE2CTEX,CT2COLE,CT2OLEEX和CT2COLEEX)。更多细节,参考atlconv.h.
    注意:
      

  5.   

    对于BSTR字符串的转换操作推荐使用CComBSTR类,转换为BSTR时将现有的字符串传入CComBSTR的构造函数,从BSTR转换,使用COLE2[C] 目标类型[EX],比如COLE2T。
    新的转换类要求用一个固定大小的静态缓存区来存储转换结果。如果结果太大而不适合静态缓存区,类将使用malloc来分配内存,并在对象超出范围之后释放内存。不像较早的文本转换宏,以上特性保证了这些类在循环中的安全使用,避免了栈溢出。
    默认情况下,ATL转换类和转换宏使用当前线程的ANSI代码页转换。如果有特殊转换需要覆盖默认行为,可以使用基于类CA2WEX 或 CW2AEX的宏,在类的构造函数的第二个参数指定代码页。安全提醒:
    将字符串传入这些宏之前检查长度可以避免潜在的缓冲区溢出问题。堆栈溢出可以通过try/except抓取。旧的字符串转换宏和新的字符串转换类之间的几个重要区别:
    Old ATL 3.0 Conversion Macros New ATL 7.0 Conversion Classes
    在栈上分配内存 小字符串在栈上,栈内存不足则使用堆
    函数退出时释放字符串 变量超出范围时释放字符串
    无异常处理 可以在异常处理中使用
    不适合循环使用,内存增长直到函数退出 支持循环使用。循环范围确保内存被释放在每个迭代。
    不适合大的字符串,栈内存有限 支持大字符串,堆上分配内存
    需要USES_CONVERSION 不再需要USES_CONVERSION
    OLE的意义取决于OLE2ANSI的定义 OLE始终等于W.示例代码:
    //Example 1 
    // 将LPCWSTR 转为 LPCSTR. 
    void ExampleFunction1(LPCWSTR pszW)
    {
       // Create an instance of CW2A, called pszA, 
       // and initialize it with pszW.
       CW2A pszA(pszW);
       // pszA works like an LPCSTR, and can be used thus:
       ExampleFunctionA(pszA);  
       // Note: pszA will become invalid when it goes out of scope.
    }// Example 2 
    // 使用CW2A的临时实例
    void ExampleFunction2(LPCWSTR pszW)
    {
       // Create a temporary instance of CW2A, 
       // and initialize it with pszW.
       ExampleFunctionA(CW2A(pszW));
       // Note: the temporary instance becomes invalid  
       // after the execution of the statement above.
    }// Example 3 
    // 转换宏的错误使用 
    void ExampleFunction3(LPCWSTR pszW)
    {
       // Create a temporary instance of CW2A, 
       // save a pointer to it and then delete 
       // the temportary instance.
       LPCSTR pszA = CW2A(pszW); //ERROR USE
       // The pszA in the following line is an invalid pointer, 
       // as the instance of CW2A has gone out of scope.
       ExampleFunctionA(pszA);
    }
      

  6.   

    关于临时类实例的一个警告:
    需要强调的是以下代码是错误的代码。
    LPCTSTR szr = CA2T(szReplaceFile);使用ATL3.0宏,这是可以接受的使用方法:
    LPCTSTR szr = A2T(szReplaceFile);   //A2T→ ATL 3.0
    因为由转换函数申请的内存直到函数退出时才释放。同样的代码在新的(ATL 7.0)类中是不工作的。为什么呢?
    这行代码
     LPCTSTR szr = CA2T(szReplaceFile); 
    实际上等价于
    LPCTSTR szr;
    {
       CA2T temp(szReplaceFile);
       szr = temp.operator LPTSTR();
    }   
    因为内存是由临时对象申请的、由类型转换操作符返回的,当对象销毁时它也销毁了,再使用szr的值结果将是未知的。替换代码是,
    CA2T szr(szReplaceFile);   
    这样,类型转换操作符(cast operator)生产了一个LPCTSTR.高阶使用
    默认的静态缓冲区大小是128个字符,如果需要改变缓冲区的大小,使用EX版本的宏,并以模板参数指定缓冲区的大小。
    // Example 4 
    // 改变缓冲区的大小
    void ExampleFunction4(LPCWSTR pszW)
    {
       // 使用16个字符的缓冲区.
       ExampleFunctionA(CW2AEX<16>(pszW));
    }
    下面是一个通过类构造函数的第二个参数指定代码页大小的例子:
    // Example 5 
    // 指定代码页. 
    void ExampleFunction5(LPCWSTR pszW)
    {
       // Convert to the Macintosh code page
       ExampleFunctionA(CW2A(pszW, CP_MACCP));
    }