显示标签为“delphi”的博文。显示所有博文
显示标签为“delphi”的博文。显示所有博文

2010年4月7日星期三

imenu parser for emacs delphi-mode

improve the one found on  http://www.emacswiki.org/emacs/DelphiMode

1. support 'record', 'class' and 'interface' as level 1 menu
2. methods show as submenu of class
3. correctly jump to the impl. part (ignore interface part)

FIXME: currently not work if no 'interface/implementation'

keyword: emacs, delphi, freepascal, imenu, ecb

2006年12月18日星期一

codegear.com网站终于建立起来了

不知道是否会出现当初Borland改名为Inprise时那样的情况: 用户们找不到原来的Borland,以为它已经不再存在了。

2006年10月19日星期四

wine上跑Delphi 7

某天在Delphi盒子上看见一个mini版本的Delphi7,只有5M大小,解压后简单设置一下就可以跑起来。现在常常很不愿意跑个笨重的BDS 2006做简单的试验或者制作界面原型。这个东西正合适。

回家又想,能不能在wine上面跑起来?于是动手来折腾,过程中碰到一些问题,不过到现在终于比较满意了。



1.基本安装

1.1 该安装程序实际是一个RAR的自解压包,随便解压(安装)到人和位置都可以(以下假设为C:Delphi7)。

1.2 解压后完成后会自动调用regd7.exe,这实际上也是一个自解压包,里面包含了调试器代理bordbk70.dll, 注册表数据delphi7.reg和注册信息REGISTRY.SLM。它的解压位置为%USERPROFILE%\.borland,但wine上面 USERPROFILE这个环境变量不一定能正确翻译出来(在Windows上是X:\Documents and Settings),会解压到Program Files里面去。

1.2.1将bordbk70.dll拷贝到C:\Delphi7, 运行regsvr32.exe bordbk70.dll;

1.2.2 然后运行regedit导入delphi32.reg;如果搞不定(没有regedit或者导入不成功),可以直接编辑~/.wine/user.reg,把内容拷贝过去,不过要注意删除HKEY_CURRENT_USER这几个字。

1.2.3 最后建立目录X:\Windows\.borland,将注册信息REGISTRY.SLM拷贝到这个目录下。另外要导入如下内容到HKEY_CURRENT_MACHINE:

 [SoftwareBorlandDelphi7.0] 1160143880

"App"="C:\Delphi7\bin\Delphi32.exe"

"LMKEY"="QX8-EEC"

"LMLIC"="6AKD-PD29Q9-RDF?JQ-X65Z"

"LocalSharedRoot"="C:\Delphi7\Shared"

"RootDir"="C:\Delphi7"

"UseSharedFiles"="TRUE"

"Version"="PRO"

然后就可以运行了: wine c:\delphi7\bin\delphi32.exe

(如果调试时设置了断点但不能停下来,请检查bordbk70.dll是否正确注册; 如果报告delphi没有注册或者没有找到d7reg.exe,请检查上面第1.2.3步)

注意那个mini包带的都是原来delphi7的,没有打过补丁,建议用补丁后的版本(如果你手头没有,可以下载这个所谓的delphi 7 second edition (delphibox下载, delphifans下载))。

2. 加装一些东西

这个mini版本是够精简的,东西很少,连Code Explorer和To-Do List也没有,如果你有Delphi 7 Professional,可以从拷贝vclie70.bpl, vclhie70.bpl, proide70.bpl和delphipro70.bpl这几个文件过来,在Component->Install Packages...中加载delphipro70.bpl即可。

另外也可以安装GExpertsCnWizards,这两个专家包都是针对Personal版本测试过的,尽量减少了对Professional或者Enterprise版本采用的特性的依赖。不过对于Castalia就没有那么好运了。

3.其它

也许你会很愿意让X的窗口管理器来管理Delphi7的窗口,因为它不管是主窗口还是工具窗口都显示成一样,CnWizards的一些扩展按钮也看不着,更重要的是,窗口一拖动就糊成一团,工具窗口的docking也不起作用。

那就改为非managed模式吧: 运行regedit,建立如下内容

 [HKEY_CURRENT_USER\Software\Wine\AppDefaults\delphi32.exe\X11 Driver]

"Managed"="N"
注意改成这样delphi在任务条上是看不见的了,最下化后请去桌面左下角找图标 :-)


2006年10月17日星期二

为什么不升级到BDS2006

Borland的DTG(Developer Tool Group)的掌门人Nick Hodges发出了一个邮件Why aren't you upgrading?,并在Blog上给出一堆应该升级的理由

不料这下可炸开锅了。Blog上的回帖有几十条,话语都很尖锐; 而新闻组borland.public.delphi.non-technical上对这个邮件的直接回信更是长达1100多条。


2006年10月1日星期日

C++类继承中的几个小问题

是的,我一直是个Delphi的粉丝。虽然现在工作上用的是C++(而且是在用VC/MFC),但一直都没有认真去学习它。前两天听俺们项目组的C ++高手讲解了一些“基本知识”,我还是觉得这个语言太复杂了,陷阱也太多。以下有几个例子(鄙人C++确很粗浅,如有不对的地方,敬请指正)。

[@more@]

第一个例子:

class Base
{
public:
virtual void MethodFoo(std::string s);
}
class Child: public Base
{
public:
virtual void MethodFoo(std::string s);
}
Base *b = new Child;
std::string s("something");
b.MethodFoo(str);

我 们会利用多态性来调用不同的MethodFoo实现,但突然有一天你觉得MethodFoo中间s是不应该发生变化的,于是加了一个const。问题来 了,很多编译器不会告诉你任何告警,但b.MethodFoo再也调用不到派生类的MethodFoo了,除非你把它们一个个都改过来。

第二个例子:

class Base
{
public:
virtual void MethodFoo(std::string s);
}

class Child: public Base
{
public:
virtual void MethodFoo(std::string s);
{
DoSometingMyself();
Base::MethodFoo(s);
}
}

突然有一天,你觉得这个设计不太合理,需要在Base和Child之间再插入一层(class Middle),这就意味着你得修改Child所有函数中类似上面黑体的部分,把它们改成Middle::MethodFoo什么的。

第三个例子:

我 们知道C++中支持多继承,但它对于多个基类中有同名同类型函数的问题没有提供解决方法(也许你会说,我们不应该写这样的代码,但仔细想想X, Y都是接口(C++用纯虚类来做)的情况下,难免会有重名的)。对于X, Y均派生自B,而C又牌证自X+Y这种”恐怖的菱形,它有一个"workaround"是用虚基类,但这要求更改X, Y的代码,使得它们虚拟继承自B。

-----------

是的,这三个问题在Delphi中均可以避免:

1. 要重新实现虚方法必须用override关键字;而带有override声明的方法如果参数不一致,编译器会报错;如果基类中不存在叫这个名字的方法,也会报错。而你确实要用同样的函数名做别的事情,得用reintroduce或者overload关键字。

2. Child::MethodFoo中调用其父类的MethodFoo时不用写Base::MethodFoo,直接写inherited MethodFoo就行了。

3. 采用方法分辨子句即可:

TChild = class(TParent, Interface1, Interface2)
procedure Interface1.MethodFoo = MethodFoo1;
procedure Interface2.MethodFoo = MethodFoo2;
procedure MethodFoo1(s: String);
procedure MethodFoo2(s: String);
end;

2006年9月13日星期三

几个Eye Candy (Windows)

  • Blueberry 3D-Desktop 这个Windows外壳可比较另类,找个控制面板就得跟玩DOOM一样找上半天。

2006年9月8日星期五

Borland发布Turbo系列

9月刚来,Borland就如期推出了早先宣布的Turbo系列。可以从下面网址找到下载地址,其中Turbo Explorer系列是免费的,只是不能加装第三方控件和其它扩展。
http://www.turboexplorer.com/

该网站上有几个广告视频链接,挺有意思,看样子应该是90年代初的风格。

2006年8月8日星期二

Borland新瓶装老酒,重新推出Turbo系列

Borland今日用"Turbo"这个名称重新推出了当前的几个开发工具:

? Turbo Delphi for Windows
? Turbo C++ for Windows
? Turbo Delphi for .NET
? Turbo C# for .NET

现在分成了Turbo Explorer和Turbo Enterprise两个系列。前者是免费的,带不能安装第三方控件和其它扩展;后者价格也有了较大优惠,现在是在$500以内(具体还没定),对于学生则是$100以内(以前是$1000 - $3500)。

免费的Turbo Delphi和Turbo C++带有目前已有全部200多个控件,提供数据库、Web应用、网络应用的解决方案,比起以前的student版本是强了不少。

但新闻中没有提到任何关于DevCo的信息,也不知道这次“更名”是否与前几天所说的即将到来的出售有关。

BTW: 俺总觉得不应该再用Turbo C++这个名字 :-)

2006年8月6日星期日

Inno setup, 不错

俺现在用Delphi的时候少了,业余也不怎么玩它了,有时候有点手痒。

俺在公司赖以混饭吃的那个产品原来是用 InstallShield做安装程序的,一直用的是个老版本6.22,都好几年了,有很多功能做起来相当麻烦,很多新特性也不支持;加上IS公司又查的 紧,搞得想升级到新版本又被公司卡得紧;俺又不喜欢它一个工程要一大堆目录的风格(而且还不能随便挪目录)。于是就琢磨着换个免费的工具。

NSISInno Setup之间比较了半天之后,选择了Inno Setup,最开始的原因很简单: Inno是用Delphi写的,而且居然支持用Pascal写安装脚本(好像用的是RemObjects Pascal Script引擎)。

用 了一阵下来,感觉不错:

  • 用InstallShield没法自行调用函数注册COM组件(只好调用外部regsvr32:-(),这个问题在InnoSetup根本就不存在;
  • 用TStrings类可 以很容易地操作非ini类的文本文件,这样原来很多配置文件里面的选项都可以用安装程序来调整了;
  • 同样可以用CreateOLEObject来创建COM对象,并直接调用,俺们的XML配置文件就可以很好解决了;
  • 整个工程设置都在一个文件里面,用版本配置工具管理起来 也方便
  • ......

最重要的是,用Pascal写起代码来让我感觉得心应手,干嘛还要另外学习一个语法古怪的语言:-).

2006年1月31日星期二

GUI程序的RAD和脚本化?

在我赖之混饭吃的那个项目上,这个大版本碰到一个比较棘手的问题, 那就是: 业务功能太多,虽然都不是很复杂,但总工作量却相当之多,加上项目组有2/3是新入职不到一年的同事,所以我们一直想把核心功能和业务功能分开来,后者用脚本来写。

但UI怎么办呢? 当然是要求有一些常用控件的,而且有事件响应能力,脚本中也要求能够操纵这些UI元素。基于俺个人多年的爱好,最好是能够同时编辑UI和事件处理代码(我认为没有这个功能就不能叫RAD:-)。


比较理想的是像Excel/Word那样用VBA(该项目是在Windows上用MFC开发的),但似乎这方面的例子和文档都比较少,也拿不到VBA的试用版来评估一下。

从目前看到的一些东西来看,Windows下比较接近我们的需求的是Script Builder, 它是基于Delphi的,可以直接使用ActiveX或者Delphi编写的package,支持ActiveScript(也就是说可以使用 VBScript, JScript, Python和Perl了)和DelphiScript。如果我们自己的项目是用Delphi开发的,把这个集成进去应该是件很酷的事情。(这个东西实际 是基于以前见过的Dream Scripter,只是UI表现上做得更加接近了我们“用脚本写程序”的想法而已。)

再看一些其他的GUI toolkit吧:

  • gtk有一个glade来编辑界面,然后我们可以在pygtk/python-glade或者gtk-perl/glade-perl来写响应代码,没法直接编辑界面代码(毕竟glade不是针对具体哪种语言的) P.S 刚刚在Planet Debian TW上看见yungyuc介绍一个新东东Gazpacho,说是"看起來是 Python+GTK 的 IDE",我还高兴了一阵,拉下来试试却发现只是一个改为完全用python写的一个glade而已。当然,我们可以以此为基础再来扩展。
  • wxWidgets有个wxGlade, 是模仿Glade的,不用多说。
  • Qt有Qt-Designer来编辑UI, 但这个东西也是跟glade差不多;同时它还有个Qt Script for Application,使得可以通过Qt Script(基于JavaScript)来操纵UI,不知道这两个东西是否可以接合,不过这已经很不错了。
  • SpecTcl是一个tk的界面设计器,不过它可以直接生成脚本(tcl甚至perl, python, ruby)
  • Java方面我用过JBuilder, 对于Borland的这种方式,用最近最红火的郭德纲的话说:“ 这个杭子,我做兴!”,简直" 要了亲命了"。只是因为java的烦琐,一个用JBuilder编写的略微复杂的界面,其创建UI部分的代码,基本上是不可手工维护的。至于Eclipse上UI设计器,还没玩过,不瞎说了。

说了这么些,有朋友会问,到底你们用的哪种?呵呵,记住我们的程序是用MFC写的,也没有买Qt这样的界面套件。最后我们用了用友华表的 Cell控件做模板来模拟UI,上面也可以放些按钮、下拉框什么的,虽然显得很不专业,但总算能对付过去。

想 想也知道为什么这种东西没有基于MFC的: 要在脚本中操纵UI控件(当然是说比较自然的方式,比如MainForm.Statubar1.SimpleText = "hello, world", 不是我见一些高手在tcl里面用c代码封装SendMessage来操纵的那种),这显然要求界面库有良好的RTTI,以便宿主程序能够很方便地将界面控 件对象加到脚本解释器当中去,否则脚本中怎么操纵它们。MFC有这些个嘛? ──除非完全自己手工来折腾。

补充:

1. 忘了gambas了,这个接近于Visual Basic,UI是用Qt写的。

2. mozilla的XUL应该是一个很不错的选择,而且传言很快将加入python支持,只是比较耗内存(似乎也没界面编辑器)。

2006年1月2日星期一

闲话UI: 选择目录对话框

很多时候我们都会要求让用户选择一个文件夹。在很多论坛上都会有朋友问到这个问题:怎么能够显示如下一个对话框?

这用ShBrowserForFolder这个Windows API可以实现。
WINSHELLAPI LPITEMIDLIST WINAPI SHBrowseForFolder(
LPBROWSEINFO lpbi
);

在Delphi中有下面这个函数可以使用:
function SelectDirectory(const Caption: string; const Root: WideString; out Directory: string): Boolean; overload; (1)

但我更喜欢用这个(在一些简单的场合):
function SelectDirectory(var Directory: string; Options: TSelectDirOpts; HelpCtx: Longint): Boolean; overload; (2)


但很多朋友不愿意,认为后面这个太难看。但在我看来,第一个对话框在可用性上是存在很大问题的:
* 不能设置(并展开到)缺省的选择
* 不能手工输入,这使得要进入一个层次深一点的目录非常麻烦
* 不能新建目录

其 实就ShBrowserForFolder这个API而言,第一个问题是很容易解决的,不过M$提供的是一种挺麻烦的方式: 你必须得编写回调函数(BrowseCallbackProc),在BFFM_INITIALIZED消息里面发送BFFM_SETSELECTION消 息。(我觉得Delphi在提供SelectDirectory(1)这个函数时就应该包装这个功能。)

对于第二个问题, 如果你的shell32.dll版本大于或等于4.71, 就可以有个手工输入路径的编辑框了, 只要在flags中包含BIF_EDITBOX;

对 于第三个问题, 如果你的shell32.dll版本大于或等于5.0, 就可以有个"新建文件夹"按钮了, 只要在flags中包含BIF_NEWDIALOGSTYLE (而且这个版本有其他一些特性: 对话框大小可调, 目录可拖动, 目录有context menu(这可以带来其他一些功能)。

BTW:
1. lazarus中有TSelectDirectoryDialog控件,功能上等于Delphi的SelectDirectory(1)函数加上设置缺省目录功能。
2. DFS套件(Torry.Net上的信息)里面有一个dfsBrowseDirectoryDlg控件,支持shell32 5.0的NewDialogStyle,对这个功能包装得比较完整(其实上面的第三个图用得就是这个控件),要添加新版本的特性(比如6.0的BIF_NOTRANSLATETARGETS等)也很容易。

2005年11月5日星期六

Porting simple Delphi application to Lazarus

You should read the following docs first:

Now I'm porting unwebcompiler(see also) to lazarus. The Windows version now works fine. but the linux one would thraw exceptions on LH5 decompressing.

The debugger refuse to work on my Linux box, I have to fall back on gdb.

Another problem is the executable created by Lazarus is too big(as for the unwebcompiler, it is about 6M). :-(

2005年5月17日星期二

lazarus: Delphi for Linux

今天看见新闻Free Pascal发布了2.0,恰好这几日正在玩Lazarus(最近因为工作上要做界面原型,我申请了一份BCB来做,一时间对Delphi(BCB跟Delphi差不多是一回事)的兴趣又回来了,于是回家后又跑到lazarus网站下载了最新版本,安装到我的laptop上),

运行起来后发现控件又多了很多,整体界面也不像原来那么粗糙了,看来前面一段时间一直想写的几个界面小工具可以用这个写了。

注意到这个东西应该是在2001年,Borland正在做Kylix 1.0的时候,在一个linux网站上看见有人提到这个,当时拉下来试过,但功能太少,几乎不能用(当然只作为一个freepascal的IDE是没有问题的,但我这种浅薄之人一向喜欢RAD),所以也就是看了看,转头就放在那里了。

Lazarus IDE screenshot (small)

后来又下载过两次新版本,感觉这个东西是在往Delphi的方向上靠,整体界面的布局,库文件的名称、内容,类的功能几乎都是Delphi的方式(其实Free Pascal的语法也是这样在往上面靠,上面的新闻对应的讨论里面有人说: "The later Object Pascal versions of the language is actually very nice to use in most respects. There are features in OP7 from Borland that I would die for in C++ or Java (methods attached transparently for property get/set). ")

对做GUI而言,跟Kylix不同的是, 它的界面库底层采用的是标准的gtk-1.2,并不象Kylix那样做出来的软件还必须附带一堆由Borland修改过的QT库。

不 过UNIX下还是C/C++的天下,其他的语言总是无法进入聚光灯(这里是可生成native程序的语言,不包括脚本语言),Borland最后只好对 Kylix偃旗息鼓,跟这点似乎也有些关系。相对C++的繁琐而言,我跟喜欢Pascal的严谨、条理清楚,即使是Borland的版本自己加了不少语法 和特性也比C++要简洁(毕竟没有多个厂家都来添加特性搞得乱七八糟)。

不过free pascal和Lazarus却似乎不管外面的世界多么喧嚣、浮躁,自己在不紧不慢地前进着,据说1.0到2.0就用了5年,LCL, SynEdit, Indy...

P.S: 如果你想在lazarus上用上gtk2,也是可以的: gtk2forpascal
P.P.S: lazarus也有win32版本,不过界面相对Linux下显得粗糙一些。

2005年3月14日星期一

怎样在exe中内嵌程序的帮助文档

重新编写ezMsg2时,翻出原来用的一个"奇技淫巧":在exe的资源中嵌入HTML文档,然后"帮助"菜单项中调用res://path/to/exe/foo.html在IE里显示出来

1. 编写用户文档
假设有index.htm, manual.htm, minimsg.png, buttons.gif四个文件, htm间有相互连接,

2.编写doc.rc文件

INDEX_HTML 23 "index.htm"
MANUAL_HTML 23 "manual.htm"
minimsgr_png 23 "minimsgr.png"
buttons_gif 23 "buttons.gif"

3.编译得到doc.res文件, 可用brcc32

brcc32 doc.rc

4.将doc.res连接到exe中
比如Delphi中

{$R doc.res}


5.然后在代码中调用

sDocFile := '"res://' + Application.ExeName + '/index_html"';
ShellExecute(Self.Handle, 'Open', //action
'iexplore.exe', //program
PChar(sDocFile),//parameters
nil, //current dir
SW_MAXIMIZE); //window command

注意URL的最后(index_html)就是index.html在rc中的资源标识符

6.但这里有一个问题: index.htm嵌入的图片显示不出来,点击index.htm中到manual.html的连接也无法出来。
这是因为res://foo.exe/后面是根据资源标识符来定位资源的,但这里并没有一个名称为manual.html或者buttons.gif的资源,而同时manual.html也不是一个合法的资源标识符('.'是不允许的)。
解决办法是用UltraEdit编辑doc.res,查找FF FF 17 00,每个后面都是资源标识符,改为对应的文件名即可('_'改为'.')。注意如果入口标识符(INDEX_HTML)如果改掉的话,代码中也要相应修改。



2005年3月4日星期五

RPM content plugin for Total Commander

今天有空,在Mandryka Yurij的rpm_wcx源代码基础上完成了rpm content plugin
下载: rpm_wdx-1.00-src.zip

读取包信息部分的代码如下,很简单,是不是?


function ReadRPMInfo(filename: String): integer;
var
fh: integer;
fh_file: file;
r_lead: RPM_Lead;
signature, r_header: RPM_Header;
//r_info: RPM_InfoRec;
begin
Result := -1;
fh := FileOpen(filename, fmOpenRead or fmShareDenyNone);
if fh=-1 then exit;


AssignFile(fh_file, filename);
try
FileMode := 0;
Reset(fh_file, 1);

if IOResult <> 0 then exit;

RPM_ReadLead(fh_file, r_lead);
if r_lead.magic <> RPM_MAGIC then exit;

if not RPM_ReadSignature(fh_file, r_lead.signature_type, signature) then exit;

if not RPM_ReadHeader(fh_file, false, r_header, FileInfoCache) then exit;

Result := 0;
finally
CloseFile(fh_file);

FileClose(fh); //oppsition to FileOpen
end;
end;

2005年3月1日星期二

Debian package content plugin for Total Commander

年前完成了Debian package content plugin for Total Commander,可以在Total Commander中显示.deb文件的各项说明.
(下载: deb_wdx-1.02.zip deb_wdx-1.02-src.zip)

前两天发给了Ghisler,今天收到回信


年前完成了Debian package content plugin for Total Commander,可以在Total
Commander中显示.deb文件的各项说明: Package, Version, Depends/Suggests/Conflicts,
Installed-Size, Summary, Description...

但因为公司邮件系统的过滤,年前发给Ghisler的邮件给拦截了。

前两天在gmail上重新发了一遍,今天收到Ghisler的回信:

Christian Ghisler &lt;beta@ghisler.com&gt; to me
More options 2/28/05 (3 days ago)

Hi,

I have tested your Debian plugin now - it's very nice! Can you please
fill out the plugin submissions form so I can put your plugin online?

&gt; You gave one two years ago, when I sent my debunpacker, although you've
&gt; got one from another developer just a few days before. Thanks for your
&gt; generosity.
&gt; But I won't reject a new one if you give for the new plugins I write,
&gt; so that I can give it to my friend :-)

Yes you can, just send me the name+address of your friend (for the key).

&gt; Now I finished the first one: Debian Linux package (*.deb) content plugin.
&gt; (I'm a debian fan, and often running Total Commander with WINE.
&gt; Both the binary and the source attached.

Works fine with the .deb files with which I have tested.

Best regards

Christian Ghisler



Powered by ScribeFire.

2005年2月26日星期六

文摘: MSN / QQ 中的动画表情 在Delphi中RichEdit的实现。

相信用过QQ、MSN中的动画表情对我们的吸引力了吧。在前几天我的一个小应用中需要添加这样的一个功能,首先从网上下载了RXLib2.75(包括RxRichEdit),安装后测试了一下它提供的例子$(DELPHI)RXDemoRICHED2Richedit.dpr,在使用插入GIF图片时我发现了一个严重的问题:就是GIF图片是不会动的。因为原来对COM这些技术接触较少,只有上网查询资料,首先我去了大富翁www.delphibbs.com查找,不过没有查到,后来终于在网上查到了dtianx大侠的资料(见文章前面的链接),不过我发现他提供的代码是C++下的,于是把这些代码转换了一下,使其在Delphi下也能用。 ...

原文出处: CSDN

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ActiveX, ComCtrls, RxRichEd, ImageOleLib_TLB;

//RxRichEd单元是Rxlib下的RxRichEdit,一套增强功能的RichEdit
//ImageOleLib_TLB是从qq的ImageOle.dll引入的类型库

const
IID_IOleObject: TGUID = (
D1: $00000112; D2: $0000; D3: $0000; D4: ($C0, $00, $00, $00, $00, $00, $00,
$46));
EM_GETOLEINTERFACE = WM_USER + 60;
type
TForm1 = class(TForm)
Button1: TButton;
Editor: TRxRichEdit;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation
{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var
FRTF: IRichEditOle;
FLockBytes: ILockBytes;
FStorage: ISTORAGE;
FClientSite: IOLECLIENTSITE;
m_lpObject: IOleObject;
m_lpAnimator: TGifAnimator;
i_GifAnimator: IGifAnimator;
reobject: TReObject;
clsid: TGuid;
sizel: tagSize;
dwStart, dwEnd: DWORD;
Rect:TRect;
begin
try
if CreateILockBytesOnHGlobal(0, True, FLockBytes) <> S_OK then
begin
showmessage('Error to create Global Heap');
exit;
end;
//建立一个混合文档存取对象
if StgCreateDocfileOnILockBytes(FLockBytes, STGM_SHARE_EXCLUSIVE or
STGM_CREATE or STGM_READWRITE, 0, FStorage) <> S_OK then
begin
Showmessage('Error to create storage');
exit;
end;
//取得RichEdit的接口
Sendmessage(Editor.handle,EM_GETOLEINTERFACE,0,LongInt(@FRTF));

if FRTF.GetClientSite(FClientSite)<>S_OK then
begin
ShowMessage('Error to get ClentSite');
Exit;
end;
CoInitializeEx(nil, COINIT_APARTMENTTHREADED);
m_lpAnimator := TGifAnimator.Create(Self);
i_GifAnimator := m_lpAnimator.ControlInterface;
i_GifAnimator.LoadFromFile('c:ti.gif');
i_GifAnimator.QueryInterface(IID_IOleObject, m_lpObject);
OleSetContainedObject(m_lpObject, True);
FillChar(ReObject, SizeOf(ReObject), 0);
ReObject.cbStruct := SizeOf(ReObject);
m_lpObject.GetUserClassID(clsid);
ReObject.clsid := clsid;
reobject.cp := REO_CP_SELECTION;
//content, but not static
reobject.dvaspect := DVASPECT_CONTENT;
//goes in the same line of text line
reobject.dwFlags := REO_BELOWBASELINE; //REO_RESIZABLE |
reobject.dwUser := 0;
//the very object
reobject.poleobj := m_lpObject;
//client site contain the object
reobject.polesite := FClientSite;
//the storage
reobject.pstg := FStorage;
sizel.cx := 0;
sizel.cy := 0;
reobject.sizel := sizel;
//Sel all text
SendMessage(Editor.Handle, EM_SETSEL, 0, -1);
SendMessage(Editor.Handle, EM_GETSEL, dwStart, dwEnd);
SendMessage(Editor.Handle, EM_SETSEL, dwEnd + 1, dwEnd + 1);
//Insert after the line of text
FRTF.InsertObject(reobject);
SendMessage(Editor.Handle, EM_SCROLLCARET, 0, 0);
//VARIANT_BOOL ret;
//do frame changing
m_lpAnimator.TriggerFrameChange();
//show it
m_lpObject.DoVerb(OLEIVERB_UIACTIVATE, Nil, FClientSite, 0, Editor.Handle,Rect);
// m_lpObject.DoVerb(
m_lpObject.DoVerb(OLEIVERB_SHOW, Nil, FClientSite, 0, Editor.Handle, Rect);
//redraw the window to show animation
redrawwindow(Handle, nil, 0, RDW_ERASE or RDW_INVALIDATE or RDW_FRAME or RDW_ERASENOW or RDW_ALLCHILDREN);
finally
FRTF:=nil;
FClientSite := nil;
FStorage :=nil;
end;
end;

end.

2005年1月20日星期四

Delphi的SOAP Header问题

对于我的程序,服务器要求的Header是这样(只是要添加两个简单的元素):


BigLuo
111


但Delphi中的SOAPHeader只能通过继承TSOAPHeader来实现,但这样就会把派生类的名字添加上去,变成了这样:



4
2005-01-06T15:01:26.531Z



怎么办?




1.Delphi给了一个SOAP Header的示例



4
2005-01-06T15:01:26.531Z




实现方法是:
1.先定义一个TSOAPHeader的继承类,要在SOAP包中出现的字段以property方式出现

AuthHeader = class(TSOAPHeader)
private
FAccNumber: Integer;
FTimeStamp: TXSDateTime;
public
destructor Destroy; override; //用于释放FTimeStamp,别无它用
published
property AccNumber: Integer read FAccNumber write FAccNumber;
property TimeStamp: TXSDateTime read FTimeStamp write FTimeStamp;
end;

2.在initialization中注册

InvRegistry.RegisterHeaderClass(TypeInfo(IBankAccount), AuthHeader, 'AuthHeader', 'urn:BankAccountIntf');
RemClassRegistry.RegisterXSClass(AuthHeader, 'urn:BankAccountIntf', 'AuthHeader');

3.使用:

var
H: AuthHeader;
svc: IBankAccount;
begin
svc := HTTPRIO1 as IBankAccount;

H := AuthHeader.Create;
try
H.AccNumber := FAuthKey;
H.TimeStamp := DateTimeToXSDateTime(FTimeStamp, True);
if UseHeader then
(svc as ISOAPHeaders).send(H);
svc.some_method(...)
finally
H.Free;
end


2. 我的要求和问题
对于我的程序,服务器要求的Header是这样


BigLuo
111


与上面的不同是Header下直接是两个元素,没有一个NS1:AuthHeader的外包层

仔细查看了一下Delphi的帮助,在Defining and using SOAP headers一节淘到如下一段

Handling scalar-type headers

Some Web Services define and use headers that are simple types (such as an integer or string) rather than a complex structure that corresponds to a remotable type. However, Delphi's support for SOAP headers requires that you use a TSOAPHeader descendant to represent header types. You can define header classes for simple types by treating the TSOAPHeader class as a holder class. That is, the TSOAPHeader descendant has a single published property, which is the type of the actual header. To signal that the SOAP representation does not need to include a node for the TSOAPHeader descendant, call the remotable type registry's RegisterSerializeOptions method (after registering the header type) and give your header type an option of xoSimpleTypeWrapper.


从最后一句看,我只要这样定义:

HdrUsername = class(TSOAPHeader)
private
FUsername: String;
published
property Username: String read FUsername write FUsername;
end;

然后按如下方式注册

InvRegistry.RegisterHeaderClass(TypeInfo(ezMsgServer), HdrUsername, 'Username', ');
RemClassRegistry.RegisterSerializeOptions(TypeInfo(HdrUsername), [xoSimpleTypeWrapper]);

(Password一项也类似处理)
应该就可以了。

但运行一下发现文档里面说的根本就不对,而是这样:



y19451


mypass



看样子xoSimpleTypeWrapper根本没有任何作用(不加那一句也是这个结果)

3. 问题的解决


在帮助文件里面来回折腾了半天,看到RegisterSerializeOptions的帮助里提到这样一个选项

xoHolderClass
The remotable object corresponds to a "holder" class. That is, the SOAP representation does not include a node for the class itself, just for its members. This is used when a type that would otherwise not require a remotable class uses a feature only available on remotable classes (such as attributes).

这个选项倒好像跟我的需求比较接近哦,试试!
结果又是失望。“希望,失望,希望,失望”,麦兜抱怨到。

在google上搜索了半天没有发现什么有用的结果,在无望之余回来又来看Delphi提供的例子,注意到它的例子中将AuthHeader这个类注册了一下:
RemClassRegistry.RegisterXSClass(AuthHeader, 'urn:BankAccountIntf', 'AuthHeader');
对啊,这个类应该在Remote Class Registry里面注册,于是加上HdrUsername和HdrPassword的注册语句, 再试,搞定!

总结一下:
帮助里面说的应该是纯常量作为Header的情况,对于我这种......的情况,应该按如下方式处理:
1. 按上面所说,声明HdrUsername和HdrPassword
2. 在initialization时按如下方式注册

InvRegistry.RegisterHeaderClass(TypeInfo(ezMsgServer), HdrUsername, 'Username', ');
RemClassRegistry.RegisterXSClass(HdrUsername, ', 'Username', 'Username');
RemClassRegistry.RegisterSerializeOptions(TypeInfo(HdrUsername), [xoHolderClass]);

InvRegistry.RegisterHeaderClass(TypeInfo(ezMsgServer), HdrPassword, 'Password', ');
RemClassRegistry.RegisterXSClass(HdrPassword, ', 'Password', 'Password');
RemClassRegistry.RegisterSerializeOptions(HdrPassword, [xoHolderClass]);


其实这样也可以(而且简单一点):
1. 将Username和Password声明在一个Header内
以下内容为程序代码:

TezMsgHdr = class(TSOAPHeader)
private
FUsername: String;
FPassword: String;
published
property Username: String read FUsername write FUsername;
property Password: String read FPassword write FPassword;
end;

2.将TMsgHdr注册:

InvRegistry.RegisterHeaderClass(TypeInfo(ezMsgServer), TezMsgHdr, 'Username', ', hmtRequest);
RemClassRegistry.RegisterXSInfo(TypeInfo(TezMsgHdr), ', 'Username', 'Username');
RemClassRegistry.RegisterSerializeOptions(TypeInfo(TezMsgHdr), [xoSimpleTypeWrapper, xoHolderClass]);

总的来说,还是看E文水平不够啊

4. 其他

细心的话,可以注意到后面一种方法里面多了一个xoSimpleTypeWrapper选项。其实对于后一种方法的复杂类TezMsgHdr, 这个选项是无效的,但对于前一种,就有些不同了(正如其名称所表明的那样,只有真正是SimpleType才有作用):

a. 如果只对HdrUsername加xoSimpleTypeWrapper选项:

y19451Password

可以注意到Username元素不见了,只能见到其值y19451赤裸地出现,而Password一项正常

b.如果只对HdrPassword加xoSimpleTypeWrapper选项:
运行时会出现"Element does not contain a single text node"这样的错误。我估计SOAP Header如下,Password的出现导致了这不是一个合法的XML

y19451Password


c.如果两者都加xoSimpleTypeWrapper选项,结果会是怎样呢?

Password

居然Username都不见了

2004年11月6日星期六

Fw: Scripting your Delphi Application

"In this paper I'll show you how to use the Microsoft ActiveScripting technologies to achieve everything we've just mentioned. While there is more to these technologies than can be covered by a single paper, by the end of this paper you'll know more than enough to start planning how you can use this technology in your application."

Full story: http://www.delphidevelopers.com/learnbooks/Scripting_your_Delphi_Application.htm
PDF created by pdfFactory: Scripting Your Delphi Applications.pdf
AXS_FAQ: Microsoft Active Scripting Frequently Asked Questions