Modest opinions
by a humble autodidact
公告
昵称:
yushih
园龄:
3年11个月
粉丝:
2
关注:
2
日历
<
2008年3月
>
日
一
二
三
四
五
六
24
25
26
27
28
29
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
3
4
5
统计
随笔 - 57
文章 - 1
评论 - 133
引用 - 1
导航
博客园
首页
发新随笔
发新文章
联系
订阅
管理
搜索
常用链接
我的随笔
我的评论
我的参与
最新评论
我的标签
我的标签
F#
(11)
www
(9)
ruby
(7)
python
(5)
CppCLI
(4)
FP
(4)
Cpp
(3)
HTML Javascript
(3)
C#
(2)
book review
(1)
更多
随笔档案
2011年9月 (1)
2010年9月 (1)
2010年7月 (1)
2010年6月 (1)
2010年5月 (1)
2010年1月 (3)
2009年6月 (1)
2008年11月 (2)
2008年10月 (8)
2008年9月 (6)
2008年8月 (3)
2008年7月 (6)
2008年6月 (6)
2008年5月 (2)
2008年4月 (2)
2008年3月 (16)
最新评论
阅读排行榜
评论排行榜
推荐排行榜
2008年3月6日
一个在C++/CLI中手工列集System::String的辅助工具
虽然在C++/CLI中调用DLL里的native函数时,P/Invoke可以自动把System::String
列集成C字串(const char*或const wchar_t*),但有的时候我们仍然需要手工
列集System::String。比如当出现以下情况时:1.托管代码要调用同属一个mixed assembly里的非托管函数(比如和一个
非托管
静态库链接),并传递一个字串,此时P/Invoke自动列集不能发挥作用,因为这项功能只针对从DLL里导入的函数。2.调用一个以非托管指针操作C字串的托管函数,如编译成IL代码的老的C/C++函数。为了简便手工列集System::String,我写了几个辅助类。以下例子说明如何使用:
#include
<
iostream
>
#include
"
StringMarshaller.h
"
int
main()
{
using
namespace
std;
using
namespace
System;
String
^
s1
=
"
sometimes
"
;
String
^
s2
=
"
C++/CLI
"
;
String
^
s3
=
"
sucks
"
;
wcout
<<
(
const
wchar_t
*
)
StringMarshaller::MarshalStringUni(s1)
;
cout
<<
StringMarshaller::MarshalStringAnsi(s2)
;
wcout
<<
(
const
wchar_t
*
)
StringMarshaller::MarshalStringPin(s3)
<<
endl;
}
可以看到在StringMarshaller.h的名字空间StringMarshaller里有三个“函数”MarshalStringUni, MarshalStringAnsi和MarshalStringPin。其中前两个要将传递的内容进行一次拷贝,最后一个不拷贝,但是会在被调用函数返回之前pin住传递的System::String。MarshalStringPin得到的是unicode字串,因为CLR中的字串是以unicode方式储存的。需要注意的是使用这三个“函数”的条件是被调用函数不会保存传入的const char或const wchar_t指针,因为被调用函数返回后这些指针就失效了。
以下是StringMarshaller.h的源码:
#pragma
once
#include
<
vcclr.h
>
namespace
StringMarshaller
{
using
namespace
System;
using
namespace
System::Runtime::InteropServices;
/**/
/////////////////////////////////////////////////////////////////////
// The copying version
template
<
typename CharT
>
//
CharT = char or unsigned char or wchar_t
class
copy_marshaller
{
IntPtr m;
public
:
copy_marshaller(IntPtr x)
{ m
=
x; }
operator
const
CharT
*
()
{
return
static_cast
<
const
CharT
*>
(m.ToPointer()); }
~
copy_marshaller()
{ Marshal::FreeHGlobal(m); }
}
;
#define
DEFINE_MarshalString(encoding, type)\
struct
MarshalString##encoding:
public
copy_marshaller
<
type
>
\
{\
MarshalString##encoding(String
^
s)\
: copy_marshaller
<
type
>
(Marshal::StringToHGlobal##encoding(s))\
{}
\
}
;
DEFINE_MarshalString(Ansi,
char
) //
MarshalStringAnsi
DEFINE_MarshalString(Uni, wchar_t) //
MarshalStringUni
/**/
/////////////////////////////////////////////////////////////////////
// The pining version.
class MarshalStringPin
{
GCHandle h;
public:
MarshalStringPin(String^ s)
{
h = GCHandle::Alloc(s, GCHandleType::Pinned);
}
operator const wchar_t*()
{
return reinterpret_cast<wchar_t*>(
h.AddrOfPinnedObject().ToPointer());
}
~MarshalStringPin()
{
h.Free();
}
};
}
posted @ 2008-03-06 23:50 yushih 阅读(218) 评论(0)
编辑
Visual C++ .NET WinForm designer sucks
个人认为,C++/CLI的WinForm designer是个败笔,败就败在它非要和相应的C++/CLI代码实时对应。这样的结果就是用起来很迟钝,非常的不流畅,非常的不爽,估计就是前列腺炎的虚拟体验。增加、删除、修改control和切换窗口的时候都有明显的延迟,而且伴随硬盘动作。须知我打Day of Defeat的时候,延迟大于80ms的服务器是不会进的。我认为不是我机器配置不够,我的CPU是3800+X2,硬盘有?m的缓存,内存不多,1.5G,但是1.Visual Studio,包括Windows的cache manager,并没用把这些内存用完,2.本人的机子上没有病毒(supposedly)和防毒软件(两者并列世界上最邪恶的程序),3.本人的操作系统是小巧灵动节约资源的Windows XP(真是没想到XP也有今天,但是不出几年Vista也能得到这样的评价)。为什么怀疑这样的延迟是“和相应的C++/CLI代码实时对应”引起的呢?因为Visual Studio 6的dialog editor没有这样的功能,也没有这样的毛病,即使在性能差得多的机子上也没有可感知的延迟。忍受了如此缺陷,这个功能带来了什么好处呢?啥也没有。WinForm designer生成的代码并不好看:随着用户在WinForm designer里反复添加删除controls及其属性,生成的代码到处是乱糟糟的缩进,随机出现的空白行、accessibility modifiers。把和WinForm对应的C++/CLI代码暴露出来,是方便程序员用代码控制UI吗?比如你想把某控件的宽度设置成分辨率的函数,而不是一个常数?也不是。WinForm designer生成的代码根本不能手工修改,除非你准备从此以后再不用WinForm designer。如果你过度的修改了WinForm designer生成的代码,既便得到的代码可以编译、运行,WinForm designer也可能无法解析,而不能映射成图形,只在屏幕上留下几个exception。
基于以上的原因,当我不得不用WinForm时,我根本不以代码窗口打开WinForm designer使用的那个头文件。我会另建一个头文件,定义一个class,继承WinForm designer生成的class,然后在这个新的class搞进一步初始化,event handling之类的事。或者让Form中的controls都成为public成员,在另外的文件里用一个controller类包含这个Form类,访问相关controls,比如安装event handlers。
我希望WinForm designer在内存中用二进制的对象结构,比如一个syntax tree,记录正在被修改的Form,并将相关信息(Form衍生类的public部分)告知IntelliSense。编译的时候直接用这个二进制的对象结构生成IL代码就可以了。我不需要看到我正在编辑的WinForm的C++/CLI代码。
不知道用WinForm designer生成C#代码有没有这样的问题?有体验的读者请留下评论。谢谢。
posted @ 2008-03-06 00:44 yushih 阅读(403) 评论(2)
编辑
Copyright © yushih
Powered by:
博客园
模板提供:
沪江博客