??xml version="1.0" encoding="utf-8" standalone="yes"?>国产亚洲av片在线观看播放,日本中文一区二区三区亚洲 ,亚洲国产美女在线观看 http://m.tkk7.com/konhon/category/3015.html忘掉過去Q展望未來。找回自我,越自我? <br> <b>逃避不一定躲的过, 面对不一定最难过, 孤单不一定不快乐, 得到不一定能长久, 失去不一定不再拥? 可能因ؓ某个理由而伤心难q? 但我却能找个理由让自己快?</b><br><p> <!-- Search Google --> <left> <form method="get" action="http://www.google.com/custom" target="google_window"> <table> <tr><td nowrap="nowrap" valign="top" align="left" height="32"> <a > <img src="http://www.google.com/logos/Logo_25wht.gif" border="0" alt="Google" align="middle"></img></a> <input type="text" name="q" size="31" maxlength="255" value=""></input> <input type="submit" name="sa" value="搜烦"></input> <input type="hidden" name="client" value="pub-5408663347953425"></input> <input type="hidden" name="forid" value="1"></input> <input type="hidden" name="ie" value="UTF-8"></input> <input type="hidden" name="oe" value="UTF-8"></input> <input type="hidden" name="cof" value="GALT:#008000;GL:1;DIV:#336699;VLC:663399;AH:center;BGC:FFFFFF;LBGC:336699;ALC:0000FF;LC:0000FF;T:000000;GFNT:0000FF;GIMP:0000FF;FORID:1;"></input> <input type="hidden" name="hl" value="zh-CN"></input> </td></tr></table> </form> </left> <!-- Search Google --> zh-cnThu, 29 Mar 2007 12:21:27 GMTThu, 29 Mar 2007 12:21:27 GMT60TClientDataSethttp://m.tkk7.com/konhon/archive/2007/03/29/107306.htmlkonhon 优华konhon 优华Thu, 29 Mar 2007 10:57:00 GMThttp://m.tkk7.com/konhon/archive/2007/03/29/107306.htmlhttp://m.tkk7.com/konhon/comments/107306.htmlhttp://m.tkk7.com/konhon/archive/2007/03/29/107306.html#Feedback0http://m.tkk7.com/konhon/comments/commentRss/107306.htmlhttp://m.tkk7.com/konhon/services/trackbacks/107306.html http://www.openitpower.com/wenzhang/97/10846_1.html

  与TTable、TQuery一PTClientDataSet也是从TDataSetl承下来的,它通常用于多层体系l构的客L。TClientDataSet最大的特点是它不依赖于BDE(Borland Database Engine)Q但它需要一个动态链接库的支持,q个动态链接库叫DBCLIENT.DLL。在客户端,也不需要用TDatabase构gQ因为客Lq不直接q接数据库?br />  ׃TClientDataSet是从TDataSetl承下来的,所以,它支持诸如编辑、搜索、浏览、纠错、过滤等功能。由于TClientDataSet在内存中建立了数据的本地副本Q上q操作的执行速度很快。也正是׃TClientDataSetq不直接q接数据库,因此Q客L序必L供获取数据的机制。在Delphi 4中,TClientDataSet有三U途径获取数据Q?br />.从文件中存取数据?br />.从本地的另一个数据集中获取数据?br />.通过IProvider接口从远E数据库服务器获取数据?br />  在一个客L序中Q可以同时运用上qCU机制获取数据?
11.1 览和编辑数?/b>
  和其他数据集构g一P可以用标准的数据控g昄由TClientDataSet引入的数据集Q当Ӟq需要借助于TDataSource构g?br />  ׃TClientDataSet是从TDataSetl承下来的,所以,凡是其他数据集构件支持的功能QTClientDataSet构g也大致具备。不同的是,TClientDataSet能够在内存中建立数据的副本,因此QTClientDataSet比其他数据集构g增加了一些特D的功能?br />11.1.1 览数据
  可以用标准的数据控g昄由TClientDataSet引入的数据集。在q行期,可以调用诸如First、GotoKey、Last、Next和Prior{函数来览数据?br />  TClientDataSet也支持书{֊能,可以用书{来标记某条记录Q以后就可以方便地找到这条记录?br />  对于TTable、TQuery{数据集构g来说Q只能读RecNo属性来判断当前记录的序受对于TClientDataSet构g来说Q还可以写RecNo属性,使某一序号的记录成为当前记录?br />11.1.2 CanModify属?/b>
  TDataSet的CanModify属性用于判断数据集中的数据是否可以修改。CanModify属性本w是只读的,也就是说Q数据是否能够修改不取决于应用程序?br />  不过QTClientDataSet构g有其Ҏ性,因ؓTClientDataSet已经把数据在内存中徏立了副本Q因此,应用E序可以军_是否允许修改数据。如果不允许用户修改数据Q只要把ReadOnly属性设为TrueQ此ӞCanModify属性肯定返回False?br />  与其他数据集构g不同Q修改TClientDataSet构g的ReadOnly属性时Q不需要事先把Active属性设为True?br />11.1.3 取消修改
  TClientDataSet传输数据的基本单位称为数据包Q当前的数据包可以由Data属性来讉K。不q,用户Ҏ据的修改q不直接反映到Data属性中Q而是临时写到一个日志即Delta属性中Q这样做的好处是以后随时可以取消修改?br />  不过Q这里要说明一点,管用户的修改ƈ没有反映到DataQ当用户在数据控件中看到的却是最C改的数据。如果一条记录被反复修改了多ơ,用户看到的只是最新的数据Q但日志中却记蝲了多ơ?br />  要取消上一ơ的修改Q调用UndoLastChange函数。UndoLastChange需要传递一个布类型的参数叫FollowChangeQ如果FollowChange参数设ؓTrueQ光标就Ud被恢复的记录上,如果FollowChange参数设ؓFalseQ光标仍然在当前记录上?br />  ChangeCount属性返回日志中记蝲的修Ҏ数。如果一条记录被反复修改了多ơ,每调用一ơUndoLastChange能够逐取消上一ơ的修改?br />  UndoLastChange只能取消上一ơ的修改Q如果想一下子取消所有的修改Q首先要选择一个记录,然后调用RevertRecord。RevertRecord从日志中取消所有对当前记录的修攏V?br />  TClientDataSetq有一个SavePoint属性,它能把当前的~辑状态保存v来,以后随时可以q回当时的状态。例如,可以q样保存当前的状态:
  BeforeChanges := ClientDataSet1.SavePoint;
  以后Q可以这h恢复当时的状态:
  ClientDataSet1.SavePoint := BeforeChanges;
  应用E序可以保存多处状态,可以恢复其中一个状态,不过Q一旦某个状态被恢复Q在其之后的状态就无效?br />  如果要一下子取消日志中记载的所有修改,可以调用CancelUpdates函数。CancelUpdates把日志清空Q取消所有的修改?br />  如果LogChanges属性设为FalseQ用户对数据的修改就会直接反映到Data属性中?
11.1.4 合ƈ修改
  要把日志中记载的修改合ƈ到Data属性中Q有两种方式Q具体用哪一U方式,取决于应用程序获取数据的机制。不q,不管是哪U机Ӟ合ƈ后,日志自动被清I?br />  对于一个从文g中获取数据的E序来说Q只要调用MergeChangeLog函数Q就把日志中记蝲的修改合q到Data属性中。不用担心其他用户同时修改了数据?br />  对于一个从应用服务器获取数据的E序来说Q就不能调用MergeChangeLog来合q数据,而要调用ApplyUpdates函数QApplyUpdates会把日志中记载的修改传递给应用服务器,待应用服务器成功地把数据更新了数据库服务器后Q才会合q到Data属性中?br />11.1.5 U错
  TClientDataSet支持U错功能。一般情况下Q需要自己徏立纠错规则,以便对用戯入的数据q行U错?br />  此外Q如果获得了IProvider接口的话Q还可以从远E服务器引入U错规则?br />  有时候,客户端可能需要暂时禁止纠错,因ؓ客户端从应用服务器检索数据是分阶D进行的Q在所有的数据索完毕之前,有些U错规则很可能会报错?
要暂时禁止纠错,可以调用DisableConstraintsQ要重新允许U错Q可以调用EnableConstraints函数。DisableConstraints和EnableConstraints实际上都是作用于一个内部的计数?br />11.2 ??/b>
  使用索引有这么几个好处:
.在数据集中定位记录比较快?br />.能够在两个数据集之间建立Lookup或Master/Detail关系?br />.可以对记录排序?br />  在多层体pȝ构中Q当客户E序从应用服务器索数据时Q它同时获得了默认的索引。默认的索引叫DEFAULT_ORDERQ可以用这个烦引排序,但不能修Ҏ删除q个索引?br />  除了默认的烦引外QTClientDataSetq对日志中记载的记录自动建立了一个副索引叫CHANGEINDEX。与DEFAULT_ORDER一P不能修改或删除这个副索引?br />  另外Q还可以使用数据集中已徏立的其他索引Q或者自己徏立烦引?br />11.2.1 创徏一个新的烦?/b>
  要创Z个新的烦引,可以调用AddIndex。AddIndex需要传递若q个参数Q?br />  一是Name参数Q用于指定烦引名。在q行期切换烦引时需要用到烦引的名称?br />  二是Fields参数Q它是一个字W串Q用于指定烦引中的字D名Q彼此之间用分号隔开?br />  三是Options参数Q用于设|烦引的选项Q包含ixDescending元素表示按降序排列,包含ixCaseInsensitive元素表示大小写不敏感?br />  四是DescFields参数Q它也是一个字W串Q用于指定若q个字段名,q些字段按照降序排列?br />  五是CaseInsFields参数Q它的作用与DescFields参数cMQ包含在CaseInsFields参数中的字段对大小写不敏感?br />  六是GroupingLevel参数Q用于指定分l别,其g能超q烦引中的字D|?br />  下面的代码创Z一个烦引:
If Edit1.Text <> '' and ClientDataSet1.Fields.FindField(Edit1.Text) then
Begin
ClientDataSet1.AddIndex(Edit1.Text+'Index',Edit1.Text,  
  [ixCaseInsensitive],'','',0);
ClientDataSet1.IndexName := Edit1.Text + 'Index';
End;
Z避免创徏一个烦引,可以临时用IndexFieldNames属性来指定若干个字D,让数据集按这些字D|序?br />11.2.2 删除和切换烦?/b>
  要删除一个先前创建的索引Q可以调用DeleteIndexq指定要删除的烦引名U。注意:DEFAULT_ORDER和CHANGEINDEX不能删除?br />  如果建立了多个烦引,可以L选择其中的一个烦引,q就要用到IndexName属性?br />11.2.3 用烦引把数据分组
  选择了一个烦引后Q数据集自动按其中的字D进行排序。这P临近的记录往往在关键字D上含有相同的倹{例如,假设有一个表是这LQ?br />SalesRep Customer OrderNo Amount
1      1     5    100
1      1     2    50
1      2     3    200
1       2     6    75
2      1     1    10
2      3     4    200
  可以看出QSalesRep字段的值有重复的。对于SalesRep字段的gؓ1的来_Customer字段的g有重复的。这是_可以按SalesRep字段分组Q进而再按Customer字段分组。显Ӟq里的分l别是不同的,按SalesRep字段建立的分l属于第一U,按Customer字段建立的分l属于第二。实际上Q分l别取决于字段在烦引中的顺序?br />  TClientDataSet可以军_是否按照分组U别来显C录的倹{例如,也许想以下面q种形式昄数据Q?br />SalesRep Customer OrderNo Amount
1      1    5    100
           2    50
       2    3    200
           6    75
2      1    1    10
2      3    4    200
  要判断当前记录某一U的什么位|,可以调用GetGroupState函数。GetGroupState函数需要传递一个参敎ͼ用于指定分组U别?br />11.3 ???D?/b>
  与其他数据集一P也可以在TClientDataSet建立的数据集中增加计字Dc计字D늚值是Z同一个记录中的其他字D计出来的?br />  在其他数据集中,只要用户修改了数据或当前记录发生改变Q就会触发OnCalcFields事gQ换句话_计算字段的值就被计一ơ?br />  TClientDataSet引入了“内部计字D”的概念。与一般的计算字段不同的是Q内部计字D늚值将随其他字D늚g起存取,q样Q只有当用户修改了数据才会触发OnCalcFields事gQ如果仅仅改变了当前记录Q不会触发OnCalcFields事g。也是_内部计算字段的值需要重新计的Z大大减少?br />  在处理OnCalcFields事g的句柄中Q首先要判断State属性。如果State属性返回dsInternalCalcQ此旉要计内部计字D늚倹{如果State属性返回dsCalcFieldsQ此旉要计一般的计算字段的倹{?br />11.4 l???/b>
  TClientDataSet增加了统计的功能Q它可以Z分组自动计算d、^均、计数、最大、最倹{当用户~辑数据Ӟq些l计g自动跟着变化?br />11.4.1 指定l计方式
  要指定怎样q行l计Q就要用到Aggregates属性。这个属性是一个TAggregates对象Q它用于理一lTAggregate对象?br />  在设计期Q可以单击Aggregates属性边上的省略h钮打开如图11.1所C?br />的编辑器?br />  ?1.1 理一lTAggregate对象
  单击按钮可以增加一个TAggregate对象Q单L钮可以删减一个TAggregate对象Q单L钮可以把TAggregate对象前移Q单L钮可以把TAggregate对象后移?br />  可以用字D늼辑器专门创徏一个用于表辄计值的字段Q该字段的类型必L“Aggregate”。Delphi 4会自动创Z个TAggregate对象Qƈ加到Aggregates属性中。选择一个TAggregate对象QObject Inpector显C对象的属性?br />  其中QExpression属性用于指定统计表辑ּQ例如:
Sum(Field1)
  也可以是比较复杂的表辑ּQ?br />Sum(Qty * Price) - Sum(AmountPaid)
  在表辑ּ中,可以使用下列l计q算W:
.Sum计算一l数据的d?br />.Avg计算一l数据的q_倹{?br />.Count计算一l数据中的非I值的个数?br />.Min计算一l数据的最倹{?br />.Max计算一l数据的最大倹{?br />  除了上述几个l计q算W外Q还可以使用qo条g中所能用的q算W,但不能嵌套。在一个表辑ּ中,可以混合出现几个l计值或帔RQ但不能混合出现l计值和字段?br />  Sum(Qty * Price){合法}
  Max(Field1) - Max(Field2){合法}
  Avg(DiscountRate) * 100{合法}
  Min(Sum(Field1)){非法Q不能嵌套}
  Count(Field1) - Field2{非法Q统计值和字段不能混合出现在一个表辑ּ中}
11.4.2 指定分组
  默认情况下,l计值是Z数据集中所有的记录计算出来的。不q,也可以针对一部分记录计算l计|q就需要事先徏立分l?br />  前面在介l烦引时已经提到分组的概c可以通过IndexName属性和GroupingLevel属性来选择使用哪个索引以及最大的分组U别?br />  例如Q假设有一个表是这LQ?br />SalesRep Customer OrderNo Amount
1      1     5    100
1      1     2    50
1      2     3    200
1       2     6    75
2      1     1    10
2      3     4    200
  如果要按SalesRep字段分组Qƈ且指定其中的W一U,E序代码应当q样写:
Agg.Expression := 'Sum(Amount)';
Agg.IndexName := 'SalesCust';
Agg.GroupingLevel := 1;
Agg.AggregateName := 'Total for Rep';
11.4.3 怎样获取l计?/b>
  要获取统计|可以调用TAggregate对象的Value函数。如果统计值是Z数据集中所有的记录计算出来的,随时可以调用Value函数。如果统计值是Z分组计算出来的,必须保证当前记录正好位于该分l内。因此,在调用Value之前Q最好先调用GetGroupState函数看看当前记录是否位于该分l内?br />  要在数据控g中显C统计|必须事先在字D늼辑器中创Z个永久字D对象,该字D늚cd必须是Aggregate?br />11.5 ???/b>
  通过Data属性可以访问客L序从应用服务器检索到的数据。程序示例如下:
Procedure TForm1.Button1Click(Sender: TObject);
Begin
ClientDataSet1.Data := ClientDataSet1.Provider.DataRequest(FilterEdit.Text);
End;
11.5.1 直接对Data属性赋?/b>
  前面讲过Q客L序既可以通过IProvider接口获取数据Q也可以从另一个数据集获取数据Q后者就是通过Data属性赋值的。程序示例如下:
  ClientDataSet1.Data := ClientDataSet2.Data;
  一旦Data被赋|可以用标准的数据控件显C些数据?br />  注意Q当从另一个数据集获取数据Ӟ另一个数据集的日志也被复制q来Q但不包括原来的范围和过滤条件?br />  如果要从另一个基于BDE的数据集中获取数据,可以通过数据集构件的Provider属性,E序CZ如下Q?br />  ClientDataSet1.Data := Table1.Provider.Data;
  如果要从一个自定义的数据集获取数据Q首先要创徏一个时的TProvider构gQ然后设|其DataSet属性指定这个自定义的数据集。程序示例如下:
TempProvider := TDataSetProvider.Create(Form1);
TempProvider.DataSet := SourceDataSet;
ClientDataSet1.Data := TempProvider.Data;
TempProvider.Free;
11.5.2 在数据包中加入自定义的信?/b>
  可以把自定义的信息加到数据包中。当把数据保存到文g或流中时Q这些自定义的信息也保存到文g或流中。如果把数据包直接赋值给另一个数据集的话Q这些自定义的信息也被复制?br />  要把自定义的信息加到数据包中Q可以调用SetOptionalParam函数。要从数据包中检索自定义的信息,可以调用GetOptionalParam。程序示例如下:
Procedure TAppServer.Provider1UpdateData(Sender: TObject; DataSet: TClientDataSet);
var
WhenProvided: TDateTime;
Begin
WhenProvided := DataSet.GetOptionalParam('TimeProvided');
...
End;
11.5.3 克隆另一个数据集
  调用TClientDataSet的CloneCursor函数可以获得一个数据集的完全相同的副本。它与直接通过Data属性赋值是有区别的?br />  区别之一Q数据在两个数据集之间是׃n的,修改其中一个将同时修改另一个?br />  区别之二Q除了数据外QCloneCursor函数q复制了一些属性和事gQ这取决于Reset和KeepSettings参数怎样讄?br />   CloneCursor函数需要传递三个参敎ͼ其中QSource参数指定源数据集QReset参数和KeepSettings参数用于讄除了数据外是否还要复制下列属性和事gQFilter、Filtered、FilterOptions、OnFilterRecord、IndexName、MasterSource、MasterFields、ReadOnly、RemoteServer、ProviderName、Provider?br />  如果Reset和KeepSettings参数都设为FalseQ源数据集的上述属性和事g都将被复制给目标数据集。如果Reset参数设ؓTrueQ目标数据集的上q属性和事g都将被清I。如果Reset参数设ؓFalseQ而KeepSettings参数设ؓTrueQ目标数据集的上q属性和事g不变Q不q,必须保证q些属性和事g与克隆后的数据相宏V?br />11.6 与应用服务器通讯
  在多层体pȝ构中Q客L序通过IProvider接口与应用服务器交换数据。这一章介l怎样在客L获得IProvider接口、怎样向应用服务器传递参数、怎样向应用服务器h数据、怎样把用户对数据的修改写到数据库中?br />11.6.1 怎样在客L获得IProvider接口
  在单层应用程序以及工作在“公文包”模式下的多层应用程序中Q不需要用到IProvider接口。而在多层体系l构中,客户E序要与应用服务器交换数据,首先必须获得IProvider接口Q这p用到RemoteServer属性和ProviderName属性?br />  RemoteServer属性用于指定客L的MIDASq接构g。MIDASq接构g又称Data BrokerQ用于徏立和l护与应用服务器的连接?br />  在设计期Q正设|了RemoteServer属性后Q就可以在对象观察器中ؓProviderName属性选择一个|实际上就是选择应用服务器上的一个TProvider构g?br />11.6.2 向应用服务器传递参?/b>
  客户E序可以向应用服务器传递参敎ͼq些参数实际上是传递给应用服务器上的TQuery构g或TStoredProc构g。既可以在设计期也可以在q行期设|参数?br />  在设计期Q可以单击Params属性边上的省略h钮,打开一个如?1.2所C的~辑器?br />  ?1.2 讄参数
  单击按钮可以增加一个参敎ͼ单击按钮可以删减一个参敎ͼ单击按钮可以把一个参数前U,单击按钮可以把一个参数后UR?br />  选择一个参敎ͼ对象观察器将昄该参?TParam对象)的属性?br />  在运行期可以调用TParams的CreateParam函数来创Z个参数。例如,下面的代码创Z一个参数叫CustNoQ它的用类型是ptInputQ数据类型是ftIntegerQ它的D?05?br />With ClientDataSet1.Params.CreateParam(ftInteger, 'CustNo', ptInput) Do
AsInteger := 605;
  讄好参C后,如果TClientDataset的Active属性是FalseQ只要把Active属性设为TrueQ这些参数将被自动传递给应用服务器。如果Active属性已lؓTrueQ就要调用SendParams函数把参C递给应用服务器?br />  注意Q传递给应用服务器的参数必须与TQuery构g或TStoredProc构g的参数匹配,包括名称、数据类型和参数cd?br />11.6.3 怎样向应用服务器h数据
  TClientDataSet提供了两个属性和三个ҎQ用于怎样向应用服务器h数据Q?br />  一是FetchOnDemand属性。如果这个属性设为TrueQTClientDataSet会根据需要自动检索附加的数据包,例如BLOB字段的值或者嵌套表的内宏V如果这个属性设为FalseQ程序需要显式地调用GetNextPacket才能获得q些附加的数据包?br />  二是PacketRecords属性,用于讄一个数据包中最多可容纳的记录数Q设?1表示一个数据包可以容纳数据集的所有记录?br />  三是GetNextPacket函数Q用于向应用服务器检索下一个数据包Qƈ把检索到的数据包d到前一ơ检索到的数据包的后面。这个函数返回实际检索到的记录数?br />  四是FetchBlobsq程Q用于从应用服务器检索BLOB字段的倹{如果FetchOnDemand属性设为TrueQ就没必要调用FetchBlobs函数?br />  五是FetchDetailsq程Q用于检索嵌套表中的数据。如果FetchOnDemand属性设为TrueQ就没必要调用FetchDetails函数?br />11.6.4 更新数据?/b>
  在多层体pȝ构中Q用户在客户端修改了数据后,需要把最新的数据写到数据库中Q这p调用TClientDataSet的ApplyUpdates函数?br />  ApplyUpdates只需要传递一个参数叫MaxErrorsQ用于指定一个整敎ͼ当遇到无法更新的记录过q个数时Q此ơ更新就中止。如果MaxErrors参数设ؓ0Q表C只要遇C个错误更新就中止Q客L的日志保持不变。如果MaxErrors参数设ؓ-1Q当应用服务器发现有错误的记录,尝试更C一个记录,{所有的记录都尝试过以后才返回?br />  ApplyUpdates会自动调用Reconcile函数Q进而调用应用服务器上的TProvider构g的ApplyUpdates函数L新远E的数据库服务器。没有被DBMS服务器认可的记录通过Reconcileq回l客LQ此时将在客L触发OnReconcileError事g让您更正错误。最后,ApplyUpdates函数q回仍然没有被认可的记录数?br />11.7 在文件中存取数据
  要从文g中读取数据,可以调用LoadFromFile函数。LoadFromFile函数需要传递一个参敎ͼ用于指定文g名。文件名应包含完整的路径。如果客L序L从一个固定的文g中读取数据,可以讄FileName属性指定一个文件名Q以后,当TClientDataSet引入的数据集打开Ӟp动从q个文g中读取数据,不需要调用LoadFromFile?br />  要从中d数据Q可以调用LoadFromStream。LoadFromStream需要传递一个参敎ͼ用于指定一个流对象?br />  注意QLoadFromFile(LoadFromStream)只能从先前用SaveToFile(SaveToStream)保存的文件中d数据?br />  要把数据保存到文件中Q可以调用SaveToFile函数。SaveToFile需要传递一个参敎ͼ用于指定文g名。如果指定的文g已存在,文g中的数据被覆盖。如果客L序L把数据保存到一个固定的文g中,可以讄FileName属性指定一个文件名Q当TClientDataSet引入的数据集关闭Ӟp动把数据保存到这个文件中Q不需要调用SaveToFile?br />  要把数据保存到流中,可以调用SaveToStream。SaveToStream需要传递一个参敎ͼ指定一个流对象?br />  注意Q当把数据保存到文g或流中时Q日志中记蝲的修改仍然保留。这P当下ơ调用LoadFromFile或LoadFromStreamd数据Ӟ仍然可以恢复原来的数据?


konhon 优华 2007-03-29 18:57 发表评论
]]>
[轉]物流信息pȝ开发手?Delphi的三层开?http://m.tkk7.com/konhon/archive/2007/03/28/107039.htmlkonhon 优华konhon 优华Wed, 28 Mar 2007 10:07:00 GMThttp://m.tkk7.com/konhon/archive/2007/03/28/107039.htmlhttp://m.tkk7.com/konhon/comments/107039.htmlhttp://m.tkk7.com/konhon/archive/2007/03/28/107039.html#Feedback0http://m.tkk7.com/konhon/comments/commentRss/107039.htmlhttp://m.tkk7.com/konhon/services/trackbacks/107039.html  q日Q呵呵,q篇文章是去q写的)用了两个月开发了一个物信息系l,q个pȝ是两层、三层相l合Q?/span>C/S?/span>B/S相结合的pȝ。虽焉于时间的紧张和h手的原因Q系l规模不是很大,但是其中涉及的技术却很全面。在q个?b>开发技术篇》中我们讲解我在开发系l中遇到的技术问题及解决ҎQ希望对大家有帮助。对于物信息系l的分析设计问题Q我在另一文章《物信息系l开发手记――系l构架篇》中讲解?/span>

 

一?/span>Midas的安全问题?/span>

    Midas技术是Delphi中进行三层开发的首选技术,它不仅有U?/span>DCOM/COM+(COM+技术是.NET技术的基础)的优点,而且也结合了Delphi的快速开发特性,可以快速开发出惌的系l,其开发速度是用VC,PB{开?/span>DCOM的数十倍,把程序员从烦杂的代码中解脱出来,从而将更多的精力投入到业务逻辑的设计中厅R?/span>

    但是Midas技术的一个最令h担忧的就是它的安全问题:

q端只要知道应用服务器的端口号即可访问到应用服务器,而一旦访问到应用服务器,TClientDataSet卛_获得ProviderNames列表。一旦知道了ProviderNames列表Q这q当于数据库暴露在外了?/span>

关于可轻易获?/span>ProviderNames列表的问题,我用下面的Ҏ解决Q?/span>

 在服务器端定义一?/span>

LoginMTS(const AUserId, APassword: WideString): WordBool;

Ҏ。初始状态下Q所有的DataSetProvider和数据集的连接断开。用户必调?/span>LoginMTSq传递用户名和密码,登陆成功才将DataSetProvider和数据集的连接打开。这样如果用户验证没有通过Q即使它获得?/span>ProviderNames列表也没法调用接口中的方法对数据库进行操作?/span>

二?/span>Midas中主从表的实?/span>

M表的应用在信息系l中应用很广。在两层开发中我们可以通过直接建立两个数据集之间ؓM关系来实C从表Q在三层中虽然我们仍然可以通过直接建立两个数据集之间ؓM关系来实C从表Q但是这样就要求把数据库中所有相关的数据行都下蝲到本圎ͼ丧失了三层开发的优势。我在实际中使用下面的方法实现。这里我以实现入库单查询、添加、修攏V删?/span>(CRUD)Z来讲解:

Q?/span>1Q新Z?/span>MTS Data ModuleQ命名ؓTmtsStockInListBiz,增加如下ҎQ?/span>

    function QueryStockInListMasterById(const AId: WideString;

      var ADatas: OleVariant): WordBool; safecall;

    function QueryStockInListSlaveByMasterId(const AId: WideString;

      var ADatas: OleVariant): WordBool; safecall;

    procedure UpdataStockInListMaster(var ADatas: OleVariant); safecall;

    procedure UpdataStockInListSlave(var ADatas: OleVariant); safecall;

    function GenerateStockInListId: WideString; safecall;

 

QueryStockInListMasterById作用是根据入库单单号查询入库单的基本信息Q入库日期、负责h{)Q?/span>Aid为入库单单号Q?/span>Adatas回|其格式就?/span>Midas的数据包Q可以将光l?/span>ClientDatSet?/span>Data属性?/span>

QueryStockInListSlaveByMasterId作用是根据入库单单号查询入库单的详细信息Q商品条码,数量Q?/span>

UpdataStockInListMaster是对入库单主表进行删除、添加、修Ҏ作。只要将ClientDataSet?/span>Delta属性做Z递即可?/span>

UpdataStockInListSlave是对入库单从表进行删除、添加、修Ҏ作?/span>

GenerateStockInListId是生一个唯一的入库单受?/span>

下面是几个方法的代码Q都很简单,׃多解释了Q可以查?/span>Delphi的帮助?/span>

function TmtsStockInListBiz.QueryStockInListMasterById(

  const AId: WideString; var ADatas: OleVariant): WordBool;

begin

  result := false;

  ADatas := null;

  try

    cdsQuery.Close;

    cdsQuery.CommandText := 'select * from t_StockInListMaster where Id=:Id';

    cdsQuery.Params.ParamByName('Id').AsString := AId;

    cdsQuery.Open;

    if cdsQuery.RecordCount > 0 then

    begin

      result := true;

      ADatas := cdsQuery.Data;

    end;

  finally

    cdsQuery.Close;

  end;

end;

 

procedure TmtsStockInListBiz.UpdataStockInListMaster(

  var ADatas: OleVariant);

var

  eCount: Integer;

  OwnerData: OleVariant;

begin

  DCOMConStockInList.GetServer.AS_ApplyUpdates('dspStockInListMaster',

    ADatas, -1, eCount, OwnerData);

end;

 

function TmtsStockInListBiz.GenerateStockInListId: WideString;

var

  LPrior: string;

  i: Integer;

begin

  cdsQuery.Close;

  cdsQuery.CommandText := 'select top 1 id from t_StockInListMaster order by id desc';

  cdsQuery.Open;

  LPrior := cdsQuery.FieldByName('Id').AsString;

  i := StrToIntDef(RightStr(LPrior,8),0);

  Inc(i);

  result := 'RK' + FormatFloat('00000000',i);

  cdsQuery.Close;

end;

 

Q?/span>2Q、新Z个应用程序,通过DCOMConnection?/span>SocketConnection{连接到MTSlgQ然后就可以调用MTS的相应的Ҏ实现客户端功能了?/span>

攑օcdsStockInListMaster?/span>cdsStockInListSlave两个ClientDataSet控gQ在控g上点d键,选择?/span>FieldsEditor”新Z服务器中的字D同L字段Q然后再ơ在控g上单d键,选择?/span>CreateDataSet”,建立一个本地数据库?/span>

Q?/span>3Q?/span>

Ҏ入库单号查询入库单的Ҏ实现Q?/span>

procedure TFormStockInList.BtnFindClick(Sender: TObject);

var

  v,vs: OleVariant;

begin

  if SocketConStockInList.AppServer.QueryStockInListMasterById(Trim(LEdtId.Text), v) then

  begin

    cdsStockInListMaster.Data := v;//昄入库单主表(主要信息Q?/span>

 

    if SocketConStockInList.AppServer.QueryStockInListSlaveByMasterId(Trim(LEdtId.Text), vs) then

      cdsStockInListSlave.Data := vs; ;//昄入库单从表(明细信息Q?/span>

  end

  else

    ShowMessage('此单不存在!');

end;

Q?/span>4Q新建入库单的实?/span>

procedure TFormStockInList.BtnNewClick(Sender: TObject);

var

  LId: string;

begin

  ClearCDSRecord;

  cdsStockInListMaster.Open;

  cdsStockInListMaster.Insert;

  LId := SocketConStockInList.AppServer.GenerateStockInListId;

  LEdtId.Text := LId;

  cdsStockInListMaster.FieldByName('Id').AsString := LId;

  cdsStockInListMaster.FieldByName('GenerateDate').AsDateTime := Now();

end;

Q?/span>5Q提交功能的实现

procedure TFormStockInList.BtnPostClick(Sender: TObject);

var

  LQuerymts: ImtsQueryObjDisp;

  LBar: string;

begin

  SetSocketConnectionConnect(SocketConQuery);

  LQuerymts := ImtsQueryObjDisp(SocketConQuery.GetServer);

 

  SocketConQuery.Close;

 

  if cdsStockInListMaster.RecordCount > 0 then

    SocketConStockInList.AppServer.UpdataStockInListMaster(cdsStockInListMaster.Delta);

  if cdsStockInListSlave.RecordCount > 0 then

  SocketConStockInList.AppServer.UpdataStockInListSlave(cdsStockInListSlave.Delta);

end;

注:本文?/span>ClientDataSet控g的名U开头一般ؓcds?/span>TsocketConnection控g的名U开头一般ؓSocketCon?/span>

三、动态设|?/span>TsimpleObjectBroker的服务器列表

procedure SetSocketConnectionConnect(AValue: TSocketConnection);

  procedure FillAppServerList(ABroker: TSimpleObjectBroker);

  var

    sl: TStringList;

    i, n: Integer;

  begin

    sl := TStringList.Create;

    从配|文件中d服务器列表,q保存到sl?/span>;

    n := sl.Count - 1;

    ABroker.ServerData := null;

    for i := 0 to n do

    begin

      ABroker.Servers.Add;

      ABroker.Servers[i].ComputerName := sl.Strings[i]

    end;

    sl.Free;

  end;

var

  LBroker: TSimpleObjectBroker;

begin

  LBroker := TSimpleObjectBroker.Create(nil);

    FillAppServerList(LBroker);

    AValue.ObjectBroker := LBroker;

    try

      AValue.Connected := true;

    except

      raise Exception.Create('应用服务器连接错误!');

    end;

    LBroker.Free;

end;



konhon 优华 2007-03-28 18:07 发表评论
]]>动态设|DNS的例?/title><link>http://m.tkk7.com/konhon/archive/2005/12/02/22186.html</link><dc:creator>konhon 优华</dc:creator><author>konhon 优华</author><pubDate>Fri, 02 Dec 2005 01:21:00 GMT</pubDate><guid>http://m.tkk7.com/konhon/archive/2005/12/02/22186.html</guid><wfw:comment>http://m.tkk7.com/konhon/comments/22186.html</wfw:comment><comments>http://m.tkk7.com/konhon/archive/2005/12/02/22186.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/konhon/comments/commentRss/22186.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/konhon/services/trackbacks/22186.html</trackback:ping><description><![CDATA[<P>一个在普通用户下讄DNS的例?/P> <P>unit uMain;</P> <P>interface</P> <P>uses<BR>  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,<BR>  Dialogs, StdCtrls, Registry;</P> <P>type<BR>  _STARTUPINFOW = record<BR>    cb: DWORD;<BR>    lpReserved: LPWSTR;<BR>    lpDesktop: LPWSTR;<BR>    lpTitle: LPWSTR;<BR>    dwX: DWORD;<BR>    dwY: DWORD;<BR>    dwXSize: DWORD;<BR>    dwYSize: DWORD;<BR>    dwXCountChars: DWORD;<BR>    dwYCountChars: DWORD;<BR>    dwFillAttribute: DWORD;<BR>    dwFlags: DWORD;<BR>    wShowWindow: Word;<BR>    cbReserved2: Word;<BR>    lpReserved2: PByte;<BR>    hStdInput: THandle;<BR>    hStdOutput: THandle;<BR>    hStdError: THandle;<BR>  end;<BR>  STARTUPINFOW = _STARTUPINFOW;</P> <P>  TForm1 = class(TForm)<BR>    Button1: TButton;<BR>    Button2: TButton;<BR>    procedure Button1Click(Sender: TObject);<BR>    procedure Button2Click(Sender: TObject);<BR>    procedure FormClose(Sender: TObject; var Action: TCloseAction);<BR>  private<BR>    { Private declarations }<BR>    procedure DoOperation(aCmd: string);<BR>  public<BR>    { Public declarations }<BR>  end;</P> <P>var<BR>  Form1: TForm1;</P> <P>function CreateProcessWithLogonW(lpUserName, lpDomain, lpPassword: LPCWSTR;<BR>  dwLogonFlags: DWORD; lpApplicationName: LPCWSTR; lpCommandLine: LPWSTR;<BR>  dwCreationFlags: DWORD; lpEnvironment: Pointer; lpCurrentDirectory: LPCWSTR;<BR>  const lpStartupInfo: STARTUPINFOW; var lpProcessInformation: PROCESS_INFORMATION): BOOL; stdcall;<BR>external advapi32 Name 'CreateProcessWithLogonW'</P> <P><BR>implementation</P> <P>{$R *.dfm}</P> <P><BR>procedure DelRegCache;<BR>begin<BR>  with TRegistry.Create do<BR>  try<BR>    RootKey := HKEY_CURRENT_USER;<BR>    DeleteKey('Software\Microsoft\Internet Explorer\TypedURLs');<BR>  finally<BR>    Free;<BR>  end;<BR>end;</P> <P><BR>procedure TForm1.DoOperation(aCmd: string);<BR>var<BR>  STARTUPINFO: StartupInfoW;<BR>  ProcessInfo: TProcessInformation;<BR>  AUser, ADomain, APass, AExe: WideString;<BR>const<BR>  LOGON_WITH_PROFILE = $00000001;<BR>  LOGON_NETCREDENTIALS_ONLY = $00000002;<BR>begin<BR>  Screen.Cursor := crHourGlass;<BR>  try<BR>    FillChar(STARTUPINFO, SizeOf(StartupInfoW), #0);<BR>    STARTUPINFO.cb := SizeOf(StartupInfoW);<BR>    STARTUPINFO.dwFlags := STARTF_USESHOWWINDOW;<BR>    STARTUPINFO.wShowWindow := SW_SHOW;<BR>    AUser := 'administrator';<BR>    APass := '123';<BR>    ADomain := 'domain';<BR>    AExe := aCmd;<BR>    if not CreateProcessWithLogonW(PWideChar(AUser), PWideChar(ADomain),<BR>      PWideChar(APass),<BR>      LOGON_WITH_PROFILE, nil, PWideChar(AExe),<BR>      NORMAL_PRIORITY_CLASS, nil, nil, STARTUPINFO, ProcessInfo) then<BR>      RaiseLastOSError;<BR>    WaitForSingleObject(ProcessInfo.hProcess, INFINITE);<BR>  finally<BR>    Screen.Cursor := crDefault;<BR>  end;<BR>end;</P> <P>procedure TForm1.Button1Click(Sender: TObject);<BR>begin<BR>  DoOperation('netsh interface ip add dns "區域連線" 192.168.10.81 1');<BR>  DoOperation('netsh interface ip add dns "區域連線" 202.96.128.166 2');<BR>  Application.MessageBox('操作完成!', 'CrackNet', MB_OK + 64);<BR>end;</P> <P>procedure TForm1.Button2Click(Sender: TObject);<BR>begin<BR>  DelRegCache;<BR>  DoOperation('netsh interface ip set dns "區域連線" dhcp');<BR>end;</P> <P>procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);<BR>begin<BR>  Hide;<BR>  Button2.Click;<BR>end;</P> <P>end.<BR></P><img src ="http://m.tkk7.com/konhon/aggbug/22186.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/konhon/" target="_blank">konhon 优华</a> 2005-12-02 09:21 <a href="http://m.tkk7.com/konhon/archive/2005/12/02/22186.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Delphi 中如何用另外一个用Lw䆾来运行一人程?http://m.tkk7.com/konhon/archive/2005/11/15/19793.htmlkonhon 优华konhon 优华Tue, 15 Nov 2005 00:15:00 GMThttp://m.tkk7.com/konhon/archive/2005/11/15/19793.htmlhttp://m.tkk7.com/konhon/comments/19793.htmlhttp://m.tkk7.com/konhon/archive/2005/11/15/19793.html#Feedback0http://m.tkk7.com/konhon/comments/commentRss/19793.htmlhttp://m.tkk7.com/konhon/services/trackbacks/19793.html如一个程序要有以下的命o来运?BR>runas /env /savecred /user:hhql "c:\qlnetbar\bc2\bc2"
我现在的问题是如何在Delphi中用代码来代?runas /env /savecred /user:hhql 的功能,因ؓ我要监视 c:\qlnetbar\bc2\bc2 的运行情况,所?c:\qlnetbar\bc2\bc2 必须要由我用Delphi写的E序来运?/P>

请高手指教。。。?BR>

果你用XP?000Q可以用下面的APIQCreateProcessWithLogonW
type
  _STARTUPINFOW = record
    cb: DWORD;
    lpReserved: LPWSTR;
    lpDesktop: LPWSTR;
    lpTitle: LPWSTR;
    dwX: DWORD;
    dwY: DWORD;
    dwXSize: DWORD;
    dwYSize: DWORD;
    dwXCountChars: DWORD;
    dwYCountChars: DWORD;
    dwFillAttribute: DWORD;
    dwFlags: DWORD;
    wShowWindow: Word;
    cbReserved2: Word;
    lpReserved2: PByte;
    hStdInput: THandle;
    hStdOutput: THandle;
    hStdError: THandle;
  end;
  STARTUPINFOW = _STARTUPINFOW;

function CreateProcessWithLogonW(lpUserName, lpDomain, lpPassword: LPCWSTR;
  dwLogonFlags: DWORD; lpApplicationName: LPCWSTR; lpCommandLine: LPWSTR;
  dwCreationFlags: DWORD; lpEnvironment: Pointer; lpCurrentDirectory: LPCWSTR;
  const lpStartupInfo: STARTUPINFOW; var lpProcessInformation: PROCESS_INFORMATION): BOOL; stdcall;
  external advapi32 Name 'CreateProcessWithLogonW'

procedure TForm1.Button2Click(Sender: TObject);
var
  STARTUPINFO: StartupInfoW;
  ProcessInfo: TProcessInformation;
  AUser, ADomain, APass, AExe: WideString;
const
  LOGON_WITH_PROFILE = $00000001;
  LOGON_NETCREDENTIALS_ONLY = $00000002;
begin
  FillChar(STARTUPINFO, SizeOf(StartupInfoW), #0);
  STARTUPINFO.cb := SizeOf(StartupInfoW);
  STARTUPINFO.dwFlags := STARTF_USESHOWWINDOW;
  STARTUPINFO.wShowWindow := SW_SHOW;
  AUser := edtUser.Text;
  ADomain := edtDomain.Text;
  APass := edtPass.Text;
  AExe := edtExe.Text;
  if not CreateProcessWithLogonW(PWideChar(AUser), PWideChar(ADomain),
    PWideChar(APass),
    LOGON_WITH_PROFILE, nil, PWideChar(AExe),
    NORMAL_PRIORITY_CLASS, nil, nil, STARTUPINFO, ProcessInfo) then
    RaiseLastOSError;
end;

已经试通过

代码修改了一下:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

type
  _STARTUPINFOW = record
    cb: DWORD;
    lpReserved: LPWSTR;
    lpDesktop: LPWSTR;
    lpTitle: LPWSTR;
    dwX: DWORD;
    dwY: DWORD;
    dwXSize: DWORD;
    dwYSize: DWORD;
    dwXCountChars: DWORD;
    dwYCountChars: DWORD;
    dwFillAttribute: DWORD;
    dwFlags: DWORD;
    wShowWindow: Word;
    cbReserved2: Word;
    lpReserved2: PByte;
    hStdInput: THandle;
    hStdOutput: THandle;
    hStdError: THandle;
  end;
  STARTUPINFOW = _STARTUPINFOW;

function CreateProcessWithLogonW(lpUserName, lpDomain, lpPassword: LPCWSTR;
  dwLogonFlags: DWORD; lpApplicationName: LPCWSTR; lpCommandLine: LPWSTR;
  dwCreationFlags: DWORD; lpEnvironment: Pointer; lpCurrentDirectory: LPCWSTR;
  const lpStartupInfo: STARTUPINFOW; var lpProcessInformation: PROCESS_INFORMATION): BOOL; stdcall;
  external advapi32 Name 'CreateProcessWithLogonW'
var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  STARTUPINFO: StartupInfoW;
  ProcessInfo: TProcessInformation;
  AUser, ADomain, APass, AExe: WideString;
const
  LOGON_WITH_PROFILE = $00000001;
  LOGON_NETCREDENTIALS_ONLY = $00000002;
begin
  FillChar(STARTUPINFO, SizeOf(StartupInfoW), #0);
  STARTUPINFO.cb := SizeOf(StartupInfoW);
  STARTUPINFO.dwFlags := STARTF_USESHOWWINDOW;
  STARTUPINFO.wShowWindow := SW_SHOW;
  AUser := 'pcmax';
  //ADomain := edtDomain.Text;
  APass := 'pcmax';
  AExe := 'c:\windows\system32\mspaint.exe';
  if not CreateProcessWithLogonW(PWideChar(AUser), PWideChar(ADomain),
    PWideChar(APass),
    LOGON_WITH_PROFILE, nil, PWideChar(AExe),
    NORMAL_PRIORITY_CLASS, nil, nil, STARTUPINFO, ProcessInfo) then
    RaiseLastOSError;
  WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
  ShowMessage('over now');
end;

end.

q行上面的代码,点击button1׃以用户pcmaxq行 c:\windows\system32\mspaint.exe。然后等待运行结束后弹出提示对话框?/P>

 



konhon 优华 2005-11-15 08:15 发表评论
]]>
??/title><link>http://m.tkk7.com/konhon/archive/2005/11/12/19442.html</link><dc:creator>konhon 优华</dc:creator><author>konhon 优华</author><pubDate>Sat, 12 Nov 2005 00:59:00 GMT</pubDate><guid>http://m.tkk7.com/konhon/archive/2005/11/12/19442.html</guid><wfw:comment>http://m.tkk7.com/konhon/comments/19442.html</wfw:comment><comments>http://m.tkk7.com/konhon/archive/2005/11/12/19442.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/konhon/comments/commentRss/19442.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/konhon/services/trackbacks/19442.html</trackback:ping><description><![CDATA[???????????Q?Windows????????????<BR>????????????Q??????DrawIcon?????????<BR><BR><BR>procedure TForm1.FormClick(Sender: TObject);<BR>var<BR>  winHWND, hCur: integer;<BR>  winDC: integer;<BR>  rect: TRect;<BR>  pt: TPoint;<BR>  fBitmap: TBitmap;<BR>begin<BR>  hCur := GetCursor(); // 取得光标句柄<BR>  GetCursorPos(pt); // 取得光标位置<BR>  winHWND := GetDesktopWindow();<BR>  winDC := GetDC(winHWND);<BR>  GetWindowRect(winHWND, rect);<BR>  fBitmap := TBitmap.create;<BR>  try<BR>    fBitmap.width := rect.right - rect.left;<BR>    fBitmap.height := rect.bottom - rect.top;<BR>    BitBlt(fBitmap.canvas.handle, 0, 0, fBitmap.width, fBitmap.height, winDC, 0, 0, SRCCOPY);<BR>    DrawIcon(fBitmap.canvas.handle, pt.x, pt.y, hCur); // d?BR>    ReleaseDC(winHWND, winDC);<BR>    Image1.Picture.Bitmap.Assign(fBitmap);<BR>  finally<BR>    fBitmap.Free;<BR>  end;<BR>end;<img src ="http://m.tkk7.com/konhon/aggbug/19442.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/konhon/" target="_blank">konhon 优华</a> 2005-11-12 08:59 <a href="http://m.tkk7.com/konhon/archive/2005/11/12/19442.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> 字符串与二进制数之间的互相{?http://m.tkk7.com/konhon/archive/2005/11/02/17868.htmlkonhon 优华konhon 优华Wed, 02 Nov 2005 10:37:00 GMThttp://m.tkk7.com/konhon/archive/2005/11/02/17868.htmlhttp://m.tkk7.com/konhon/comments/17868.htmlhttp://m.tkk7.com/konhon/archive/2005/11/02/17868.html#Feedback0http://m.tkk7.com/konhon/comments/commentRss/17868.htmlhttp://m.tkk7.com/konhon/services/trackbacks/17868.html
   把字W串(可含中文字符)转ؓ二进制数的函?ConvertStrToBin();把二q制数{换ؓ字符串的函数QConvertBinToStr()?BR>   以下两个函数亦可以对包含有中文字W的字符串进行处?逆{时亦可正常{Z文?BR>Function ConvertStrToBin(Value : string):string;//把字W串转化Zq制?BR>var tempHex : string[2];
    i : integer;
begin
  Result := '';
  if trim(Value) = '' then Exit;
  tempHex := '';
  for i := 1 to Length(Value) do
  begin
    tempHex := IntToHex(Ord(Value[i]),2);//每个字符转成两位十六q制?BR>    Result := Result + BinToHexEachOther(tempHex,False);//十六q制转成二进?BR>  end;
end;

Function ConvertBinToStr(Value : string):string; //把二q制数据转化为字W串
Var tempHex : string;
    i, tempInt : integer;
begin
  Result := '';
  if trim(Value) = '' then Exit;
  tempHex := BinToHexEachOther(Value,true);//二进制{成十六进?BR>  i := 0;
  Repeat
    begin
      i := i + 1;
      tempInt := HexCharToInt(tempHex[i]);
      i := i + 1;
      tempInt := tempInt * 16 + HexCharToInt(tempHex[i]);
       //以上两位十六进制数转变Z个十q制?BR>      Result := Result + chr(TempInt); //转成ASCII?BR>    end;
  Until i >= length(tempHex)
end;

上两个互逆的函数中要调用到的函数HexCharToInt()和BinToHexEachOther()如下Q?BR>
function BinToHexEachOther(ValueA : string; Action : Boolean) : string;
  //把二q制串{换成十六q制串或相反
  var
    ValueArray1 : Array [0..15] of string[4];
    ValueArray2 : Array [0..15] of char;
    i : shortint;
begin
    //数组初始?BR>    ValueArray1[0] := '0000';  ValueArray1[1] := '0001';  ValueArray1[2] := '0010';
    ValueArray1[3] := '0011';  ValueArray1[4] := '0100';  ValueArray1[5] := '0101';
    ValueArray1[6] := '0110';  ValueArray1[7] := '0111';  ValueArray1[8] := '1000';
    ValueArray1[9] := '1001';  ValueArray1[10] := '1010';  ValueArray1[11] := '1011';
    ValueArray1[12] := '1100';  ValueArray1[13] := '1101';  ValueArray1[14] := '1110';
    ValueArray1[15] := '1111';
    for i := 0 to 15 do
      if i >= 10 then ValueArray2[i] := chr(65 + (i - 10))
      else ValueArray2[i] := inttostr(i)[1];

    Result := '';
    if Action then
    begin //二进制串转换成十六进制串
      if (Length(ValueA) MOD 4 <> 0) then
        ValueA := stringofchar('0',Length(ValueA) MOD 4) + ValueA;
      while (Length(ValueA) >= 4) do
      begin
        for i := 0 to 15 do
          if Copy(ValueA,1,4) = ValueArray1[i] then
            Result := Result + ValueArray2[i];
        ValueA := Copy(ValueA,5,Length(ValueA) - 4);
      end;
    end
    else begin //十六q制串{换成二进制串
      while (Length(ValueA) >= 1) do
      begin
        for i := 0 to 15 do
          if Copy(ValueA,1,1) = ValueArray2[i] then
            Result := Result + ValueArray1[i];
        ValueA := Copy(ValueA,2,Length(ValueA) - 1);
      end;
    end;
end;

function HexCharToInt(HexToken : char):Integer;
begin
Result:=0;
if (HexToken>#47) and (HexToken<#58) then       { chars 0....9 }
   Result:=Ord(HexToken)-48
else if (HexToken>#64) and (HexToken<#71) then  { chars A....F }
   Result:=Ord(HexToken)-65 + 10;
end;


十六q制字串转十q制又一法:
procedure TForm1.BitBtn1Click(Sender: TObject);
var myint : integer;
begin
  myint := StrToInt('$' + '3A'); // myint = 58
  showmessage(inttostr(myint));
end;

konhon 优华 2005-11-02 18:37 发表评论
]]>
a置pȝ時間http://m.tkk7.com/konhon/archive/2005/10/12/15323.htmlkonhon 优华konhon 优华Wed, 12 Oct 2005 05:49:00 GMThttp://m.tkk7.com/konhon/archive/2005/10/12/15323.htmlhttp://m.tkk7.com/konhon/comments/15323.htmlhttp://m.tkk7.com/konhon/archive/2005/10/12/15323.html#Feedback0http://m.tkk7.com/konhon/comments/commentRss/15323.htmlhttp://m.tkk7.com/konhon/services/trackbacks/15323.htmlvar
  ADateTime: TSystemTime;
  yy, mon, dd, hh, min, ss, ms: Word;
begin
  decodedate(ATime, yy, mon, dd);
  decodetime(ATime, hh, min, ss, ms);
  with ADateTime do
  begin
    wYear := yy;
    wMonth := mon;
    wDay := dd;
    wHour := hh;
    wMinute := min;
    wSecond := ss;
    wMilliseconds := ms;
  end;
  Result := SetLocalTime(ADateTime);
  SendMessage(HWND_BROADCAST, WM_TIMECHANGE, 0, 0);
end;

konhon 优华 2005-10-12 13:49 发表评论
]]>
按分隔符取字W串http://m.tkk7.com/konhon/archive/2005/08/30/11512.htmlkonhon 优华konhon 优华Tue, 30 Aug 2005 00:21:00 GMThttp://m.tkk7.com/konhon/archive/2005/08/30/11512.htmlhttp://m.tkk7.com/konhon/comments/11512.htmlhttp://m.tkk7.com/konhon/archive/2005/08/30/11512.html#Feedback0http://m.tkk7.com/konhon/comments/commentRss/11512.htmlhttp://m.tkk7.com/konhon/services/trackbacks/11512.htmlfunction TForm1.ExtractString(const aString: string; const aSeparator: char; var aPos: Integer): string;
var
  I: Integer;
begin
  I := aPos;
  while (I <= Length(aString)) and (aString[I] <> aSeparator) do Inc(I);
  Result := Trim(Copy(aString, aPos, I - aPos));
  if (I <= Length(aString)) and (aString[I] = aSeparator) then Inc(I);
  aPos := I;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  lString, lSubString: string;
  lPos, j: integer;
begin
  lString := '023842394201342|343242423423|342342424|533423|2455';
  lPos := 1;
  j := 0;

  while lPos <= Length(lString) do
  begin
    lSubString := ExtractString(lString, '|', lPos);
    inc(j);
    if j = 2 then    // W二?BR>      showmessage(lSubString);
  end;
end;



konhon 优华 2005-08-30 08:21 发表评论
]]>
動態a定Menu快捷键的问题 http://m.tkk7.com/konhon/archive/2005/08/27/11280.htmlkonhon 优华konhon 优华Sat, 27 Aug 2005 02:29:00 GMThttp://m.tkk7.com/konhon/archive/2005/08/27/11280.htmlhttp://m.tkk7.com/konhon/comments/11280.htmlhttp://m.tkk7.com/konhon/archive/2005/08/27/11280.html#Feedback0http://m.tkk7.com/konhon/comments/commentRss/11280.htmlhttp://m.tkk7.com/konhon/services/trackbacks/11280.html

konhon 优华 2005-08-27 10:29 发表评论
]]>
啟用用要地連接http://m.tkk7.com/konhon/archive/2005/08/26/11228.htmlkonhon 优华konhon 优华Fri, 26 Aug 2005 09:11:00 GMThttp://m.tkk7.com/konhon/archive/2005/08/26/11228.htmlhttp://m.tkk7.com/konhon/comments/11228.htmlhttp://m.tkk7.com/konhon/archive/2005/08/26/11228.html#Feedback0http://m.tkk7.com/konhon/comments/commentRss/11228.htmlhttp://m.tkk7.com/konhon/services/trackbacks/11228.htmlhttp://m.tkk7.com/Files/konhon/EnableNetCard.rar

在Delphi中选Project Import Type Library命oQ在对话框中选Import Microsoft Shell Controls And Automationcd库,点Install后,在Delphi的ActiveX控g板上多了TShellFolderItemQTShellLinkObjectQTShellFolderViewQTShellQTSearchCommand{几个组?/P>

const
   discVerb = '用(&B)';
   connVerb = '启用(&A)';

function TForm1.DisableEthernet(const EthName,State: String): Boolean;
var
  cpFolder: Folder;
  nwFolder: Folder;
  nVerbs: FolderItemVerbs;
  i,j,k: integer;
  aItem: TListItem;
begin
  result := false;
  cpFolder := Form1.shell1.NameSpace(3);
  if cpFolder <> nil then
  begin
    for i := 0 to cpFolder.items.Count-1 do
    begin
      if cpFolder.Items.Item(i).Name = '|络和拨可? then
      begin
        nwFolder := cpFolder.items.item(i).GetFolder as Folder;
        if nwFolder <> nil then
        begin
          for j :=0 to nwFolder.items.Count-1 do
          begin
            if nwFolder.Items.Item(j).Name = EthName then
            begin
              nVerbs := nwFolder.Items.Item(j).Verbs;
              for k := 0 to  nVerbs.Count-1 do
             begin
                if nVerbs.Item(k).Name = State then
                begin
                  nVerbs.Item(k).DoIt;
                  aItem := Form1.lvLog.Items.Add;
                  aItem.Caption := FormatDateTime('yyyy-mm-dd hh:mm:ss',now);
                  aItem.SubItems.Add(EthName);
                  aItem.SubItems.Add(State);
                  Result := True;
                end;
              end;
            end;
          end;
        end;
      end;
    end;
    if nwFolder = nil then
       showmessage('Network and Dial-up Connections not found');
  end
  else
    showmessage('control panel not found');

end;


procedure TForm1.Button1Click(Sender: TObject);
begin
  DisableEthernet('本地q接',discVerb);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  DisableEthernet('本地q接',connVerb);
end;



konhon 优华 2005-08-26 17:11 发表评论
]]>
向CGI提交數據http://m.tkk7.com/konhon/archive/2005/08/26/11188.htmlkonhon 优华konhon 优华Fri, 26 Aug 2005 03:13:00 GMThttp://m.tkk7.com/konhon/archive/2005/08/26/11188.htmlhttp://m.tkk7.com/konhon/comments/11188.htmlhttp://m.tkk7.com/konhon/archive/2005/08/26/11188.html#Feedback0http://m.tkk7.com/konhon/comments/commentRss/11188.htmlhttp://m.tkk7.com/konhon/services/trackbacks/11188.htmlvar
  lUrl: string;
  lParams: TStrings;
  lHtml: string;
begin
  lUrl := 'http://snixxx.co.uk/cgi-bin/mt-comments.cgi';
  lParams := TStringList.Create;
  try
    lParams.Add('entry_id=1302');
    lParams.Add('author=dqxhyy');
    lParams.Add('dqxhyy@sina.com');
    lParams.Add('dqxhyydqxhyydqxhyydqxhyy');
    try
      lHtml := IdHttp1.Post(lUrl, lParams);
    except
      showmessage(lhtml);
    end;
    showmessage(lhtml);
  finally
    lParams.Free;
  end;
end;

konhon 优华 2005-08-26 11:13 发表评论
]]>
如何通过发送WM_COMMAND消息模拟点击其他E序H体上的菜单? http://m.tkk7.com/konhon/archive/2005/08/26/11169.htmlkonhon 优华konhon 优华Fri, 26 Aug 2005 02:05:00 GMThttp://m.tkk7.com/konhon/archive/2005/08/26/11169.htmlhttp://m.tkk7.com/konhon/comments/11169.htmlhttp://m.tkk7.com/konhon/archive/2005/08/26/11169.html#Feedback0http://m.tkk7.com/konhon/comments/commentRss/11169.htmlhttp://m.tkk7.com/konhon/services/trackbacks/11169.htmlprocedure TForm1.Button1Click(Sender: TObject);
var
   h,m,s,s1:hwnd;
begin
  h:=FindWindow('notepad',nil);
   if h<>0 then
   begin
     m:=GetMenu(h);
     s:=GetSubMenu(m,1);
     s1:=GetSubMenu(s,7);
     SendMessage(h,WM_COMMAND,MakeLong(GetMenuItemId(s,7),0),s1);
  end;
end;

konhon 优华 2005-08-26 10:05 发表评论
]]>
在Lalel上单击,然后在Label下文出现下拉框(popupmenuQ,怎样让下拉框紧挨着Label下方出现?/title><link>http://m.tkk7.com/konhon/archive/2005/08/25/11116.html</link><dc:creator>konhon 优华</dc:creator><author>konhon 优华</author><pubDate>Thu, 25 Aug 2005 11:58:00 GMT</pubDate><guid>http://m.tkk7.com/konhon/archive/2005/08/25/11116.html</guid><wfw:comment>http://m.tkk7.com/konhon/comments/11116.html</wfw:comment><comments>http://m.tkk7.com/konhon/archive/2005/08/25/11116.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/konhon/comments/commentRss/11116.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/konhon/services/trackbacks/11116.html</trackback:ping><description><![CDATA[procedure TForm1.Label1Click(Sender: TObject);<BR>var<BR>  lPoint: TPoint;<BR>begin<BR>  lPoint.X := TLabel(Sender).Left;<BR>  lPoint.Y := TLabel(Sender).Top + TLabel(Sender).Height;<BR>  lPoint:=ClientToScreen(lPoint);<BR>  PopupMenu1.Popup(lPoint.X, lPoint.Y);<BR>end;<img src ="http://m.tkk7.com/konhon/aggbug/11116.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/konhon/" target="_blank">konhon 优华</a> 2005-08-25 19:58 <a href="http://m.tkk7.com/konhon/archive/2005/08/25/11116.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DBGrid不夠寬加'...'http://m.tkk7.com/konhon/archive/2005/08/25/11115.htmlkonhon 优华konhon 优华Thu, 25 Aug 2005 11:57:00 GMThttp://m.tkk7.com/konhon/archive/2005/08/25/11115.htmlhttp://m.tkk7.com/konhon/comments/11115.htmlhttp://m.tkk7.com/konhon/archive/2005/08/25/11115.html#Feedback0http://m.tkk7.com/konhon/comments/commentRss/11115.htmlhttp://m.tkk7.com/konhon/services/trackbacks/11115.html  var Text: string; DisplayText: Boolean);
var
  lSingleWidth: integer;
  lDBGridWidth: integer;
begin
  lSingleWidth := DBGrid1.Canvas.TextWidth('?);
  lDBGridWidth := DBGrid1.Columns[1].Width;
  if DBGrid1.Canvas.TextWidth(Sender.AsString) <= lDBGridWidth then
    Text := Sender.AsString
  else if DBGrid1.Canvas.TextWidth(Sender.AsString) > lDBGridWidth then
  begin
    lSingleWidth := lDBGridWidth div lSingleWidth - 1;
    if lSingleWidth mod 2 = 1 then
      lSingleWidth := lSingleWidth + 1;
    Text := Copy(Sender.AsString, 1, lSingleWidth) + '...';
  end
end;


konhon 优华 2005-08-25 19:57 发表评论
]]>
如何得到鼠标l过listview每一行的各列信息http://m.tkk7.com/konhon/archive/2005/08/25/11114.htmlkonhon 优华konhon 优华Thu, 25 Aug 2005 11:45:00 GMThttp://m.tkk7.com/konhon/archive/2005/08/25/11114.htmlhttp://m.tkk7.com/konhon/comments/11114.htmlhttp://m.tkk7.com/konhon/archive/2005/08/25/11114.html#Feedback0http://m.tkk7.com/konhon/comments/commentRss/11114.htmlhttp://m.tkk7.com/konhon/services/trackbacks/11114.htmluses CommCtrl;

procedure TForm1.ListView1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var
  item: TListItem;
  lvhti: LV_HITTESTINFO;
begin
  item := ListView1.GetItemAt(X, Y);
  if (item <> nil) then
    Caption := 'Mouse at: ' + item.Caption
  else
  begin
    lvhti.pt.X := X;
    lvhti.pt.Y := Y;
    ListView_SubItemHitTest(ListView1.Handle, @lvhti);
    if Assigned(ListView1.Items[lvhti.iItem])
      and (ListView1.Items[lvhti.iItem].SubItems.Count >= lvhti.iSubItem) then
      Caption := 'Mouse at:' + ListView1.Items[lvhti.iItem].SubItems[lvhti.iSubItem - 1];
  end;
end;



konhon 优华 2005-08-25 19:45 发表评论
]]>
վ֩ģ壺 Ƶ| ߲| ֻ߹ۿƵ| ѹۿ| mv| ޺һ| A޾VƷ| ֳִˬƵ| ҹƬ| 99ȾƷѹۿ| ĻƬ| hƵѹۿ| ޾ƷGVͬ| ޾Ʒ˾þ| ޹ᆱƷԲ߹ۿ| Ʒպһ| ڵ߹ۿƵ| ձ| 99Ƶ99߹ۿ| ˾69ƷƵ| Ʒѿþþ㽶 | ѹۿ| þwww˳| ձWWWѰ| CAOPORMƷƵ| Ƶѹۿ| hairyëpicsȫ| mate20pro鶹| ¶ѿ| ۺ޹| 99þ޾ƷëƬ | պӰ߹ۿĻ| XXX2߹ۿƵ| һѹۿƵ| һþAþѾƷ| ԻAVƬѲŲ| ߹ۿ| þ91ѹۿ| Ʒվ| 69ƷƵ| 91վѹۿ|