- 中查找“COM编程入门2”更多相关内容
- 中查找“COM编程入门2”更多相关内容
- ·上一篇文章:C++Builder 编程指南1
- ·下一篇文章:COM编程入门1
COM编程入门2
wcstombs()
这个CRT函数wcstombs()是个简化版,但它终结了WideCharToMultiByte()的调用,所以最终结果是一样的。其原型如下:
size_t wcstombs (
char* mbstr,
const wchar_t* wcstr,
size_t count );
以下是参数解释:
mbstr
接受结果ANSI串的字符(char)缓冲。
wcstr
要转换的Unicode串。
count
mbstr参数所指的缓冲大小。
wcstombs()在它对WideCharToMultiByte()的调用中使用WC_COMPOSITECHECK WC_SEPCHARS标志。用wcstombs()转换前面例子中的Unicode串,结果一样:
wcstombs ( szANSIString, wszSomeString, sizeof(szANSIString) );
CString
MFC中的CString包含有构造函数和接受Unicode串的赋值操作,所以你可以用CString来实现转换。例如:
// 假设有一个Unicode串wszSomeString...
CString str1 ( wszSomeString ); // 用构造器转换
CString str2;
str2 = wszSomeString; // 用赋值操作转换
ATL宏
ATL有一组很方便的宏用于串的转换。W2A()用于将Unicode串转换为ANSI串(记忆方法是“wide to ANSI”――宽字符到ANSI)。实际上使用OLE2A()更精确,“OLE”表示的意思是COM串或者OLE串。下面是使用这些宏的例子:
#include <atlconv.h>
// 还是假设有一个Unicode串wszSomeString...
{
char szANSIString [MAX_PATH];
USES_CONVERSION; // 声明这个宏要使用的局部变量
lstrcpy ( szANSIString, OLE2A(wszSomeString) );
}
OLE2A()宏“返回”转换的串的指针,但转换的串被存储在某个临时栈变量中,所以要用lstrcpy()来获得自己的拷贝。其它的几个宏是W2T()(Unicode 到 TCHAR)以及W2CT()(Unicode到常量TCHAR串)。
有个宏是OLE2CA()(Unicode到常量char串),可以被用到上面的例子中,OLE2CA()实际上是个更正宏,因为lstrcpy()的第二个参数是一个常量char*,关于这个问题本文将在以后作详细讨论。
另一方面,如果你不想做以上复杂的串处理,尽管让它还保持为Unicode串,如果编写的是控制台应用程序,输出/显示Unicode串时应该用全程变量std::wcout,如:
wcout << wszSomeString;
但是要记住,std::wcout只认Unicode,所以你要是“正常”串的话,还得用std::cout输出/显示。对于Unicode串文字量,要使用前缀L标示,如:
wcout << L"The Oracle says..." << endl << wszOracleResponse;
如果保持串为Unicode,编程时有两个限制:
―― 必须使用wcsXXX() Unicode串处理函数,如wcslen()。
―― 在Windows 9x环境中不能在Windows API中传递Unicode串。要想编写能在9x和NT上都能运行的应用,必须使用TCHAR类型,详情请参考MSDN。
用例子代码总结上述内容
下面用两个例子演示本文所讲的COM概念。代码中还包含了本文的例子工程。
使用单接口COM对象
第一个例子展示的是单接口COM对象。这可能是你碰到得最简单的例子。它使用外壳中的活动桌面组件对象类(CLSID_ActiveDesktop)来获得当前桌面墙纸的文件名。请确认系统中安装了活动桌面(Active Desktop)。
以下是编程步骤:
初始化COM库。 (Initialize)
创建一个与活动桌面交互的COM对象,并取得IActiveDesktop接口。
调用COM对象的GetWallpaper()方法。
如果GetWallpaper()成功,则输出/显示墙纸文件名。
释放接口(Release())。
收回COM库(Uninitialize)。
WCHAR wszWallpaper [MAX_PATH];
CString strPath;
HRESULT hr;
IActiveDesktop* pIAD;
// 1. 初始化COM库(让Windows加载DLLs)。通常是在程序的InitInstance()中调用
// CoInitialize ( NULL )或其它启动代码。MFC程序使用AfxOleInit()。
CoInitialize ( NULL );
// 2. 使用外壳提供的活动桌面组件对象类创建COM对象。
// 第四个参数通知COM需要什么接口(这里是IActiveDesktop).
hr = CoCreateInstance ( CLSID_ActiveDesktop,
NULL,
CLSCTX_INPROC_SERVER,
IID_IActiveDesktop,
(void**) &pIAD );
if ( SUCCEEDED(hr) )
{
// 3. 如果COM对象被创建成功,则调用这个对象的GetWallpaper() 方法。
hr = pIAD->GetWallpaper ( wszWallpaper, MAX_PATH, 0 );
if ( SUCCEEDED(hr) )
{
// 4. 如果 GetWallpaper() 成功,则输出它返回的文件名字。
// 注意这里使用wcout 来显示Unicode 串wszWallpaper. wcout 是
// Unicode 专用,功能与cout.相同。
wcout << L"Wallpaper path is: " << wszWallpaper << endl << endl;
}
else
{
cout << _T("GetWallpaper() failed.") << endl << endl;
}
// 5. 释放接口。
pIAD->Release();
}
else
{
cout << _T("CoCreateInstance() failed.") << endl << endl;
}
// 6. 收回COM库。MFC 程序不用这一步,它自动完成。
CoUninitialize();
在这个例子中,输出/显示Unicode 串 wszWallpaper用的是std::wcout。
使用多接口的COM对象
第二个例子展示了如何使用一个提供单接口的COM对象QueryInterface()函数。其中的代码用外壳的Shell Link组件对象类创建我们在第一个例子中获得的墙纸文件的快捷方式
以下是编程步骤:
初始化COM 库。
创建一个用于建立快捷方式的COM 对象并取得IShellLink 接口。
调用IShellLink 接口的SetPath()方法
调用对象的QueryInterface()函数并取得IPersistFile接口。
调用IPersistFile 接口的Save()方法。
释放接口
收回COM库
CString sWallpaper = wszWallpaper; // 将墙纸路径转换为ANSI
IShellLink* pISL;
IPersistFile* pIPF;
// 1. 初始化COM库(让Windows 加载DLLs). 通常在InitInstance()中调用
// CoInitialize ( NULL )或其它启动代码。MFC 程序使用AfxOleInit() 。
CoInitialize ( NULL );
// 2. 使用外壳提供的Shell Link组件对象类创建COM对象。.
// 第四个参数通知COM 需要什么接口(这里是IShellLink)。
hr = CoCreateInstance ( CLSID_ShellLink,
NULL,
CLSCTX_INPROC_SERVER,
IID_IShellLink,
(void**) &pISL );
if ( SUCCEEDED(hr) )
{
// 3. 设置快捷方式目标(墙纸文件)的路径。
hr = pISL->SetPath ( sWallpaper );
if ( SUCCEEDED(hr) )
{
// 4. 获取这个对象的第二个接口(IPersistFile)。
hr = pISL->QueryInterface ( IID_IPersistFile, (void**) &pIPF );
if ( SUCCEEDED(hr) )
{
// 5. 调用Save() 方法保存某个文件得快捷方式。第一个参数是
// Unicode 串。
hr = pIPF->Save ( L"C:\wallpaper.lnk", FALSE );
// 6a. 释放IPersistFile 接口。
pIPF->Release();
}
}
// 6. 释放IShellLink 接口。
pISL->Release();
}
// 输出错误信息部分这里省略。
// 7. 收回COM 库。MFC 程序不用这一步,它自动完成。
CoUninitialize();
处理HRESULT
这一部分准备用SUCCEEDED 和 FAILED宏进行一些简单的出错处理。主要是深入研究从COM方法返回的HRESULT,以便达到完全理解和熟练应用。
HRESULT是个32位符号整数,其非负值表示成功,负值表示失败。HRESULT有三个域:程度位(表示成功或失败),功能码和状态码。功能码表示HRESULT来自什么组件或程序。微软给不同的组件多赋予功能码,如:COM、任务调度程序等都有功能码。功能码是个16位的值,仅此而已,没有其它内在含义;它在数字和意义之间是随意关联的;类似GetLastError()返回的值。
如果你在winerror.h头文件中查找错误代码,会看到许多按照[功能]_[程度]_[描述]命名规范列出的HRESULT值,由组件返回的通用的HRESULT(类似E_OUTOFMEMORY)在名字中没有功能码。如,
REGDB_E_READREGDB: 功能码 = REGDB, 指“注册表数据库(registry database)”;程度 = E 意思是错误(error);描述 = READREGDB 是对错误的描述(意思是不能读注册表数据库)。
S_OK: 没有功能码――通用(generic)HRESULT;程度=S;表示成功(success);OK 是状态描述表示一切都好(everything's OK)。
好在有一种比察看winerror.h文件更容易的方法来确定HRESULT的意思。使用VC提供的错误查找工具(Error Lookup)可以轻松查到为HRESULT内建功能码。例如,假设你在CoCreateInstance()之前忘了调用CoInitialize()。CoCreateInstance()返回的值是0x800401F0。你只要将这个值输入到错误查找工具按“Look Up”按钮,便可以看到错误信息描述“尚未调用CoInitialize”如下图所示:
另外一种查找HRESULT描述的方法是在调试器中。假设有一个HRESULT变量是hres。在Watch窗口的左边框中输入“hres,hr”,表示想要看的值,“hr”便会通知VC显示HRESULT所描述的值。如下图所示:
通过以上的讨论,想必你对COM编程有了初步的认识,本文第二部分将探讨COM的内部机制。教你如何用C++编写自己的接口。
Tags:
作者:佚名评论内容只代表网友观点,与本站立场无关!
评论摘要(共 0 条,得分 0 分,平均 0 分)
查看完整评论