2004年9月14日

今天看到一个blog上讨论字符串分割函数,一时兴起,自己写了一个

这个是其他人写的相关函数
http://blog.codelphi.com/hanklee/archive/2004/06/08/13932.aspx?Pending=true


我是用传址的过程来实现结果返回的,反正挺简单的
//Strs: TStrings 分割后的字符串元素
//str: string; 源字符串
//spt: string 分隔符
procedure TFileServerThread.cutString(var Strs: TStrings; str: string; const spt: string);
begin
     while (pos(spt, str) <> 0) do begin
          strs.Add(copy(str, 1, pos(spt, str) - 1));
          delete(Str, 1, pos(spt, str) + 1);
     end;
     strs.Add(str);
end;

posted @ 2004-09-14 12:25 khan 阅读(743) 评论(1) 编辑

2004年8月30日

获取系统的所有串口

第一个思路应该是用建立串口的方式来取得串口名,若建立失败,则此串口不存在

void GetComList() { 
  CString strCom;
  
int nCom = 0;
  
int count = 0;
  HANDLE hCom;
  
do {
    nCom
++;
    strCom.Format(
"COM%d", nCom);
    hCom 
= CreateFile(strCom, 000, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    
if (INVALID_HANDLE_VALUE == hCom)
      
break;
    m_cbComList.AddString(strCom);
    CloseHandle(hCom);
  } 
while (1);


//-------------------------------------------------------------- - 

// 串口信息都是保存在注册表的这个位置的 // HKEY_LOCAL_MACHINEHARDWAREDEVICEMAPSERIALCOMM 
HKEY hKey; 
LONG ret; 
OSVERSIONINFO osvi; 
BOOL bOsVersionInfoEx; 
char keyinfo[100], 
     comm_name[
40], 
     ValueName[
40];
int i; 
DWORD sType, 
      Reserved, 
      cbData, 
      cbValueName;
hIcon 
= AfxGetApp() - > LoadIcon(IDI_HARDWARE); 
SetIcon(hIcon, 
false); 
ZeroMemory( 
& osvi, sizeof(OSVERSIONINFO)); 
osvi.dwOSVersionInfoSize 
= sizeof(OSVERSIONINFO); 
memset(keyinfo, 
0100); 
strcpy(keyinfo, 
"HARDWARE\DEVICEMAP\SERIALCOMM"); 
= 0
sType 
= REG_SZ; 
Reserved 
= 0
bOsVersionInfoEx 
= GetVersionEx( & osvi); 
ret 
= RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyinfo, 0, KEY_ALL_ACCESS, & hKey);
if (ret == ERROR_SUCCESS) { 
  
if (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
    
for (i = 1; i <= 128; i++) {
      sprintf(comm_name, 
"COM%d", i);
      
if (CommPortIsUsed(comm_name) == 1
        m_comlist.AddString(comm_name);
    }
  } 
else if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
    
do {
      cbData 
= 40;
      cbValueName 
= 40;
      memset(comm_name, 
040);
      memset(ValueName, 
040);
      ret 
= RegEnumValue(hKey, i, ValueName, & cbValueName, NULL, & sType, (LPBYTE) comm_name, & cbData);
      
if (ret == ERROR_SUCCESS) {
        
if (CommPortIsUsed(comm_name) == 1) m_comlist.AddString(comm_name);
        i
++;
      }
    } 
while (ret == ERROR_SUCCESS);
  }
}

 

posted @ 2004-08-30 15:45 khan 阅读(944) 评论(0) 编辑

2004年8月17日

使用TServerSocket构件提供多线程服务

最近要写一个socket的多线程的服务,刚刚好从网上找到这篇文章,觉得有用,保存下来
      {
使用TServerSocket构件提供多线程服务
www.mynetlife.com  2002-12-29  网迷教程


使用TServerSocket构件提供多线程服务
对于一个socket来说,很容易提供一个侦听消息的多线程服务。Delphi自身也提供了这样的构件:TServerSocket。
不过这里边也需要一点小技巧。
为此,我们要做以下几件事:
-将TServerSocket加入main窗体中
-设置Servertype属性为stThreadBlocking
-生成一个新单元(如下)来包含服务线程
将下面的代码赋给OnGetThread事件响应函数
   }

procedure TfrmMain.fSocketGetThread(Sender: TObject;  ClientSocket: TServerClientWinSocket;  var SocketThread: TServerClientThread);

begin

// 在每次一个新连接建立的时候为它生成一个新的TServerThread对象。

  SocketThread := TServerThread.Create(FALSE, ClientSocket);

end;

       {下面是我自己生成的TServerThread对象代码.该对象从TServerClinetThread继承而来,包含从socket读写数据的代码。}
unit serverthread;

interface

uses

  windows, scktcomp, SysUtils, Classes, Forms;

type
  EServerThread = class(Exception);
// TServerThread服务线程类是TServerClientThread的派生类
  TServerThread = class(TServerClientThread)

  private
    fSocketStream: TWinSocketStream;

  public
    procedure ClientExecute; override;

// ClientExecute过程将覆盖TServerClientThread.ClientExecute过程
// 并包含实际执行的代码于线程开始时。
  end;

implementation

procedure TServerThread.ClientExecute;
begin
  inherited FreeOnTerminate := TRUE;
  try
    fSocketStream := TWinSocketStream.Create(ClientSocket, 100000);
   // 设置100000毫秒的充许超时.
    try
      while (not Terminated) and (ClientSocket.Connected) do
      try
      // 在此处加入你对输入、读、写的等待
      // 下面的示范你可以拿来照搬在此

      except on e: exception do begin
         // 一旦错误发生就关闭并退出
          ClientSocket.Close;
          Terminate;
        end;
      end;
    finally
      fSocketStream.Free;
    end;
  except on e: exception do  begin
     // 一旦错误发生就关闭并退出
      ClientSocket.Close;
      Terminate;
    end;
  end;
end;

      {一旦连接建立,线程需要等待数据到来.你可以使用下面的代码来等待数据:}
if (not Terminated) and (not fSocketStream.WaitForData(1000000)) then
begin
// 超时处理
end;

// 数据到达!
    {为了读取数据,我们需要建立一个数据缓冲区存取到达的数据,可以使用PByteArray或一个char型的数组.
在此例中我设置了一个名为fRequest的char型数组缓冲。此外我将其设为定长,其大小由REQUESTSIZE常量决定.}
var
  ac, readlen: integer;
begin
  FillChar(fRequest, REQUESTSIZE, 0);
  ac := 0;
  repeat
    readlen := fSocketStream.Read(fRequest[ac],1024);
    // 每次读取1024 bytes直到缓冲区满
    ac := ac + readlen;
  until (readlen = 0) or (ac = REQUESTSIZE);
end;
{
如果说readlen是 0 的话,说明我未收到任何数据.读函数的超时从TWinSocketStream.Create()执行后开始.如果说你不知道预期的数据量,你最好将超时设置得尽量小些.在大多数情况下 30 秒是上限.
当发送一个应答时,你应该很清楚客户端的行为.许多客户端仅仅等待一个应答包,一些则等待许多包.
在本例中,我只设置了一个客户端并只等待一个包,所以我们需要一次就将数据包发送出去。

fSocketStream.WriteBuffer( fRep, fReplySize );
fRep是应答缓冲区,fReplySize则是缓冲区大小.  }

posted @ 2004-08-17 16:39 khan 阅读(2446) 评论(0) 编辑

2004年6月25日

object pascal字符串的几个类型

大家对有object pascal的字符串可能您经常用AnsiString其他的字符串一般很少用到。

下面举几个字符串的几个类型:

AnsiSring 这是Pascal的默认类型。其长度没有限制的。并且字符串结束是以null结尾。也就是以'/0'结尾。

ShortSring是为了与Delphi以前的版本保持兼容性。其长度限制在255个字符之内的。

WideSring与AnsiString类似,但它是由WideChar字符组成的。
PChar指向null结束的字符串的指针。类似于c里面的char*或者lpstr.
PAnsiChar指向以null结束的AnisChar结束的字符串指针。
PWideChar指向以null结束的WideChar的字符串的指针。
缺省情况下是AnisSring的类型:
var
 S:String;
也可以有编译器开关$H来将String类型定义为ShortString类型:例子
var
 {$H-}
 s1:=string;//s1是shortstring类型
 {$H+}
 s2:=string;//s2是sring类型
但是当特定指定的字符串的长度,长度要小于255的时候,其用{$H}的时候总是AnsiSring
例子:
var
 s:string[254];
下面我要讲讲这些类型的各自用法:
1、AnisSring类型
它是动态分配的并且有自动回收功能。这个功能被称为生存期自管理功能。不用象c中的中间结果
由于AnisSring类型的字符串以null结尾的,因此可以与Win32Api兼容。实际上AnisSring是
指向在堆栈中的字符串结构的指针。

posted @ 2004-06-25 12:30 khan 阅读(693) 评论(0) 编辑

2004年6月15日

VCL的诞生和设计原理(摘抄inside vcl)

VCL的诞生和设计原理
从无到有--?VCL对象生命的成型

基本的对象管理服务至少应该包含下面的服务:
l 对象的创建和初始化
l 对象方法的分配
l 对象的消灭

Object Pascal 的对象模型
使用Object pascal定义的Tobject类非常简单,只要如下两行代码就可以
Tobject =class
End;

这虽然时合法的类定义,但是实际用处不大,因为在创建类对象时必须为对象分配内存并且进行对象初始化之后才能正确的使用对象.
因此一般的类都会定义对象的构造函数(constructor或者ctor),而构造函数的目的就是为对象分配内存及进行对象初始化工作.由于对象分配了内存,因此当对象生命结束之后当然需要释放分配的内存以及进行初始化反向的工作,如此在能够归还系统资源,所以类也会定义析构函数(destructor 或者 dtor).因此最基础的类通常会定义成如下形式:
Tobject = class
  Constructor Create;
  Destructor Destroy; virtual;
End;

其中析构函数Destroy声明为virtual方法时因为在Tobject的派生类中可能会分配额外的资源,因此派生类可以改写(override)Tobject的析构函数,当派生类对象释放时,先释放他自己分配的资源,在调用Tobject的析构函数来释放Tobject为对象分配的资源.如果Tobject的析构函数不声明成虚拟方法,那么派生类的析构函数便会覆盖Tobject的析构函数,如此一来,只有派生类分配的内存会被释放,由Tobject为对象分配的资源则可能没有释放,这就造成了内存泄漏(leak)问题.

定义这样一个类:
TMyObject = class(Tobject)
  Destructor Destory ; override;
End;



Destructor TMyObject.Destory;
Begin
  //释放TmyObject分配的内存;
  inherited Destory;//调用父类的Destory;
End;

当我们使用如下程序代码创建TmyObject 时,发生了什么?
Obj := TMyObject.Create;
Object Pascal的对象模型在这行程序代码后进行了很多的工作,包括分配内存,设定字段变量数据结构,设定执行框架等工作,因此上面的程序可分解成如下的程序代码:
TMyObject.AllocateMemory;
TMyObject.InitializeSpecialFields;
Obj:= TMyObject.SetupExecFrame;

创建对象的第一步是分配内存,Object Pascal会使用内建的内存管理器为对象分配内存:
PMemoryManager = ^TMemoryManager;
TMemoryManager = record
  GetMem:function(Size:Integer):Pointer;
  FreeMem:function(p:Pointer):Integer;
  ReallocMem :function(P:pointer; Size:Integer):Pointer;
End;

虽然Object Pascal使用了默认的内存管理器,但是Object Pascal对象模型的设计似乎是允许切换内存管理器的.
在分配了对象的原始内存之后,Object Pascal的对象模型会先初始化所有的内存内容为0.
FillChar(Instance^ ,InstanceSize, 0);
然后对类中声明的特别字段进行初始化工作,如对于接口变量必须设定引用记数值为0,对于动态数组则必须初始化内存区块.
下面的TMyObject声明了Variant类型的字段变量vDate,那么Object Pascal的对象模式会对 vDate进行特别的初始化工作,至于GetHashValue虚拟方法则会进入VMT(Virtual Method Table)之中.
TMyObject =class(TObject)
Private
  VDate :Variant;
Public
  Function GetHashValue:Integer; virtual;
  Destructor Destory;override;
End;

posted @ 2004-06-15 17:40 khan 阅读(682) 评论(1) 编辑

如何设计和驱动多任务执行环境(摘抄自inside Vcl)

如何设计和驱动多任务执行环境

这一节描述,一个单任务的操作系统,以一个大型的循环(loop),不断的检查每一个应用程序是否触发了特定的事件,如鼠标,键盘。然后否定其运行效率及反应速度
( ?) 这里所说的事件驱动式操作系统是如何运作,是不是也由一个loop来检测机器的当前事件,然后将事件转化成消息(Message),然后分派给正确的应用程序来处理。

消息结构:
MyMessage = packed record
  Hwnd :HWND; //消息触发窗口句柄
  MessageID : Longint; //事件id
  wParam : Longint; // 封装事件额外信息
  lParam : Longint; // 封装事件额外信息
  time : Longint; //事件发生事件
  pt : TPont; //存储鼠标的全域坐标
end;

这节作者提出了3个问题
1. 应用程序可能拥有多个窗口,如何把触发的消息分派给正确的窗口区处理?
2. 把消息分派给应用程序或者窗口是如何办到的?
3. 分派了消息给窗口之后,窗口药如何处理此消息?

解答:
1.仔细看上面的消息结构MyMessage, 窗口句柄解决了第一个问题,由于句柄的唯一性.所以根据得到的消息触发窗口句柄,可以知道消息所对应的窗口.
我们的执行环境为每个应用程序建立一个消息队列(Message Queue),当事件发生时,执行环境久把代表他的消息分派到此消息队列中,等待应用程序从其中取出并处理.如此,程序就可以应付快速产生的数个事件而不会丢失消息.

2.窗口信息数据结构:
MyWindowClassInfo =packed record
  Style:UINT; //窗口的类型
  iWidth:integer; //窗口的宽
  iHeight:integer; //窗口的高
  lpfnWndProc:Pointer; //回调函数,窗体消息处理函数的指针
  hIcon:HICON;
  hCursor:HCURSOR; //窗口使用的光标种类
  hbrBackground:HBRUSH;//背景颜色
  lpszMenuName:PAnsiChar; //
  lpszClassName:PAnsiChar; //窗体类名
  hIconSm:HICON;
end;
当窗口发生事件并由执行环境转换为消息后,接下来就是要应用程序中对应的窗口来处理这个消息了,要让窗口处理消息最简单的方法就是让执行环境调用窗口提供的函数,并且传递消息给此函数来处理,但问题时要如何方窗口提供函数给执行环境,执行环境才能够知道在消息产生后要调用什么函数.
MyWindowClassInfo数据结构中有一个lpfnWndProc字段是一个Pointer类型的字段,代表应用程序可以把任何的函数地址指定给此字段以代表可以处理此窗口消息的函数.由于这个函数会有执行环境调用,这种函数也被称为回调函数(Callback Routine).
由于执行环境在调用应用程序提供的回调函数时必须传递和消息相关的信息给此函数,因此执行环境必须定义此函数的原型(Prototype):
function WindowProc(
  Window:HWnd; //窗口句柄
  AMessage:UNIT; //分派的消息
  Wparam:WPARAM;
  Lparam:LPARAM
): LRESULT;stdcall;export;

当应用程序遵照回调函数的原型,提供了适当的处理窗体消息函数并指定给MyWindowClassInfo中的lpfnWindProc字段,那么应用程序就可以在窗体事件触发后自动调用这个回调函数来处理消息了

3.这个问题由如下源代码实现:
case AMessage of
  WM_PAINT //窗体重画
  .. .. ..
  WM_DESTROY//窗体销毁
  .. .. ..

posted @ 2004-06-15 17:37 khan 阅读(495) 评论(0) 编辑

RetroGuard的使用方法(转)

RetroGuard的使用方法:

RetroGuard是一个很不错的Java混淆器,而且在JBuilder7的企业版中也带了这个混淆器。
RetroGuard本身是一个Java程序(一个Jar包),所以要使用的话必须先安装JDK。运行前需要设置一些环境变量,除了要在PATH中包含java的执行路径以外,还要在CLASSPATH中加入D:\retroguard\RetroGuard.jar(假设你的RetroGuard.jar在D:\retroguard下)。如果没有设置CLASSPATH的话也不要紧,只不过每次运行时就要通过 -classpath 加上路径参数。设置好运行环境以后还要准备好你要混淆的.jar文件包,至于如何把编译好的类打包成.jar文件就不在这里多说了。
RetroGuard的执行格式是:
java RetroGuard [输入JAR文件 [输出JAR文件 [“保留脚本文件” [日志文件]]

其中“保留脚本文件”描述了那些类、函数、变量名必须保留,不能被混淆;日志文件是执行后生成的记录文件,记录的错误、混淆情况等信息。
对于“保留脚本文件”可以通过一个图形界面RGgui来设置,执行命令是:
java RGgui
运行后,可以根据提示选择输入Jar文件,选择要保留的类、函数、变量,完成后会自动生成“保留脚本文件”。其实通常情况下只要保留运行的起始类名称就可以了。
如果你的Jar包用到了第三方的函数库,比如Siemens的API,那么就要在 -classpath 参数中指定。例如:
java -classpath c:\siemens\smtk\6688i1_b8\lib\api.jar RetroGuard in.jar out.jar script.txt log.txt

如果RetroGuard混淆失败,可以查看日志文件取得错误信息。
这里我发现一个问题,就是遇到有类似 ...$$1.class 这样的文件,RetroGuard会提示出错,后来我修改了他的源代码,直接跳过了对这种文件的处理。

JBuilder7中RetroGuard的设置和用法:
JBuilder7的企业版中带了RetroGuard v1.1,再JBuilder7安装路径下的retroguard-v1.1目录中。在JBuilder7中可以直接调用RetroGuard。设置的方法如下:
点菜单Tools -> Configure Obfuscators配置混淆器,点左下角的New...新建一个混淆器,选择RetroGuard的路径,完成配置。使用起来要通过Archive Builder,点菜单Wizards -> Archive Builder...,Archive type选择MIDlet(这里仅仅介绍针对J2ME应用),然后根据提示一步一步往下设置,到达第9步也就是混淆器设置的时候,选中obfuscate the contents of the archive,Obfuscator选择混淆器,Use the classes specified blow下面添加要保留的类(默认保留起始执行类),结束设置。
这样当每次编译的时候,就会自动生成混淆过的Jar文件包了

posted @ 2004-06-15 17:34 khan 阅读(1065) 评论(0) 编辑

写了一些java的字符处理函数,可能对大家有些用

/**将一串以空格分隔并以空格结尾的字符串转换为字符串数
*@param s 以空格分隔并以空格结尾的字符串
*@return String[] 字符串数组 */
private
 String[] StringToArray(String s) {
    String[] strs = new String[StringCount(s,' ')];
    String tmp = s;
    for (int i = 0; i < strs.length; i++) {
        strs[i] = tmp.substring(0, tmp.indexOf(" "));
        tmp = tmp.substring(tmp.indexOf(" ") + 1);
    }
    return strs;
}






/**
 统计以空格分隔并以空格结尾的字符串转换为字符串数组中的字段个数
*@param s 以空格分隔并以空格结尾的字符串
*@param cut 分割字符标记
*@return int 字段个数 */
private
 int StringCount(String s,char cut) {
    int j = 0;
    for (int i = 0; i < s.length(); i++) {
        if (s.charAt(i) == cut)
        j++;
    }
    return j;
}





/**
替换空格分割的字符串中第index个子串
*@param str 字符串
*@param index 索引
*@param subString 用来替换的的子串 
*@return String 替换后的字符串 */
private
 String replaceStr(String str, int index, String subString) {
    if (index < 61)
        return str.substring(0, pos(str, index, ' ')) + " " + subString + str.substring(pos(str, index + 1, ' '), str.length());
    else
        return str.substring(0, pos(str, index, ' ')) + " " + subString;
}



/**
返回某字符串中,indexcut实际所在的实际位置
*@param str 源字符串
*@param index 分割标志所在序号
*@param cut 分割字符 
*@return int 位置 */
private
 int pos(String str, int index, char cut) {
    int i = 0, j = -1, tmp = -1;
    while (i < str.length()) {
        i = str.indexOf(cut, i + 1);
        tmp = i;
        if (i != -1) j++;
        else break;
        if (j == index)break;
    }
    return tmp;
}

posted @ 2004-06-15 17:32 khan 阅读(913) 评论(0) 编辑

导航

<2012年2月>
2930311234
567891011
12131415161718
19202122232425
26272829123
45678910

公告

昵称:khan
园龄:7年7个月
粉丝:0
关注:0

搜索

 
 

常用链接

随笔档案

相册

khan的链接

最新评论

阅读排行榜

评论排行榜

推荐排行榜