便便代码人生

关注技术, 偶尔动动手

Archive for the 'Delphi' Category

Delphi….

[原]关于Indy组件(Delphi)实现FTP上传断点续传的方法 (upload resume)

Posted by bianbian on 2008-01-15 09:00


本文Tags: , , ,

Indy不仅支持下载断点续传,也支持上载断点续传,而且不需要对Indy做出改造。
在Blues的blog,他提到可以“通过IDFTP得到服务端已经上传的部分的SIZE,然后通过文件流在本地建立剩余部分的临时文件,然后以APPEND方式上传,传完后删除临时文件,达到上传断点续传的效果”。原文在此:DELPHI ftp 上传断点续传的实现
我再仔细看了Indy的源码,发现不需要临时文件。可以对Blues的方法作出重大改进:
Put()方法第一个参数可以是TStream(实际上,如果是文件名的话Indy会建立Stream,然后再调用Stream的Put方法)。而且如果Append设为True的话,Indy不会去动Stream的Position:

  1. procedure TIdFTP.Put(const ASource: TStream; const ADestFile: string = '';
  2.  const AAppend: boolean = false);
  3. ...
  4. procedure TIdTCPConnection.WriteStream(AStream: TStream; const AAll: boolean = true;
  5.   const AWriteByteCount: Boolean = False; const ASize: Integer = 0);
  6. ...
  7.   if AAll then begin //bianbian注:如果Append,AAll是false
  8.     AStream.Position := 0;
  9.   end;
  10.   // This is copied to a local var because accessing .Size is very inefficient
  11.   if ASize = 0 then begin
  12.     LStreamEnd := AStream.Size;
  13.   end else begin
  14.     LStreamEnd := ASize + AStream.Position;
  15.   end;
  16.   LSize := LStreamEnd - AStream.Position;
  17. ...

也就是说,先把原文件的Stream Seek到Size位置,丢给Indy即可,实现也很简单:

  1. var
  2.   fs: TFileStream;
  3. ...
  4.   fs := TFileStream.Create(FullFileName, fmOpenRead or fmShareDenyWrite);
  5.   fs.Seek(size, 0); //偏移
  6.   FTP.Put(fs, ExtractFileName(FullFileName), True);
  7.   fs.Free;
标签: , , ,

遵守创作共用协议,转载请链接形式注明来自http://bianbian.org 做人要厚道

相关日志

Posted in Delphi, Technology | 1 Comment »

[唉]Delphi怎么没有三目运算符(也叫三元运算符)

Posted by bianbian on 2008-01-13 08:22


本文Tags: ,

虽然自己写了一个iif函数,还是有问题的:

  1. function iif(const bool: Boolean; const ifSucc, ifFail: Variant): Variant;
  2. begin
  3.   if bool then
  4.     Result := ifSucc
  5.   else
  6.     Result := ifFail;
  7. end;

问题是传进的参数事先是已经被计算出值了,就会导致问题:

1)重复计算。比如:如果bool为真,输出txt,否则在之前加几个空格再输出txt
iif(bool, txt, ' ' + txt);
如果bool为真,按三目运算的规则,' ' + txt 是不会执行到的。不过这里做参数,只能重复计算,效率比if else 低

2)避免不了某些会导致异常的代码
原因还是因为参数会事先计算。比如:如果是目录,输出0,否则输出文件最后修改时间:
iif(Isdir(PathFileName), 0, FileDateToDateTime(FileAge(PathFileName)));
如果PathFileName是目录,FileAge()函数会抛出异常。
按三目运算规则,异常的代码是不应该被执行到的;但这里作参数,一旦是个目录每次必定抛异常,还得改成if else

还没想到好的解决办法,难道用Callbak函数回调?太夸张了点。。。。汗。。。。。

标签: ,

遵守创作共用协议,转载请链接形式注明来自http://bianbian.org 做人要厚道

相关日志

Posted in Delphi, Technology | No Comments »

[原] TP-Link拨号/断开程序

Posted by bianbian on 2007-08-27 07:05


本文Tags: ,

万恶的南京电信好贵啊,,,,,我的套餐是一个月360小时,2M带宽,168元/月
路由器不可能一直联网,需要手动拨号。不过每次都连上192.168.1.1也太麻烦了。
于是写了个程序自动拨号、断开。程序启动就会连上路由器拨号,关闭的时候会断开连接。
tp_link.JPG
需要的朋友请下载(仅适用于TP-Link路由器):tp_link.zip

标签: ,

遵守创作共用协议,转载请链接形式注明来自http://bianbian.org 做人要厚道

相关日志

Posted in Delphi, Technology | No Comments »

[原] 改进的DOS命令输出重定向到文本框(TMemo)内

Posted by bianbian on 2007-08-17 02:44


本文Tags: , , ,

虽然是Delphi的,都是调用的WinAPI,C++也可参考。
原理就是管道(Pipe),自己的程序可以Create管道出来,让CreateProcess的子程序能继承自己程序里的管道,替代子程序的标准输入输出。
这样DOS程序对stdout输出的内容就输出到自己程序建立的管道里来了,也就能对其进行读取操作,从而完成重定向到文本框(实时显示)。

基本上Delphi世界里流行的都是DFW上的那个重定向代码,我进行了改进:
1)原来那个代码只能截取输出结果,但是没有换行的整理,要是直接Add到Memo里会杂乱不堪(因为循环取到的内容有可能含有 \r 或 \n,这时候直接Add就有了两行)。
我加上了换行符的处理,Add行的时候按实际的换行进行处理,这样和DOS窗口输出就一致了。
2)原来那个代码没有和Memo绑定,还得自己写Memo操作部分
我加上了Memo作为参数,这样直接调用就省事了。

使用的时候只要 CmdExecAndView(“命令”, memo) 即可。

下面是改进后的代码,欢迎交流:

  1. procedure CmdExecAndView(FileName: string; memo: TMemo);
  2.   procedure _AddInfo(mmInfo:TMemo; S: string; var line: string);
  3.   var
  4.     i, p: Integer;
  5.   begin
  6.     if mmInfo.Lines.Count > 800 then
  7.       mmInfo.Lines.Clear;
  8.     //去掉 \r
  9.     for i := 0 to Length(S) - 1 do
  10.       if S[i] = #13 then S[i] := ' ';
  11.     line := line + S;
  12.     // \n 断行
  13.     p := Pos(#10, line);
  14.     if p > 0 then
  15.     begin
  16.       // \n 前面的加入一行,后面的留到下次
  17.       mmInfo.Lines.Add(Copy(line, 1, p - 1));
  18.       line := Copy(line, p + 1, Length(line) - p);
  19.     end;
  20.   end;
  21. var
  22.   hReadPipe, hWritePipe: THandle;
  23.   si: STARTUPINFO;
  24.   lsa: SECURITY_ATTRIBUTES;
  25.   pi: PROCESS_INFORMATION;
  26.   cchReadBuffer: DWORD;
  27.   ph: PChar;
  28.   fname: PChar;
  29.   line: string;
  30. begin
  31.   fname := allocmem(1024);
  32.   ph := AllocMem(1024);
  33.   lsa.nLength := sizeof(SECURITY_ATTRIBUTES);
  34.   lsa.lpSecurityDescriptor := nil;
  35.   lsa.bInheritHandle := True;
  36.   if CreatePipe(hReadPipe, hWritePipe, @lsa, 0) = false then
  37.     Exit;
  38.   fillchar(si, sizeof(STARTUPINFO), 0);
  39.   si.cb := sizeof(STARTUPINFO);
  40.   si.dwFlags := (STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW);
  41.   si.wShowWindow := SW_HIDE;
  42.   si.hStdOutput := hWritePipe;
  43.   si.hStdError := hWritePipe;
  44.   StrPCopy(fname, FileName);
  45.   if CreateProcess(nil, fname, nil, nil, true, 0, nil, nil, si, pi) = False then
  46.   begin
  47.     FreeMem(ph);
  48.     FreeMem(fname);
  49.     Exit;
  50.   end;
  51.   CloseHandle(hWritePipe);
  52.   while (true) do
  53.   begin
  54.     if not PeekNamedPipe(hReadPipe, ph, 1, @cchReadBuffer, nil, nil) then break;
  55.     if cchReadBuffer <> 0 then
  56.     begin
  57.       if ReadFile(hReadPipe, ph^, 512, cchReadBuffer, nil) = false then break;
  58.       ph[cchReadbuffer] := chr(0);
  59.       _AddInfo(memo, ph, line);
  60.     end
  61.     else if (WaitForSingleObject(pi.hProcess, 0) = WAIT_OBJECT_0) then break;
  62.     Application.ProcessMessages;
  63.     Sleep(200);
  64.   end;
  65.   ph[cchReadBuffer] := chr(0);
  66.   _AddInfo(memo, ph, line);
  67.   CloseHandle(hReadPipe);
  68.   CloseHandle(pi.hThread);
  69.   CloseHandle(pi.hProcess);
  70.   FreeMem(ph);
  71.   FreeMem(fname);
  72. end;
标签: , , ,

遵守创作共用协议,转载请链接形式注明来自http://bianbian.org 做人要厚道

相关日志

Posted in Delphi, Technology | 3 Comments »

[原]用内嵌IE做软件界面的几点体会

Posted by bianbian on 2006-12-22 10:48


本文Tags: , , ,

做人要厚道,转载请用链接形式标明出处,谢谢合作。

内嵌IE做软件界面是比较方便和流行的,如.NET 2003的安装程序(好像2005也是,不太记得了)。主要是随便插入图片阿、字体阿什么的。不过因为是内嵌IE,保持了大部分IE的特性,但是这些特性稍不注意,在软件界面看起来却是BUG(或者换句话说,用户很明显地发觉这是个网页…)。比如.NET 2003的安装程序,右键点击会出现IE浏览网页时的右键菜单就是个BUG:
.NET 2003 setup
或者呢,按住Shift,点击网页内那些链接,会发现新开了个IE窗口显示,这样连存放的文件名也暴露了。

当然了,BUG还不仅如此:虽然这个主要的内嵌IE不支持文件拖入(会显示禁止drop的图标),但是安装时右上角不停变化的图片处其实也是个内嵌IE——这里Microsoft显然遗漏了禁止drop的处理——你用鼠标拖个htm文件过去,会发现是可以drop的(直接用PrintScreen截的,没有鼠标,不过能看到拖过去的htm图标),如图:
dotnet2003-2.JPG

那么针对这些问题,我说一下用内嵌IE做软件界面的几点体会:
(1)避免script error。(今天没有空,内容待补充,下同)
(2)去掉右键菜单。
(3)禁止拖入。
(4)禁止打开新窗口。
(5)往内嵌IE里写入数据。
(6)截获页面跳转执行相应的代码,换句话说就是和主程序交互。
(7)这点可能是Delphi 7特有的bug,Delphi自带的TWebBrowser不支持键盘:如回车键提交表单等。

标签: , , ,

遵守创作共用协议,转载请链接形式注明来自http://bianbian.org 做人要厚道

相关日志

Posted in Delphi, Technology | 3 Comments »

[原]Delphi调用ShellAPI删除整个目录(我觉得是最快的方法)

Posted by bianbian on 2006-09-16 03:28


本文Tags: ,

  1. var
  2.   S: string;
  3.   T: TSHFileOpStruct;
  4. begin
  5.     S := '目录名';
  6.     with T do
  7.     begin
  8.       Wnd := 0;
  9.       wFunc := FO_DELETE;
  10.       pFrom := PChar(S);
  11.       pTo := nil;
  12.       fFlags := FOF_ALLOWUNDO + FOF_NOCONFIRMATION + FOF_NOERRORUI;
  13.       //标志表明允许恢复,无须确认并不显示出错信息
  14.       hNameMappings := nil;
  15.       lpszProgressTitle := '正在删除文件夹';
  16.       fAnyOperationsAborted := False;
  17.     end;
  18.     SHFileOperation(T);
  19. end;
标签: ,

遵守创作共用协议,转载请链接形式注明来自http://bianbian.org 做人要厚道

相关日志

Posted in Delphi, Technology | No Comments »