com编程入门:COM编程入门2




wcstombs
这个CRTwcstombs是个简化版但它终结了WideCharToMultiByte所以最终结果是其原型如下:
size_t wcstombs (
char*mbstr,
const wchar_t* wcstr,
size_tcount );

以下是参数解释:
mbstr
接受结果ANSI串(char)缓冲
wcstr
要转换Unicode串
count
mbstr参数所指缓冲大小

wcstombs在它对WideCharToMultiByte中使用WC_COMPOSITECHECK | WC_SEPCHARS标志用wcstombs转换前面例子中Unicode串结果样:

wcstombs ( szANSIString, wszSomeString, (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串下面是使用这些宏例子:

# <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第 2个参数是个常量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)

WCHARwszWallpaper [MAX_PATH];
CString strPath;
HRESULT hr;
IActiveDesktop* pIAD;

// 1. 化COM库(让Windows加载DLLs)通常是在InitInstance
// CoInitialize ( NULL )或其它启动代码MFC使用AfxOleInit

CoInitialize ( NULL );

// 2. 使用外壳提供活动桌面组件对象类创建COM对象
// 第 4个参数通知COM需要什么接口(这里是IActiveDesktop).

hr = CoCreateInstance ( CLSID_ActiveDesktop,
NULL,
CLSCTX_INPROC_SERVER,
IID_IActiveDesktop,
(void**) &pIAD );

( SUCCEEDED(hr) )
{
// 3. 如果COM对象被创建成功这个对象GetWallpaper 思路方法
hr = pIAD->GetWallpaper ( wszWallpaper, MAX_PATH, 0 );

( SUCCEEDED(hr) )
{


// 4. 如果 GetWallpaper 成功则输出它返回文件名字
// 注意这里使用wcout 来显示Unicode 串wszWallpaper.wcout 是
// Unicode 专用功能和cout.相同
wcout << L\"Wallpaper path is:\\n\" << wszWallpaper << endl << endl;
}

{
cout << _T(\"GetWallpaper failed.\") << endl << endl;
}

// 5. 释放接口
pIAD->Release;
}

{
cout << _T(\"CoCreateInstance failed.\") << endl << endl;
}

// 6. 收回COM库MFC 不用这它自动完成
CoUninitialize;

在这个例子中输出/显示Unicode 串 wszWallpaper用是std::wcout

使用多接口COM对象
第 2个例子展示了如何使用个提供单接口COM对象QueryInterface其中代码用外壳Shell Link组件对象类创建我们在第个例子中获得墙纸文件快捷方式
以下是编程步骤:

化COM 库
创建个用于建立快捷方式COM 对象并取得IShellLink 接口
IShellLink 接口SetPath思路方法
对象QueryInterface并取得IPersistFile接口
IPersistFile 接口Save思路方法
释放接口
收回COM库

CStringsWallpaper = wszWallpaper;// 将墙纸路径转换为ANSI
IShellLink*pISL;
IPersistFile* pIPF;

// 1. 化COM库(让Windows 加载DLLs). 通常在InitInstance
// CoInitialize ( NULL )或其它启动代码MFC 使用AfxOleInit

CoInitialize ( NULL );

// 2. 使用外壳提供Shell Link组件对象类创建COM对象.
// 第 4个参数通知COM 需要什么接口(这里是IShellLink)

hr = CoCreateInstance ( CLSID_ShellLink,
NULL,
CLSCTX_INPROC_SERVER,
IID_IShellLink,
(void**) &pISL );

( SUCCEEDED(hr) )
{
// 3. 设置快捷方式目标(墙纸文件)路径
hr = pISL->SetPath ( sWallpaper );

( SUCCEEDED(hr) )
{
// 4. 获取这个对象第 2个接口(IPersistFile)
hr = pISL->QueryInterface ( IID_IPersistFile, (void**) &pIPF );

( 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有 3个域:程度位(表示成功或失败)功能码和状态码功能码表示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的前忘了CoInitializeCoCreateInstance返回值是0x800401F0你只要将这个值输入到查找工具按“Look Up”按钮便可以看到信息描述“尚未CoInitialize”如下图所示:

另外种查找HRESULT描述思路方法是在调试器中假设有个HRESULT变量是hres在Watch窗口左边框中输入“hres,hr”表示想要看“hr”便会通知VC显示HRESULT所描述如下图所示:

通过以上讨论想必你对COM编程有了初步认识本文第 2部分将探讨COM内部机制教你如何用C编写自己接口
Tags:  编程入门教程 电脑编程入门 编程入门 com编程入门

延伸阅读

最新评论

发表评论