袁瑞 的个人资料袁瑞的共享空间照片日志留言簿更多 工具 帮助

日志


9月9日

C++Builder 2009 的一个Bug

编译ActiveX control时,按照原来在CBuilder中的做法,将控件的GUID改成一个固定的GUID值(因为不想每次升级控件后,注册表中出现一堆无用的GUID)

一切看起来都很正常,编译成功。注册ocx控件时,却出现了0x8002802b错误。意思应该是找不到元素。

我开始并没有怀疑是修改了GUID的问题。反复定位才发现不修改GUID时是好的。

可不修改GUID以后怎么玩啊!这个2009也太扯了吧!很多使用控件的地方可都是用GUID实例化的。

 

我反复尝试,最终发现原因。

在 ridl接口设计器上修改接口时,ridl文件内容都是同步修改的,但只有修改GUID时,貌似ridl文件是修改了,但是最终的rtl文件CBuilder似乎没同步。即使你选择全部保存,单独保存都没有用。汗!这样就出现编译出来的内容跟接口对不上。

解决办法是,修改了GUID后,必须在ridl文件的设计界面上点击刷新按键,问题才能解决。

 

看来C++Builder2009,在很多细节上还有问题。

9月5日

使用C++Builder2009编写ActiveX控件的Unicode问题

以前使用C++Builder6编写ActiveX控件, Event中的参数如果有字符串,编译总是有问题。

如果参数类型是AnsiString,创建ActiveX控件时,CBuiler根本就不会为你创建这个事件接口。

如果参数类型是char*,生成的ActiveX控件的参数类型则变成short,我是修改生成的代码,将参数手工变为LPSTR解决的问题。

 

而现在的2009,默认使用的是unicode,参数如果是UnicodeString,CBuilder创建的事件参数则是BSTR,不过我试验了很多次,编译出来的ActiveX控件在微软的测试容器中运行时,触发该事件都会引起内存访问错误。

另外一种方式,将参数声明为wchar_t*,生成的ActiveX控件的参数会变成short,这次改换成LPWSTR,手工修改CBuilder生成的实现类的cpp和h文件,修改TLB文件的h文件,将所有wchar_t类型替换成wchar_t*,同时将short也替换成wchar_t*,编译通过。

不过问题又出现了,在容器中运行,字符串会出现被截断的情况。

比如点燃事件中的字符串本来是"test",作为CBuilder控件进行测试是正常的,但编译成ActiveX控件到了容器里收到的却是"te"。

 

翻了翻2009的帮助文件,其中有这么一段:

WideString

WideString was previously used for multibyte character data. Its format is essentially the same as a Windows BSTR. WideString is still appropriate for use in COM applications. WideString is not reference counted, and so UnicodeString is more flexible and efficient in other types of applications.

New String Type: UnicodeString

The new default for the type string in RAD Studio is the UnicodeString type. This type can contain either Unicode or ANSI string data.  

For Delphi, Char and PChar types still "float" to WideChar and PWideChar, respectively.  

For C++, the _TCHAR maps to option controls the floating definition of _TCHAR, which can be either wchart_t or char.  

Format of UnicodeString Data Type  

CodePage 

Element Size 

Reference Count  

Length  

String Data (element sized)  

Null Term 

-12  

-10  

-8  

-4  

0  

Length * elementsize  

Both UnicodeString and AnsiString have this format, though UnicodeString prefers multibyte data and AnsiString prefers single byte data. 

 

总的来说,新的UnicodeString为了跟AnsiString兼容做了部分处理,而WideString是纯粹的多字节字符串。

 

我看看我的点燃函数:

    if(FOnTextEvent)

        FOnTextEvent(this, Edit->Text.w_str());

 

这里的Edit->Text是UnicodeString类型,w_ctr()返回类型虽然是wchar_t*但是我怀疑问题就是出在这里。

 

于是改成如下代码:

    if(FOnTextEvent)

        FOnTextEvent(this, WideString(Edit->Text).c_bstr());

 

重新测试,一切正常了。这里不禁要提出疑问,2009在转换ActiveX控件时究竟让UnicodeString做了什么工作?是否出现了问题?