社区
ATL
帖子详情
编了一个控件,在xp下注册成功以后,一开始用vc调用时可以成功,后来把控件改写了一下,再用vc调用时就出现“找不到成员”的错误,各位高手如何解决。
qinzhonghello
2007-11-03 10:18:39
编了一个控件,在xp下注册成功以后,一开始用vc调用时可以成功,后来把控件改写了一下,再用vc调用时就出现“找不到成员”的错误,各位高手如何解决。
...全文
252
15
打赏
收藏
编了一个控件,在xp下注册成功以后,一开始用vc调用时可以成功,后来把控件改写了一下,再用vc调用时就出现“找不到成员”的错误,各位高手如何解决。
编了一个控件,在xp下注册成功以后,一开始用vc调用时可以成功,后来把控件改写了一下,再用vc调用时就出现“找不到成员”的错误,各位高手如何解决。
复制链接
扫一扫
分享
转发到动态
举报
写回复
配置赞助广告
用AI写文章
15 条
回复
切换为时间正序
请发表友善的回复…
发表回复
打赏红包
qinzhonghello
2007-11-09
打赏
举报
回复
问题解决了,完全是因为还留有残余,没有把后来添加的_IrcEvents删除干净才导致了“找不到成员”的错误。
jameshooo
2007-11-08
打赏
举报
回复
你是怎么删除接口和属性的?除了要在class中改,还要删除IDL文件中的相应描述
ouyh12345
2007-11-08
打赏
举报
回复
新建一个对话框来测试控件
qinzhonghello
2007-11-08
打赏
举报
回复
我删除接口和属性,是在整个解决方案中通过查找接口和属性名字得到相关的文件(包括IDL,cpp,h文件)并在其中将相关内容都删除了的。
bao2lei
2007-11-07
打赏
举报
回复
有点奇怪啊,帮顶!
qinzhonghello
2007-11-07
打赏
举报
回复
我在运行里输入“regsvr32 /u/i e://code/bin/r.dll”,弹出对话框提示DllUnregisterServer成功,
然后输入“regsvr32 e://code/bin/r.dll”弹出对话框提示DllRegistersever成功,当我再次用vc调用这个控件时还是弹出了“找不到成员”的对话框提示错误。
qinzhonghello
2007-11-07
打赏
举报
回复
我也这样改了,还是不行啊
oo_v_oo
2007-11-07
打赏
举报
回复
插入控件并加入变量时,vc自动生成了该控件的类定义,试一试将生成的类定义从项目中删除,并且删除相应的硬盘文件,重新加入控件的对象,重新生成类定义
另外,确认一下控件是否是正确的
qinzhonghello
2007-11-07
打赏
举报
回复
改写了控件之后,我就重新在VC里插入控件,可是结果还是一样的。
qinzhonghello
2007-11-07
打赏
举报
回复
我改控件的时候,开始没有改写原来的接口,只是添加了一个接口函数和一个属性,后来觉得没有添加接口的必要,又把它们删除了,最后只是改写了控件的Onpaint函数并给控件添加了一个按钮。
qinzhonghello
2007-11-07
打赏
举报
回复
我在控件上单击右键选择“添加变量...”,于是就有一个Rc1类型的变量m_Rc和控件联系在一起了。每次编译的时候程序是可以通过的,可是调试的时候,一运行到有m_Rc的地方就弹出一个对话框提示说“找不到成员”。没有改写控件之前,一切都是好的,可是一改写之后就有这个对话框弹出来,请高手帮忙解决一下。在下不胜感激!
ouyh12345
2007-11-07
打赏
举报
回复
接口变了吗?
变了的话,需要重新插入ActiveX控件
qinzhonghello
2007-11-07
打赏
举报
回复
我建了一个工程,view是基于CFormView的,在对话框IDD_XXX_FORM上面单击右键,选择“插入ActiveX控件...”,这样就把控件添加进去了。
wshcdr
2007-11-07
打赏
举报
回复
你在VC里是怎么使用这个控件的?
import?
还是在工具栏里,直接拖放到界面上的?
wshcdr
2007-11-06
打赏
举报
回复
很可能是注册的问题
以前的控件的注册还在
要把以前的反注册掉才可以
Android 自定义
控件
(一)完全自定义
控件
Android自定义
控件
,是Android开发者必须熟练掌握的技术之一,特别是中高级开发者。本套视频详细讲解了安卓自定义
控件
开发的过程,并且结果实战开发。学习本套视频后,你会真正理解自定义
控件
在UI效果展示上的强大之...
VC
++6.0核心编程源码.rar
第一部分 程序员必读 第一章 对程序
错误
的处理 在我们开始介绍Microsoft Windows应该提供的许多特性之前,我们首先必须了解Windows的各个函数是如何进行
错误
处理的。 当你
调用
一个
Windows函数
时
,它首先要检验你传递给它的的各个参数的有效性,然后再设法执行它的任务。如果你传递了
一个
无效参数,或者由于某种原因它无法执行这项操作,那么该函数就会返回
一个
值,指明该函数在某种程度上运行失败了。表1-1列出了大多数Windows函数使用的数据类型的返回值。 表1-1 Windows函数常用的返回值类型 数据类型 表示失败的值 VOID 该函数的运行不可能失败。Windows函数的返回值类型很少 是VOID。 BOLL 如果函数运行失败,那么返回值是0,否则返回的是非0值。最 好对返回值进行测试,以确定它是0还是非0。如果它是TRUE ,则不要测试返回值。 HANDLE 如果函数运行失败,则返回值通常是NULL,否则返回值为 HANDLE,,用于标识你可以操作的
一个
对象。对于这个返回 值,你应该小心处理,因为有些函数会返回
一个
句柄 值INVALID_HANDLE_VALUE,它被定义为-1。该函数的 Platform SDK资料将会清楚地说明该函数是返回NULL还 是INVALID_HANDLE_VALID,以便指明函数运行已经失败。 PVOID 如果函数运行失败,则返回值是NULL,否则返回PVOID,以 标识数据块的内存地址。 LONG/DWORD 这是个难以处理的值。返回数量的函数通常返回LONG 或DWORD。如果由于某种原因,函数无法对你想要进行计数 的对象进行计数,那么该函数通常返回0或-1(根据该函数而定) 。如果你
调用
的函数返回了LONG/DWORD,那么请认真阅 读Platform SDK资料,以确保你能正确检查潜在的
错误
。 当
一个
Windows函数返回
一个
错误
代码
时
,它常常可以用来了解函数为什么会运行失败。Microsoft公司编译了
一个
所有可能的
错误
代码的列表,并且为每个
错误
代码分配了
一个
32位的号码。 从系统内部来讲,当
一个
Windows函数检测到
一个
错误
时
,它会使用
一个
称为线程本地存储器的机制,将相应的
错误
代码号码与
调用
的线程关联起来。(“线程本地存储器”将在第21章中介绍)。这将使线程能够互相独立地运行,而不会影响各自的
错误
代码。当函数返回给你
时
,它的返回值就能指明
一个
错误
已经发生。若要确定这是个什么
错误
,请
调用
GetLastError函数: 见原书P4的程序(1) 该函数只返回线程的32位
错误
代码。 当你拥有32位
错误
代码的号码
时
,你必须将该号码转换成更有用的某种对象。WinError.h头文件包含了Microsoft公司定义的
错误
代码的列表。下面我显示了该列表的某些内容,使你能够看到它的大概样子: 见原书P4的程序(2)和P5的程序 你可以看到,每个
错误
都有3种表示法:即
一个
消息ID(这是你可以在源代码中使用的
一个
宏,以便与GetLastError的返回值进行比较),消息文本(对
错误
的英文描述)和
一个
号码(你应该避免使用这个号码,而应该使用消息ID)。请记住,我只选择了WinError.h头文件中的很少一部分内容来向你进行展示,整个文件的长度超过21000行。 当Windows函数运行失败
时
,你应该立即
调用
GetLastError函数,否则,如果你
调用
另
一个
Windows函数,它的值很可能被
改写
。 说明 GetLastError能返回线程产生的最后
一个
错误
。如果该线程
调用
的Windows 函数运行
成功
,那么最后
一个
错误
代码就不被
改写
,并且不指明运行
成功
。有少 数Windows函数并不遵循这一规则,并且它会更改最后的
错误
代码,但是Platform SDK资料通常指明,当函数运行
成功
时
,该函数会更改最后的
错误
代码。 Windows 98 许多Windows 98的函数实际上是用Microsoft公司的16位Windows 3.1产 品产生的16位代码来实现的。这种比较老的代码并不通过GetLastError之类函 数来报告
错误
,而且Microsoft公司并没有在Windows 98中修改16位代码,以 支持这种
错误
处理方式。对于我们来说,这意味着Windows 98中的许多Win32 函数在运行失败
时
不能设置最后的
错误
代码。该函数将返回
一个
值,指明运行失 败,这样你就能够发现该函数确实已经运行失败。但是你无法确定运行失败的原 因。 有些Windows函数之所以能够
成功
运行,那是若干个原因产生的结果。例如,创建指明的事件内核对象之所以能够取得
成功
,原因是你实际上创建了该对象,或者是因为已经存在带有相同名字的事件内核对象。你的应用程序必须知道
成功
的原因。为了将该信息返回给你,Microsoft公司选择使用最后
错误
代码机制。这样,当某些函数运行
成功
时
,你就能够通过
调用
GetLadtError函数来确定其他的一些信息。对于具有这种行为特性的函数来说,Platform SDK资料清楚地说明了GetLastError函数可以这样来使用。请参见该资料,以便
找
出CreateEvent函数的例子。 当你进行调试的
时
候,我发现监控线程的最后
错误
代码是非常有用的。在Microsoft Visual studio 6.0中,Microsoft的调试程序支持
一个
非常有用的特性,即你可以配置Watch窗口,以便始终都能向你显示线程的最后
错误
代码的号码和该
错误
的英文描述。通过选定Watch窗口中的一行,并键入“@err,hr",你就能够做到这一点。观察图1-1,你会看到我已经
调用
了CreateFile函数。该函数返回INVALID_HANDLE_VALUE(-1)的HANDLE,表示它未能打开指定的文件。但是Watch窗口向我们显示最后
错误
代码(即如果我
调用
GetLastErro函数,该函数返回的
错误
代码)是0x00000002。该Watch窗口又进一步指明
错误
代码2是指“系统不能
找
到指定的文件。”你会发现它与WinError.h头文件中的
错误
代码2所指的字符串是相同的。 图1-1 在Visual Studio 6.0的Watch窗口中键入 “@err,hr",你就可以查看当前线程的最后
错误
代码。 Visual studio还配有
一个
小的实用程序,称为Error Lookup。你可以使用Error Lookup将
错误
代码的号码转换成它的文本描述。 见P7的Error Lookup插图 如果我在我编写的应用程序中发现
一个
错误
,我可能想要向用户显示该
错误
的文本描述。Windows提供了
一个
函数,可以将
错误
代码转换成它的文本描述。该函数称为FormatMessage。请看下面的代码: 见原书P8的程序(1) FormatMessage函数的功能实际上是非常丰富的,在创建向用户显示的字符串信息
时
,它是人们首选的函数。该函数之所以有这样大的作用,原因之一是它很容易用多种语言来进行操作。该函数能够检测出用户首选的语言(在Regional Settings Control Panel小应用程序中设定),并返回相应的文本。当然,你首先必须自己转换字符串,然后将已转换的消息表资源嵌入你的.exe文件或DLL模块,不过,这
时
该函数会选定正确的嵌入对象。ErrorShow示例应用程序(本章后面将加以介绍)展示了如何
调用
该函数,以便将Microsoft公司定义的
错误
代码转换成它的文本描述。 有些人常常问我,Microsoft公司是否建立了
一个
主控列表,以显示每个Windows函数可能返回的所有
错误
代码。可惜,答案是没有这样的列表,而且Microsoft公司将永远不会建立这样的
一个
列表。因为在创建系统的新版本
时
,建立和维护该列表实在太困难了。 建立这样
一个
列表
时
存在的问题是,你可以
调用
一个
Windows函数,但是该函数能够在内部
调用
另
一个
函数,而这另
一个
函数又可以
调用
另
一个
函数,如此类推。由于各种不同的原因,这些函数中的任何
一个
函数都可能运行失败。有
时
,当
一个
函数运行失败
时
,较高级的函数对它进行恢复,并且仍然可以执行你想执行的操作。为了创建该主控列表,Microsoft公司必须跟踪每个函数的运行路径,并建立所有可能的
错误
代码的列表。这项工作很困难。当创建系统的新版本
时
,这些函数的运行路径就会改变。 1.1 你也能够定义自己的
错误
代码 好了,我已经说明Windows函数是如何向函数的
调用
者指明发生的
错误
。Microsoft公司也使你能够将该机制用于你自己的函数。比如说,你编写了
一个
你希望其他人
调用
的函数。你的函数可能因为这样或那样的原因而运行失败,你必须向函数的
调用
者说明它已经运行失败。 若要指明函数运行失败,你只需要设定线程的最后的
错误
代码,然后让你的函数返回FALSE,INVALID_HANDLE_VALUE,NULL,或者返回任何合适的信息。若要设定线程的最后
错误
代码,你只需要
调用
下面的代码: 见原书P8的程序(2) 请将你认为合适的任何32位号码传递给该函数。我设法使用WinError.h中已经存在的代码,只要该代码能够正确地指明我想要报告的
错误
即可。如果你认为WinError.h中的任何代码都不能正确地反映该
错误
的性质,那么你可以创建你自己的代码。
错误
代码是个32位的数字,它可以划分成下表所示的各个域。 位 31-30 29 28 27-16 15-0 内容 严重性 Microsoft/ 保留 设备代码 异常代码 客户 含义 0=
成功
0=Microsoft 必须是0 由Microsoft 由Microsoft/ 1=供参考 公司定义的 公司定义 客户定义 2=警告 代码 3=
错误
1=客户定义 的代码 这些域将在第24章中详细讲述。现在,你需要知道的重要域是第29位的信息。Microsoft公司规定,他们建立的所有
错误
代码的这个信息位均使用0。如果你创建自己的
错误
代码,你必须在这个信息位中输入1。这样,就可以确保你的
错误
代码与Microsoft公司目前或者将来定义的
错误
代码不会发生冲突, 1.2 ErrorShow示例应用程序 ErrorShow应用程序“01 ErrorShow.exe"(在图1-2中列出)展示了如何获取
错误
代码的文本描述的方法。该应用程序的源代码和资源文件位于本书所附光盘上的01-ErrorShow目录下。一般来说,该应用程序用于显示调试程序的Watch窗口和Error Lookup程序是如何运行的。当你启动该程序
时
,就会
出现
下面这个窗口。 见原书P9的插图 你可以将任何
错误
代码键入该编辑
控件
。当你单击Look Up按钮
时
,在底部的滚动窗口中就会显示该
错误
的文本描述。该应用程序唯一令人感兴趣的特性是如何
调用
FormatMessage函数。下面是我使用该函数的方法: 见原书P10的程序(1) 第
一个
代码行用于从编辑
控件
中检索
错误
代码的号码。然后,建立
一个
内存块的句柄并将它初始化为NULL。FormatMessage函数在内部对内存块进行分配,并将它的句柄返回给我们。 当
调用
FormatMessage函数
时
,我传递了FORMAT_MESSAGE_FROM_SYSTEM标志。该标志告诉FormatMessage函数,我们想要系统定义的
错误
代码的字符串。我还传递了FORMAT_MESSAGE_ALLOCATE_BUFFER标志,告诉该函数为
错误
代码的文本描述分配足够大的内存块。该内存块的句柄将在hlocal变量中返回。第三个参数指明我们想要查
找
的
错误
代码的号码,第四个参数指明我们想要文本描述使用什么语言。 如果FormatMessage函数运行
成功
,那么
错误
代码的文本描述就位于内存块中,我将它拷贝到对话框底部的滚动窗口中。如果FormatMesage函数运行失败,我设法查看NetMsg.dll模块中的消息代码,以了解该
错误
是否与网络有关。使用NetMsg.dll模块的句柄,我再次
调用
FormatMessage函数。你会看到,每个DLL(或.exe)都有它自己的一组
错误
代码,你可以使用Message Compiler(MC.exe)将这组
错误
代码添加给该模块,并将
一个
资源添加给该模块。这就是Visual Studio的Error Lookup工具允许你用Modules对话框进行的操作。 图1-2 ErrorShow示例应用程序 见原书P11—16 第2章 UNICODE 随着Microsoft公司的Windows操作系统在全世界日益广泛的流行,对于我们这些软件开发人员来说,将我们的目标瞄准国际上的各个不同市场,已经成为
一个
越来越重要的问题。美国的软件版本比国际版本提前6个月推向市场,这曾经是个司空见惯的现象。但是,由于各国对Windows操作系统提供了越来越多的支持,因此就更加容易为国际市场生产各种应用软件,从而缩短了软件的美国版本与国际版本推出的
时
间间隔。 Windows操作系统始终不逾地提供各种支持,以帮助软件开发人员进行应用程序的本地化工作。应用软件可以从各种不同的函数中获得特定国家的信息,并可观察控制面板的设置,以确定用户的首选项。Windows甚至支持不同的字体,以适应我们的应用的需要。 我之所以将这一章放在本书的开头,是因为我考虑到Unicode是开发任何应用程序
时
要采用的基本步骤。关于Unicode的问题,我在本书的每一章中几乎都要讲到,而且本书中给出的所有示例应用程序都是“用Unicode实现的”。如果你为Microsoft Windows 2000或Microsoft Windows CE开发应用程序,你应该使用Unicode进行开发。如果你为Microsoft Windows 98开发应用程序,你必须对某些问题作出决定。本章也要讲述Windows 98的有关问题。 2.1 字符集 软件的本地化要
解决
的真正问题,实际上就是如何来处理不同的字符集。多年来,我们许多人一直将文本串作为一系列单字节字符来进行编码,并在结尾处放上
一个
零。对于我们来说,这已经成了习惯。当我们
调用
strlen函数
时
,它在以0结尾的单字节字符数组中返回字符的数目。 问题是,有些文字和书写规则(比如日文中的汉字就是个典型的例子)的字符集中的符号太多了,因此单字节(它提供的符号最多不能超过256个)是根本不敷使用的。为此我们创建了双字节字符集(DBCS),以支持这些文字和书写规则。 2.1.1 单字节与双字节字符集 在双字节字符集中,字符串中的每个字符可以包含
一个
字节,也可以包含两个字节。例如,日文中的汉字,如果第
一个
字符在0x81与0x9F之间,或者在0xE0与0xFC之间,那么你就必须观察下
一个
字节,才能确定字符串中的这个完整的字符。如果要使用双字节字符集,对于程序员来说简直是个很大的难题,因为有些字符只有
一个
字节宽,而有些字符则是两个字节宽。 如果只是
调用
strlen函数,那么你无法真正了解字符串中究竟有多少字符,它只能告诉你到达结尾的0之前有多少个字节。ANSI的C运行期库中没有配备相应的函数,使你能够对双字节字符集进行操作。但是,Microsoft Visual C++的运行期库却包含许多函数,如_mbslen,它可以用来操作多字节(既包括单字节也包括双字节)字符串。 为了帮助你对DBCS字符串进行操作,Windows提供了下面的一组帮助函数。 函数 描述 PTSTR CharNext 返回字符串中的下
一个
字符的地址 (PCTSTR pszCurrentChar); PTSTR CharPrev 返回字符串中的上
一个
字符的地址 (PCTSTR pszStart, PCTSTR pszCurrentChar); BOOL IsDBCSLendByte 如果该字节是DBCS字符的第
一个
字节,则返 (BYTE bTestChar); 回TRUE 2.1.2 Unicode:宽字节字符集 Unicode是Apple和Xerox公司于1988年建立的
一个
技术标准。1991年,成立了
一个
集团机构负责Unicode的开发和推广应用。该集团由Apple、Compaq、HP、IBM、Microsoft、Oracle、Silicon Graphics、Sybase、Unisys和Xerox等公司组成。(若要了解该集团的全部
成员
,请通过网址www.Unicode.org查
找
。)该集团公司负责维护Unicode标准。Unicode的完整描述可以参阅AddisonWesley出版的《Unicode Standard》一书。(该书可以通过网址www.Unicode.org订购。) Unicode提供了一种简单而又一致的表示字符串的方法。Unicode字符串中的所有字符都是16位的字符(两个字节)。它没有专门的字节来指明下
一个
字节是属于同
一个
字符的组成部分,还是
一个
新字符。这意味着你只需要对指针进行递增或递减,就可以遍历字符串中的各个字符。你不再需要
调用
CharNext,CharPrev和IsDBCSLeadByte之类的函数。 由于Unicode用
一个
16位的值来表示每个字符,因此总共可以得到65000个字符,这样,它就能够对世界各国的书面文字中的所有字符进行编码。这远远超过了单字节字符集的256个字符的数目。 目前,已经为阿拉伯文、中文拼音、西里尔字母(俄文)、希腊文、西伯莱文、日文、韩文和拉丁文(英文)字母定义了Unicode代码点1。这些字符集中还包含了大量的标点符号、数学符号、技术符号、箭头、装饰标志、区分标志和其他许多字符。如果你将所有这些字母和符号加在一起,总计约达35000个不同的代码点,这样,总计的65000个代码点中,大约还有一半可供将来扩充
时
使用。 这65536个字符可以分成不同的区域。下面这个表显示了一部分这样的区域以及分配给这些区域的字符。 16位代码 字符 16位代码 字符 0000-007F ASCII 0300-036F 通用区分标志 0080-00FF 拉丁文1字符 0400-04FF 西里尔字母 0100-017F 欧洲拉丁文 0530-058F 亚美尼亚文 0180-01FF 扩充拉丁文 0590-05FF 西伯莱文 0250-02AF 标准拼音 0600-06FF 阿拉伯文 02B0-02FF 修改型字母 0900-097F 梵文 注1. 代码点是指字符集中的
一个
符号的位置 目前尚未分配的代码点大约还有29000个,不过它们是保留供将来使用的。另外,大约有6000个代码点是保留供你个人使用的。 2. 2 为何应该使用Unicode 当你开发应用程序
时
,你当然应该考虑利用Unicode的优点。即使现在你不打算对你的应用程序进行本地化,开发
时
将Unicode放在心上,肯定可以简化将来的代码转换工作。此外,Unicode还具备下列功能: * 可以很容易地在不同语言之间进行数据交换 * 使你能够分配支持所有语言的单个二进制.exe文件或DLL文件 * 提高你的应用程序的运行效率(本章后面还要详细介绍) 2.3 Windows 2000与Unicode Windows 2000是使用Unicode从头进行开发的,用于创建窗口、显示文本、进行字符串操作等的所有核心函数都需要Unicode字符串。如果你
调用
任何
一个
Windows函数并给它传递
一个
ANSI字符串,那么系统首先要将字符串转换成Unicode,然后将Unicode字符串传递给操作系统。如果你希望函数返回ANSI字符串,系统就会首先将Unicode字符串转换成ANSI字符串,然后将结果返回给你的应用程序。所有这些转换操作都是在你看不见的情况下发生的。当然,进行这些字符串的转换需要占用系统的
时
间和内存开销。 例如,如果你
调用
CreateWindowEx函数,并传递类名字和窗口标题文本的非Unicode字符串,那么CreateWindowEx必须分配内存块(在你的进程的默认堆中),将非Unicode字符串转换成Unicode字符串,并将结果存储在分配到的内存块中,然后
调用
Unicode版本的CreateWindowEx函数。 对于用字符串填入缓存的函数来说,系统必须首先将Unicode字符串转换成非Unicode字符串,然后你的应用程序才能处理该字符串。由于系统必须执行所有这些转换操作,因此你的应用程序需要更多的内存,并且运行的速度比较慢。通过从头开始用Unicode来开发应用程序,你就能够使你的应用程序更加有效地运行。 2. 4 Windows 98与Unicode Windows 98不是一种全新的操作系统。它继承了16位Windows操作系统的特性,它不是用来处理Unicode。如果要增加对Unicode的支持,其工作量非常大,因此在该产品的特性列表中没有包括这个支持项目。由于这个原因,Windows 98象它的前任产品一样,几乎都是使用ANSI字符串来进行所有的内部操作的。 你仍然可以编写用于处理Unicode字符和字符串的Windows应用程序,不过,使用Windows函数要难得多。例如,如果你想要
调用
CreateWindowEx函数并将ANSI字符串传递给它,这个
调用
的速度非常快,不需要从你进程的默认堆栈中分配缓存,也不需要进行字符串转换。但是,如果你想要
调用
CreateWindowEx函数并将Unicode字符串传递给它,你就必须明确分配缓存,并
调用
函数,以便执行从Unicode到ANSI字符串的转换操作。然后你可以
调用
CreateWindowEx,传递ANSI字符串。当CreateWindowEx函数返回
时
,你就能释放临
时
缓存。这比使用Windows 2000上的Unicode要麻烦得多。在本章的后面部分中,我要介绍如何在Windows 98下进行这些转换。 虽然Unicode函数的大多数代码在Windows 98中不起任何作用,但是有少数Unicode函数确实拥有非常有用的实现代码。这些函数是: 见原书的P21 可惜的是,这些函数中有许多函数在Windows 98中会
出现
各种各样的
错误
。有些函数无法使用某些字体,有些函数会破坏内存堆栈,有些函数会使打印机驱动程序崩溃,如此等等。如果你要使用这些函数,你必须对它们进行大量的测试。即使这样,你可能仍然无法
解决
问题。因此你必须向用户说明这些情况。 2. 5 Windows CE与Unicode Windows CE操作系统是为小型设备开发的,这些设备的内存很小,并且不带磁盘存储器。你可能认为,由于Microsoft公司的主要目标是建立一种尽可能小的操作系统,因此它会使用ANSI作为自己的字符集。但是Microsoft公司并不是鼠目寸光。他们懂得,采用Windows CE的设备要在世界各地销售,他们希望降低软件开发成本,这样就能更加容易地开发应用程序。为此,Windows CE本身就是使用Unicode的一种操作系统。 但是,为了使Windows CE尽量做得小一些,Microsoft公司决定完全不支持ANSI Windows函数。因此,如果你要为Windows CE开发应用程序,你必须懂得Unicode,并且在整个应用程序中使用Unicode。 2. 6 需要注意的问题 下面让我们进一步明确
一下
“Microsoft公司对Unicode支持的情况”: * Windows 2000既支持Unicode,也支持ANSI,因此你可以为它们当中的任何一种开发应用程序 * Windows 98 只支持ANSI,你只能为ANSI开发应用程序 * Windows CE只支持Unicode,你只能为Unicode开发应用程序 虽然Microsoft公司试图让软件开发人员能够非常容易地开发在这3种平台上运行是软件,但是Unicode与ANSI之间的差异使得事情变得困难起来,并且这种差异通常是我遇到的最大的问题之一。请不要误解,Microsoft公司坚定地支持Unicode,并且我也坚决鼓励你使用它。不过你应该懂得,你可能遇到一些问题,需要一定的
时
间来
解决
这些问题。我建议你尽可能使用Unicode。如果你运行Windows 98,那么只有在必要
时
才要转换到ANSI。 不过,还有另
一个
小问题你应该了解,那就是COM。 2.7 对COM的简单说明 当Microsoft公司将COM从16位Windows转换成Win32
时
,公司作出了
一个
决定,即,需要字符串的所有COM接口方法都只能接受Unicode字符串。这是个了不起的决定,因为COM通常用于使不同的组件能够互相之间进行通信,而Unicode则是传递字符串的最佳手段。 如果你为Windows 2000或Windows CE开发应用程序,并且也使用COM,那么你将会如虎添翼。在你的整个源代码中使用Unicode,将使与操作系统进行通信和与COM对象进行通信的操作变成一件轻而易举的事情。 如果你为Windows 98开发应用程序,并且也使用COM,那么你将会遇到一些问题。COM要求你使用Unicode字符串。操作系统的大多数函数要求你使用ANSI字符串。那是多么难办的事情啊!我曾经从事过若干个项目的开发,在这些项目中,我编写了许多代码,仅仅是为了来回进行字符串的转换。 2. 8 如何编写Unicode源代码 Microsoft公司为Unicode设计了Windows API,这样,它可以尽量减少对你的代码的影响。实际上,你可以编写单个源代码文件,以便使用或者不使用Unicode来对它进行编译。你只需要定义两个宏(UNICODE和_UNICODE),就可以修改然后重新编译该源文件。 2. 8.1 C运行期库对Unicode的支持 为了利用Unicode字符串,因此定义了一些数据类型。标准的C头文件String.h已经作了修改,以便定义
一个
名字为wchar_t的数据类型,它是
一个
Unicode字符的数据类型: 见原书P23的程序(1) 例如,如果你想要创建
一个
缓存,用于存放最多为99个字符的Unicode字符串和
一个
结尾为零的字符,你可以使用下面这个语句: 见原书P23的程序(2) 该语句创建了
一个
由100个16位值组成的数组。当然,标准的C运行期字符串函数,如strcpy、strchr和strcat等,只能对ANSI字符串进行操作,它们不能正确地处理Unicode字符串。因此,ANSI C也拥有一组补充函数。图2-1显示了一些标准的ANSI C字符串函数,后面是它们的等价Unicode函数。 图2-1 标准的ANSI C字符串函数和它们的等价Unicode函数 见原书P23的程序(3)和P24的程序 请注意,所有的Unicode函数均以wcs开头,wcs是宽字符串的英文缩写。若要
调用
Unicode函数,只需用前缀wcs来取代任何ANSI字符串函数的前缀str即可。 说明 大多数软件开发人员可能已经不记得这样
一个
非常重要的问题了,那就 是Microsoft公司提供的C运行期库与ANSI的标准C运行期库是一致的。 ANSI C规定,C运行期库支持Unicode字符和字符串。这意味着你始终都可 以
调用
C运行期函数,以便对Unicode字符和字符串进行操作,即使你是在 Windows 98上运行,也可以
调用
这些函数。换句话说,wcscat,wcslen和wcstok 等函数都能够在Windows 98上很好地运行,这些都是你必须关心的操作系统函数。 对于包含了对str函数或wcs函数进行显式
调用
的代码来说,你无法非常容易地同
时
为ANSI和Unicode对这些代码进行编译。在本章前面部分的内容中,我说过可以创建同
时
为ANSI和Unicode进行编译的单个源代码文件。若要建立这种双重功能,你必须包含Tchar.h文件,而不是包含String.h文件。 Tchar.h文件的唯一作用是帮助你创建ANSI/Unicode通用源代码文件。它包含你应该用在源代码中的一组宏,而不应该直接
调用
str函数或者wcs函数。如果你在编译源代码文件
时
定义了_UNICODE,这些宏就会引用wcs这组函数。如果你没有定义_UNICODE,那么这些宏将引用str这组宏。 例如,在Tchar.h中有
一个
宏称为_tcscpy。如果在你包含该头文件
时
没有定义_UNICODE,那么_tcscpy就会扩展为ANSI的strcpy函数。但是如果定义了_UNICODE,_tcscpy将扩展为Unicode的wcscpy函数。拥有字符串参数的所有C运行期函数都在Tchar.h文件中定义了
一个
通用宏。如果你使用通用宏,而不是ANSI/Unicode的特定函数名,你就能够顺利地创建可以为ANSI或Unicode进行编译的源代码。 但是,除了使用这些宏之外,还有一些操作你是必须进行的。Tchar.h文件包含了一些其他的宏。 若要定义
一个
ANSI/Unicode通用的字符串数组,请使用下面的TCHAR数据类型。如果定义了_UNICODE,TCHAR将声明为下面的形式: 见原书P25的程序(1) 如果没有定义_UNICODE,则TCHAR将声明为下面的形式: 见原书P25的程序(2) 使用该数据类型,你可以象下面这样分配
一个
字符串: 见原书P25的程序(3) 你也可以创建对字符串的指针: 见原书P25的程序(4) 不过上面这行代码存在
一个
问题。按照默认设置,Microsoft公司的C++编译器能够编译所有的字符串,就象它们是ANSI字符串,而不是Unicode字符串。因此,如果没有定义_UNICODE,该编译器将能正确地编译这一行代码。但是,如果定义了_UNICODE,就会产生
一个
错误
。若要生成
一个
Unicode字符串而不是ANSI字符串,你必须将该代码行
改写
为下面的样子: 见原书P25的程序(5) 原义字符串前面的大写字母L,用于告诉编译器该字符串应该作为Unicode字符串来编译。当编译器将字符串置于程序的数据部分中
时
,它在每个字符之间分散插入零字节。这种变更带来的问题是,现在只有当定义了_UNICODE
时
,程序才能
成功
地进行编译。我们需要另
一个
宏,以便有选择地在原义字符串的前面加上大写字母L。这项工作由_TEXT宏来完成,_TEXT宏也在Tchar.h文件中做了定义。如果定义了_UNICODE,那么_TEXT定义为下面的形式: 见原书P25的程序(6)
ATL
3,245
社区成员
48,539
社区内容
发帖
与我相关
我的任务
ATL
ATL,Active Template Library活动(动态)模板库,是一种微软程序库,支持利用C++语言编写ASP代码以及其它ActiveX程序。
复制链接
扫一扫
分享
社区描述
ATL,Active Template Library活动(动态)模板库,是一种微软程序库,支持利用C++语言编写ASP代码以及其它ActiveX程序。
社区管理员
加入社区
获取链接或二维码
近7日
近30日
至今
加载中
查看更多榜单
社区公告
暂无公告
试试用AI创作助手写篇文章吧
+ 用AI写文章