星期四, 九月 13, 2007

innosetup对bde打包安装

一个朋友拿来一套软件,让我帮着做一个安装程序,这套软件是用Delphi开发的,其中用到了BDE,因此要求把BDE也一起打包安装。

我没用过BDE,更加不熟悉BDE的组成,刚开始不知道如何下手。由于我习惯使用InnoSetup来制作安装程序,便想到在InnoSetup的网站上也许有相关的介绍。于是登录InnoSetup的网站,在FAQ中找到了解决办法,现总结一下:

一、首先,在InnoSetup的网站上下载BdeInst.cab、MiniReg.exe、AddAlias.exe三个程序,其中BdeInst.cab就是BDE的安装包,其中只包含BdeInst.dll一个文件,有3兆多,将它提取出来。

二、将BdeInst.dll、MiniReg.exe、AddAlias.exe与要安装的应用程序放在一起。

三、在制作好的InnoSetup脚本中的相关节中加入以下内容:

[Files]
Source: "BdeInst.dll"; DestDir: "{tmp}"
Source: "MiniReg.exe"; DestDir: "{tmp}"
Source: "AddAlias.exe"; DestDir: "{tmp}"

[Run]
Filename: "{tmp}\MiniReg.exe"; Parameters: """{tmp}\BdeInst.dll"""
Filename: "{tmp}\AddAlias.exe"; Parameters: """Alias SubDir Driver"""

经过这样的改动,制作出来的Setup.exe就可以将应用程序连同BDE一块安装了。

之所以要用到MiniReg.exe和AddAlias.exe,是因为BdeInst.dll其实是一个COM组件,拷贝到用户机器上以后还需要注册一下才能用,MiniReg.exe就是做这个工作的,它的功能类似RegSvr32(不明白为什么不直接使用RegSvr32), MiniReg.exe是用Delphi编写的,源程序很短,顺便列在下面:

// FileName: MiniReg.dpr
program MiniReg;
{
  MiniReg v1.0 by Jordan Russell

  Note: For Delphi 3+, you'll need to change "OLE2" below to "ActiveX".
}
uses
  Windows, OLE2; // ActiveX

{x$R *.RES}

procedure RegisterServer(const Filename: String);
var
  LibHandle: THandle;
  RegisterServerProc: function: HRESULT; stdcall;
begin
  LibHandle := LoadLibrary(PChar(Filename));
  if LibHandle <> 0 then
  try
    @RegisterServerProc := GetProcAddress(LibHandle, 'DllRegisterServer');
    if Assigned(@RegisterServerProc) then
      RegisterServerProc;
  finally
    FreeLibrary(LibHandle);
  end;
end;

begin
  if ParamCount <> 1 then
    Exit;
  CoInitialize(nil);
  try
    RegisterServer(ParamStr(1));
  finally
    CoUninitialize;
  end;
end.

AddAlias的作用是向BDE注册一个别名,指向要连接的数据库(类似ODBC的数据源),它运行时需要三个命令行参数,分别是:别名、子目录名、驱动名。AddAlias也是用Delphi写的,源代码如下:

// FileName: AddAlias.dpr
program AddAlias;
{
  program adds a alias to the BDE configuration file

  parameters:
    0: programname + path (standard parameter of OS)
    1: Name of alias
       if begins with '-' then delete first if exist
                         else do nothing if exist
    2: path to data directory
    3: BDE driver name

  Bugfix: Savierhs Lopez Arteaga 3.1.2001
          AddAlias didn't delete alias with beginning '-'
}

uses
  Windows, SysUtils, BDE;

var
  GAlias:    string  = 'New';
  GDriver:   string = szPARADOX;
  GAliasDir: string;
  FParams:   string;
  FDrvName:  string;
  FDelete:   boolean;
  i:         integer;

function StrToOem(const AnsiStr: string): string;
begin
  SetLength(Result, Length(AnsiStr));
  if Length(Result) > 0 then
    CharToOem(PChar(AnsiStr), PChar(Result));
end;

begin
  for i := 1 to ParamCount do
  begin
    case i of
      1: GAlias    := ParamStr(1);
      2: GAliasDir := ParamStr(2);
      3: GDriver   := ParamStr(3);
    end;
  end;

  //default alias
  if GAliasDir = '' then GAliasDir := ExtractFilePath(ParamStr(0))+'Data';

  //should delete alias first? separate alias name
  if GAlias[1] = '-' then
  begin
    FDelete := True;
    //GAlias := Copy(GAlias, 1, Length(GAlias)); Bug
    Delete(GAlias, 1, 1);  //Fix by Savierhs Lopez Artega
  end else FDelete := False;

  FDrvName := GDriver;
  //set Parameters, the driver and server name
  if (CompareText(GDriver, szCFGDBSTANDARD) = 0) or
     (CompareText(GDriver, szPARADOX) = 0)       or
     (CompareText(GDriver, szDBASE) = 0)         or
     (CompareText(GDriver, szFOXPRO) = 0)        or
     (CompareText(GDriver, szASCII) = 0)         then
  begin
    if (CompareText(GDriver, szCFGDBSTANDARD) = 0) then FDrvName := szPARADOX;

    //set parameters for the new alias
    FParams := Format('%s:"%s"',  [szCFGDBPATH, GAliasDir]) +
               Format(';%s:"%s"', [szCFGDBDEFAULTDRIVER, GDriver]) +
               Format(';%s:"%s"', [szCFGDBENABLEBCD, szCFGFALSE]);
  end else begin
    if (CompareText(GDriver, 'INTRBASE') = 0)
    then FParams := Format('%s:"%s"',  [szSERVERNAME, GAliasDir])
    else FParams := Format('%s:"%s"',  [szDATABASENAME, GAliasDir]);

    //add other Parameters here !!!!!!!!!!!!!!!!!
  end;

  DbiInit(nil);
  try
    if FDelete then
      try
        DbiDeleteAlias(nil, PChar(GAlias));
      except
      end;

    try
      DbiAddAlias(nil, PChar(StrToOem(GAlias)),
                       PChar(StrToOem(FDrvName)),
                       PChar(FParams), True);
      DbiCfgSave(nil, nil, True);
    except
    end;

  finally
    DbiExit();
  end;

end.

杂感:

一、InnoSetup这个安装制作工具非常好用,它短小精致、公开源码、无需注册可免费使用,能满足绝大多数需要,我经常向人建议抛弃InstallShield这个庞然大物,使用InnoSetup。

二、原来的印象中,BDE也是个庞然大物,有10兆之巨,但这次的安装包只有3兆,很出乎意料。


星期三, 七月 11, 2007

信息周刊:宝洁公司拥抱Web2.0宝洁|web2.0| - 使用 Google 工具栏进行发送

信息周刊:宝洁公司拥抱Web2.0宝洁|web2.0|

富礼(A.G. Lafley)自2000年担任宝洁公司(P&G,下称宝洁)的首席执行官(CEO)后,便不遗余力地推动公司员工改善彼此间以及与合作伙伴之间的合作方式,以更迅捷地开发出新产品。既得到了CEO的全力支持,现在又有无数的Web 2.0工具可供选择,乔・舒尔勒(Joe Schueller)还有可能面临哪些问题呢?他肩负着在宝洁公司部署、应用新协作工具的重任。

  电子邮件算得上一个,舒尔勒将之形容为阻碍宝洁员工应用交互式更强、也更有效的工具的最大障碍。"作为邮件的发送者,我控制着身边每个人的日程安排,"舒尔勒表示。电子邮件的发送者可以决定,谁能阅读某个消息;而"回复所有人"按钮所确保的,只是在周围所有参与者都完全丧失兴趣之后才对之发出提示。相形之下,网络日志(Blog)所寻求的则是那些兴趣最为浓厚的人的反馈意见。同时,舒尔勒还得面对来自某些员工的不满之声,这些人将处理电子邮件以外的任何事都视为加重了其工作负担。"我们接连不断地听到这样的抱怨:即往内部网上发帖是额外工作。"他补充道。

  在前不久于波士顿举行的Enterprise 2.0大会上,商业科技主管们已经结束了新概念的探讨,开始寻求部署实用技术。"一年前,我曾会晤过一些入选《财富》杂志前25名CEO的人,那时他们对Wiki一无所知。"现在,他们开始问我如何将Web 2.0工具与其现有内容管理系统集成起来。开源系统集成商SpikeSource公司CEO金・波莱斯(Kim Polese)介绍说。SpikeSource销售的Web 2.0工具包括Movable Type Blog和Socialtext Wiki。

  宝洁根据自己的项目范围及其从初创公司和知名厂商选购Web 2.0工具的途径,就如何发展Enterprise 2.0进行了研究。2005年,宝洁制定了以微软公司(Microsoft,下称微软)产品为核心的部署计划,该计划包括采用即时通讯、统一通信、以及实时通讯Live Communications Server等;网络会议采用Live Meeting;内容管理和协作通过SharePoint实现。现在,约有8万名宝洁员工使用微软IM系统,另外2万名已经迁移至Outlook。宝洁还有几个采用微软SharePoint技术的网站,并将于8月开始大规模部署该技术。

  去年,在首席信息官(CIO)菲力波・帕瑟里尼(Filippo Passerini)的支持下,舒尔勒出任宝洁Enterprise 2.0计划的负责人,该计划旨在帮助宝洁员工应用更为多样化的工具集。目前,宝洁已部署了Movable Type网络日志软件,并且员工们已开始应用该软件创建了几百个网络日志;其中包括,公司设计副总裁由于受到了通用汽车公司(GM)设计大师鲍勃・鲁兹(Bob Lutz)的网络日志启发,而建立的网络日志;此外,公共关系部门也围绕着如何与外界讨论公司问题而创建的网络日志;当然,还有舒尔勒自己的网络日志,读者多为IT人员。未来几个月内,宝洁还会发布社会网络,以使员工更便捷地找到具有某种专业特长的人。

  即使微软和国际商业机器公司(IBM)都在不断扩充各自产品的Web 2.0协作特性,比如莲花(Lotus)的Connections和微软的SharePoint Server 2007等社会网络工具都支持网络日志、Wiki、以及日历共享,但许多公司仍然下结论说:仅靠单一平台是远远不够的。

  "如果做什么事都用微软的东西,这对你的系统模块性和灵活性意味着什么呢?"舒尔勒表示,他的头衔是宝洁公司全球商业服务部门的创新经理。"我不会全部选用微软的产品,老是那些大厂商。"而且,IT部门还需要学会如何集成员工自行引入的工具,他补充道。

  超越谷歌和微软

  在企业搜索领域,宝洁所瞄准的也不仅仅是其主要的供货商。该公司现在用的是谷歌公司(Google)的搜索产品,但是舒尔勒发现,网页等级背后隐含的概念,即基于链接的相关性,对企业而言并非始终都能说明问题,这是由于企业内部的信息并非总是建有链接。此外,他也担心,谷歌搜索过于依赖关键词,而对于那些描述得含混不清的想法,如果没有准确捕捉其中的一两个单词,那很可能就会无功而返。

  因此,宝洁开始测试Connectbeam公司的产品,该产品可与谷歌搜索一同使用。企业员工可使用Connectbeam产品,共享书签、标签文章、页面、以及带描述性词汇的文档。如果某个员工用谷歌工具搜索某些内容,Connectbeam系统会将结果――相关的标签和书签,与谷歌搜索结果一同返回。

  同时,宝洁也开始修复其基于BEA系统的门户网站,添加新闻和商业信息类RSS种子,以帮助用户对网站进行个性化。该公司希望,随着时间的推移,他们可据员工的岗位和其经常访问的网站,为之推荐所需的种子。

  但是,如果这些工具被视为额外工作的话,舒尔勒怎么才能让所有人参与进来,都使用这些工具呢?

  思路之一,是以相对宽松的视角看待今天人们做事的方法,进而提供能助其实现此过程的工具。舒尔勒举了一个例子,宝洁的一名主管,每当其出差去会晤某个区域经理时,都会将所获取信息做到PowerPoint文件中,然后再将这些文件通过电子邮件发给其他人。与此不同,IT部门在微软SharePoint中建立了一个页面,主管可于此张贴其演示文档,这些文档会被存成远比电子信箱更为高效的数据格式。

  CIO帕瑟里尼(Passerini)对于如何评估Web 2.0工具对于宝洁的重要性所持的战略一向是,"先让我们试试再说,"让IT团队先拿这些新技术试验一下,并且每个Web 2.0产品区域由不同的IT经理管理,舒尔勒介绍道。而IT团队亦将此视为改变自身地位的一个良机,因为在宝洁,地位举足轻重的是是品牌经理而非技术专家。"IT部门,特别是在一家生产肥皂的公司,只是后台支持的角色,"舒尔勒不无调侃地说道。他接着表示,"现在,我们大显身手的时机到了。"

  其他公司的IT部门也将这一轮Enterprise 2.0热潮视为自己出人头地、扬眉吐气的大好机会。出席Enterprise 2.0大会的上百家组织中,赫然在内的就有美国银行(Bank of America)、中央情报局(CIA)、联邦快递公司(FedEx)、摩根士丹利银行(Morgan Stanley)、以及辉瑞制药公司(Pfizer)等知名组织。

  摩托罗拉公司(Motorola)是部署Web 2.0技术的先行者之一。迄今,该公司已用Scuttle软件建立了4,400个网络日志,4,200个Wiki页面,并且有2,600人积极对内容进行分类,而访问该系统的人数更多。摩托罗拉发起了一项名为Intranet 2.0的运动,Web 2.0工具大多被用于研究和信息共享,而销售人员则利用这些工具,针对每个客户都开发出一套全新的销售办法,他们还可重新利用发表在Wiki上的任何销售方法。使用Visible Path公司的社会网络软件,或者通过查看Wiki上的作者页,摩托罗拉员工还能轻而易举地发现具有某些特长的人。"这种办法,确实能让人们以新的视角看问题,如他们会看到聪明人和与自己相似的人是如何处理问题的。"摩托罗拉公司负责Enterprise 2.0技术的副总裁托比・莱德肖(Toby Redshaw)指出。依此思路,该公司开始围绕某些特定的问题和产品建立知识中心。

  这也是舒尔勒的最终目标,员工及合作伙伴可以在企业内部网上搜索信息,创建档案,对文档进行分类,并共享书签,所有这些都会提升网站内容的价值。无论你叫它作社会软件还是用户创建的内容,其中的风险在于如果人们发现这些Web 2.0工具不那么好用,他们便不会为丰富内容贡献自己的一份力量,而这恰是构建整个完美周期所不可或缺的。IT团队需要把握住这个关键机会,向人们证明花时间在Web 2.0上是值得的。就像一名IT主管在Enterprise 2.0大会上所阐述的那样,"如果他们接受Web 2.0,他们就能将之用起来。"

星期一, 六月 18, 2007

SQL2005报表参数大于2K问题的终极解决方案 - 技术频道 | IT168 - 使用 Google 工具栏进行发送

SQL2005报表参数大于2K问题的终极解决方案 - 技术频道 | IT168

SQL2005报表参数大于2K问题的终极解决方案

作者:AnyJack  2007-06-15

【IT168 技术文档】

    当通过表单提交信息给报表服务时,当参数值大于2K时,这时如果加入显示工具条参数时,IE会返回该页无法显示这样的错误信息,而如果不加显示工具条参数时,结果正常,但是就是没有工具条.

    问题反馈:

    据微软的专家说这是SQL2000/SQL2005的BUG,真是奇怪了,SQL2005研究了5年才发布,居然这一BUG依然保留,可以想象这是多么大的一个技术难题。 

    解决思路:

    据微软提供的建议,建议编写一个自定义的报表工具条。

    解决办法: 

    首先确定报表工具条的作用,它的作用是用于翻页和导出报表数据到其它类型的文档。可以看出,技术难点在于翻页,也就是当前报表总页数的获取。那么如何才能获得带指定参数的指定报表的页数呢?微软的建议是通过报表服务的WEB服务接口来获取,当服务器上装了报表服务时,也就相应的存在了报表服务的WEB服务接口,一般访问地址如下: http://****/reportserver/reportservice.asmx

    通过这一公开的WEB服务,调用其相应功能可以实现报表服务的N多的功能,获取页数只是其中微不足道的功能之一,实现代码如下:

public int GetNumber()
... { string deviceinfo =@"<DeviceInfo><Toolbar>False</Toolbar></DeviceInfo>" ; string[] parameters =_parameter.Split('&' ); int parameterNumber =parameters.Length;
RS.ParameterValue[] param
=new ReportNumber.RS.ParameterValue[parameterNumber]; for( int i=0;i<
parameterNumber;i++)
... { string[] p =parameters[i].Split('=' ); param[i]=new ParameterValue(); param[i].Name=p[ 0];
param[i].Value
= p[ 1];
}
RS.ReportingService rs=new ReportNumber.RS.ReportingService();
rs.Url
= this ._url+@"/ReportService.asmx" ; /**/ /*

    注意,如果你的报表服务器和应用服务器不处于同一机器,那么你必须提供访问报表服务器的凭证,如下面的凭证是通过使用Negotiate 验证来传送用户名、密码。当然,如果2个服务器在同一台机器,那就非常简单了,直接使用本地凭证验证即可

*/ CredentialCache cache = new CredentialCache();
cache.Add(
new Uri(rs.Url), "Negotiate", new NetworkCredential("administrator", "crserver", ""));
rs.Credentials
= cache;
/**/ /* rs.Credentials=System.Net.CredentialCache.DefaultCredentials;
*/
DataSourceCredentials[] credentials=null ;
string showHideToggle =null;
string encoding;
string mimeType;
Warning[] warnings
=null ; ParameterValue[] reportHistoryParameters=null ;
string [] streamIDs =null;
SessionHeader sh
=new SessionHeader(); rs.SessionHeaderValue=sh;
string historyID =null;
byte[] result =rs.Render(ReportName,"HTML4.0" ,historyID,deviceinfo,param,credentials,showHideToggle,out encoding,out mimeType,out reportHistoryParameters,out warnings,
out streamIDs);
string s =System.Text.UTF8Encoding.UTF8.GetString(result,0,result.Length -1);
string r =@"<hr/>";
Regex regex
=new Regex(r); MatchCollection mc=regex.Matches(s);
return mc.Count +1;
}