【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)

时间:2020-12-23 20:04:20
Introduction to COM - What It Is and How to Use It
By Michael Dunn
From www.codeproject.com

/**********原创翻译,转载请注明出处*********** 新手水平有限,欢迎批评指教 By FreeKid /

COM入门简介 -- 什么是COM , 怎样使用它 (5)

使用多个含有多个接口的COM对象

第二个示例展示了如何对只有一个接口的COM对象使用QueryInterface()函数。代码使用在shell中包含的Shell Link Coclass来创建一个指向当前壁纸文件的快捷方式,壁纸文件名我们是从上一个例子中获得的。

步骤如下:

    1. 初始化COM库。
    2. 创建COM对象以便创建快捷方式,并且获得IShellLink接口。
    3. 调用IShellLink接口的SetPath()方法。
    4. 在COM对象上调用QueryInterface()并获得一个IPersistFIle接口。
    5. 调用IPersistFile接口的Save()方法。
    6. 释放所有接口。
    7. 反初始化COM库。

【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)CString       sWallpaper = wszWallpaper;  // Convert the wallpaper path to ANSI
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)
IShellLink*   pISL;
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)IPersistFile
* pIPF;
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)    
// 1. Initialize the COM library (make Windows load the DLLs). Normally you would
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)    
// call this in your InitInstance() or other startup code.  In MFC apps, use
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)    
// AfxOleInit() instead.
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)
    CoInitialize ( NULL );
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)    
2. Create a COM objectusing the Shell Link coclass provided by the shell.
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)    
// The 4th parameter tells COM what interface we want (IShellLink).
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)
    hr = CoCreateInstance ( CLSID_ShellLink,
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)                            NULL,
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)                            CLSCTX_INPROC_SERVER,
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)                            IID_IShellLink,
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)                            (
void**&pISL );
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)    
if ( SUCCEEDED(hr) )
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)        
{
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)        
// 3. Set the path of the shortcut's target (the wallpaper file).
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)
        hr = pISL->SetPath ( sWallpaper );
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)        
if ( SUCCEEDED(hr) )
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)            
{
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)            
// 4. Get a second interface (IPersistFile) from the COM object.
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)
            hr = pISL->QueryInterface ( IID_IPersistFile, (void**&pIPF );
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)            
if ( SUCCEEDED(hr) )
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)                
{
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)                
// 5. Call the Save() method to save the shortcut to a file.  The
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)                
// first parameter is a Unicode string.
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)
                hr = pIPF->Save ( L"C:/wallpaper.lnk", FALSE );
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)                
// 6a. Release the IPersistFile interface.
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)
                pIPF->Release();
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)                }

【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)            }

【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)        
// 6b. Release the IShellLink interface.
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)
        pISL->Release();
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)        }

【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)    
// Printing of error messages omitted here.
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)    
// 7. Uninit the COM library.  In MFC apps, this is not necessary since MFC
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)    
// does it for us.
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)
    CoUninitialize();


处理HRESULTs

我已经展示了一些使用SUCCEEDED和FAILED宏进行错误处理的简单例子。现在我会进一步说明应当怎样处理从COM方法中返回的HRESULTs类型。

HRESULT是一个32位的有符号整数。非负表示成功,负数则表示失败。HRESULT有三个域(field):the severity bit(用来指明成功或失败),the facility code和 the status code. "facility"指明了HRESULT来自哪个组件或程序。微软把facility codes分配给了不同的组件,比如COM,比如任务调度器(Task Scheduler)等等。这种code是一串16位没有内在含义的数字。它们仅仅是用来在数字和含义之间建立一种随意的联系,就像用GetLastError()的返回值那样。

如果你在winerror.h文件中查看这些错误代码,你会发现那里列出了很多HRESULTs。它们的格式是这样的:[facility]_[severity]_[description].通常的HRESULTs可以不含有facility部分,它们可以被任何组件返回。例如:

    REGDB_E_READREGDB:Facility = REGDV,代表"registry database"; E = error; READREGDB是一种错误的描述(不能读取数据库)
    S_OK:Facility = generic; S = success; OK是一种状态描述(一切正常)

幸运的是,有许多比在winerror.h文件中查看更容易的方式,来弄清楚HRESULT的意思。HRESULTs可以用错误查看工具来进行处理。比如,你忘记了在使用CoCreateInstance()之前调用CoInitialize().CoCreateInstance()将返回错误代码0x800401F0,你可以把这个错误代码输入的错误查看工具中,然后你就会看到描述信息:“CoInitialize没有被调用”

【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)

你也可以在调试器中查看HRESULT的描述信息。如果你有一个叫做hres的HRESULT变量,你可以在观察窗口(Watch window)中输入"hres,hr"进行查看。"hr"会告诉VC将hres的值作为一个HRESULT描述信息显示出来。
【原创翻译】COM入门简介 -- 什么是COM , 怎样使用它 (5)

参考书目:

Essential COM by Don Box, ISBN 0-201-63446-5. Everything you'd ever want to know about the COM spec and IDL (interface definition language). The first two chapters go into great detail about the COM spec and the problems it was designed to solve.

MFC Internals by George Shepherd and Scot Wingo, ISBN 0-201-40721-3. Contains an in-depth look at MFC's COM support.

Beginning ATL 3 COM Programming by Richard Grimes, et al, ISBN 1-861001-20-7. This book goes into depth about about writing your own COM components using ATL.


(全文完)