占位手记 (0分)

  • 主题发起人 小雨哥
  • 开始时间

小雨哥

Unregistered / Unconfirmed
GUEST, unregistred user!
本贴是一个占位手记,没有十分的必要,请勿跟贴。
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
在 Windows 2000 中,有一个函数是 NtQuerySystemInformation :
NtQuerySystemInformation 是 Windows 系统的内部函数,由它可以得到许多种类的系统
信息。这个函数在 Windows 的未来版本中可能会有改变或被替代。
微软在自己的网站上贴出的函数原型如下:
NTSTATUS NtQuerySystemInformation(
SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength);
翻译成 Delphi 语法大概是这样吧:
function NtQuerySystemInformation(
SystemInformationClass:DWord;
// 这个参数最终根据需要取得的信息而变
SystemInformation:pointer;
// 这个参数指向接收取来的信息的缓存结构
SystemInformationLength:DWord;
// 这个参数指出上面这个缓存结构的大小
ReturnLength:DWord):DWord;stdcall;
// 这个参数指出实际返回的数据的大小
于是可以在 Delphi 程序中使用下面的语法调用这个函数:
function NtQuerySystemInformation;
external 'NTdll.dll' name 'NtQuerySystemInformation';
这个函数的参数变化实在太多,对每个参数都一一作类型声明的话,会很累的,还不如在想用它的时候,
直接用合适的值代进去拉倒。
在这个 DLL 中,获取相关的信息的函数还有很多,可以使用 PE View 工具看它的 Export 段,比如:
NtQueryInformationProcess
NtQueryInformationThread
等等。这些函数当前应该可以在 Windows 2000 和 Windows XP 中使用。
 
在 DFW 上我发现和认识了很多自称叫业余编程爱好者的高手。
什么是业余编程爱好者呢。我做了以下理解:
是指未从事商业性编程工作,所从事的职业不使用任何计算机语言,由于兴趣所致,独立地、
自发性地参与编程研究的个人。这之中包括在 IT 行业,但不从事代码分析或编写工作的人
员、计算机专业在读或毕业了,还未从业编程工作的人员、曾经有过商业编程经历,目前未从
事商业性编程工作的人员和其他不以编程为生活来源的各阶层人士。
如果这样,就难怪 DFW 上的所谓业余爱好者的水平如此之高了。
 
今天公布一个函数的使用,为方便网络编程的朋友给自己的程序获得洞查 internet 的连接
与否状态,以便为自动运行提供指示。QQ 不知道为什么没有使用这个函数,而 MSN 、ICQ
却早就在使用了。这个片段中,还是自己简单地声明了几个 Delphi 中没有函数和常量。
{***************************************************************
* Unit Name: Unit1
* Purpose : 象 MSN 一样检测网络是否连入 internet .
* Author : 小雨哥
* History : 启动后如果连接和退出 internet 都会提示
****************************************************************}
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
const
RASCN_Connection=1;
RASCN_Disconnection=2;
type
TForm1 = class(TForm)
Button1: TButton;
CheckBox1: TCheckBox;
procedure Button1Click(Sender: TObject);
private
procedure DiscOver(Sender: TObject);
procedure ConnOver(Sender: TObject);
procedure bntClose(Sender: TObject);
public
end;

TConnectCheckThread = class(TThread)
protected
procedure Execute;
override;
end;

TDisconnectCheckThread = class(TThread)
protected
procedure Execute;
override;
end;

function RasConnectionNotification(HAND:THANDLE;hEvent:THANDLE;dwFlags:DWORD):integer;stdcall;
function GetOnlineStatus : Boolean;
function WaitForConnectCheck:Boolean;
function WaitForDisconnectCheck:Boolean;
var
Form1: TForm1;
implementation
uses WinInet;
{$R *.DFM}
function RasConnectionNotification;
external 'RasAPI32.dll' name 'RasConnectionNotificationA';
function GetOnlineStatus:Boolean;
var ConTypes : Integer;
begin
ConTypes := INTERNET_CONNECTION_MODEM + INTERNET_CONNECTION_LAN + INTERNET_CONNECTION_PROXY;
if (InternetGetConnectedState(@ConTypes, 0) = False) then
Result := False
else
Result := True;
end;
function WaitForConnectCheck:Boolean;
var
SecuAttr:TSecurityAttributes;
hConnected:THANDLE;
Res:DWord;
begin
SecuAttr.nLength := SizeOf(SecuAttr);
SecuAttr.bInheritHandle:=False;
SecuAttr.lpSecurityDescriptor :=nil;
hConnected:=CreateEvent(@SecuAttr,True, False, 'Connect');
try
Res:=RasConnectionNotification(INVALID_HANDLE_VALUE,hConnected,RASCN_Connection);
if Res=0 then
begin
WaitForSingleObject(hConnected, INFINITE);
MessageBox(0,'检测到本机已经连入 Internet !','信息',MB_OK);
end
else
MessageBox(0,'Res<>0','信息',MB_OK);
finally
ResetEvent(hConnected);
Result := True;
end;
end;
function WaitForDisconnectCheck:Boolean;
var
SecuAttr:TSecurityAttributes;
hTerminated:THANDLE;
Res:DWord;
begin
SecuAttr.nLength := SizeOf(SecuAttr);
SecuAttr.bInheritHandle:=False;
SecuAttr.lpSecurityDescriptor :=nil;
hTerminated:=CreateEvent(@SecuAttr,True, False, 'Disconnect');
try
Res:=RasConnectionNotification(INVALID_HANDLE_VALUE,hTerminated,RASCN_Disconnection);
if Res=0 then
begin
WaitForSingleObject(hTerminated, INFINITE);
MessageBox(0,'检测到本机已经关闭了 Internet 连接!','信息',MB_OK);
end
else
MessageBox(0,'Res<>0','信息',MB_OK);
finally
ResetEvent(hTerminated);
Result := True;
end;

end;
procedure TForm1.bntClose(Sender: TObject);
begin
Close;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
CC:TConnectCheckThread;
DC:TDisconnectCheckThread;
begin
if GetOnlineStatus then
begin
DC:=TDisconnectCheckThread.Create(True);
DC.FreeOnTerminate :=True;
DC.Priority:=tpLower;
DC.OnTerminate:=DiscOver;
DC.Resume;
end
else
begin
CC:=TConnectCheckThread.Create(True);
CC.FreeOnTerminate :=True;
CC.Priority:=tpLower;
CC.OnTerminate :=ConnOver;
CC.Resume;
end;
SendMessage(Handle,WM_SysCommand,SC_Minimize,0);
Button1.OnClick:=bntClose;
Button1.Caption:='关闭';
end;
procedure TConnectCheckThread.Execute;
begin
WaitForConnectCheck;
end;
procedure TDisconnectCheckThread.Execute;
begin
WaitForDisconnectCheck;
end;
procedure TForm1.ConnOver(Sender: TObject);
var
DC:TDisconnectCheckThread;
begin
if CheckBox1.Checked then
begin
DC:=TDisconnectCheckThread.Create(True);
DC.FreeOnTerminate :=True;
DC.Priority:=tpLower;
DC.OnTerminate:=DiscOver;
DC.Resume;
end;
end;
procedure TForm1.DiscOver(Sender: TObject);
var
CC:TConnectCheckThread;
begin
if CheckBox1.Checked then
begin
CC:=TConnectCheckThread.Create(True);
CC.FreeOnTerminate :=True;
CC.Priority:=tpLower;
CC.OnTerminate :=ConnOver;
CC.Resume;
end;
end;
end.
这个代码实现了一个循环,正式使用可以根据自己的程序取舍。
 
exe 中的函数采用 dll 中的说明,就可以被 dll 调用,代码如下:
///////////////////////////////////////////////////////////////////////////////
// dll 中的代码:
///////////////////////////////////////////////////////////////////////////////
library dllProj;
uses
Windows, SysUtils, Classes;
type
TmyProc=function (msg:pChar):Boolean;
// {$R *.RES}
function testCalls(i:DWord):Boolean;
var
p:TmyProc;
begin
@p:=GetProcAddress(GetModuleHandle(nil),'TestExport');
if @p <> nil then
p(PChar('调用成功,返回变量是:'+intTostr(i)))
else
MessageBox(0,'调用 exe 内部例程没有成功','信息',MB_OK);
result:=true;
end;
exports
testCalls index 0 name 'testCalls';
begin
end.

///////////////////////////////////////////////////////////////////////////////
// exe 中的代码:
///////////////////////////////////////////////////////////////////////////////
unit exeUnit;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
end;
TTestProc=function(i:DWord):Boolean;
function TestExport(Msg:pChar):Boolean;
var
Form1: TForm1;
exports
TestExport name 'TestExport';
implementation
{$R *.DFM}
function TestExport(Msg: PChar): Boolean;
begin
MessageBox(0,Msg,'信息',MB_OK);
result:=true;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
theHandle:THandle;
MyProc:TTestProc;
begin
theHandle:=LoadLibrary('dllProj.dll');
if theHandle <> 0 then
begin
@MyProc := GetProcAddress(theHandle,'testCalls');
if @MyProc <> nil then
begin
MyProc(5);
FreeLibrary(theHandle);
end
else
MessageBox(0,'exe 在载入 dll 时失败','信息',MB_OK);
end;
end;
end.
 
非常好的帖子,收藏啦!
帮小雨哥up[:D][:D]
 
获取网页源代码的最简单办法,就是利用 WinInet 单元中的函数:
uses WinInet;
function GetWebPage(const Url: string):string;
var
Session,
HttpFile:HINTERNET;
szSizeBuffer:pointer;
dwLengthSizeBuffer:DWord;
dwReserved:DWord;
dwFileSize:DWord;
dwBytesRead:DWord;
Contents:pChar;
begin
Session:=InternetOpen('',0,niL,niL,0);
HttpFile:=InternetOpenUrl(Session,PChar(Url),niL,0,0,0);
dwLengthSizeBuffer:=1024;
HttpQueryInfo(HttpFile,5,szSizeBuffer,dwLengthSizeBuffer,dwReserved);
GetMem(Contents,dwFileSize);
InternetReadFile(HttpFile,Contents,dwFileSize,dwBytesRead);
InternetCloseHandle(HttpFile);
InternetCloseHandle(Session);
Result:=StrPas(Contents);
FreeMem(Contents);
end;
使用时,直接把收到的源代码显示出来:
Memo1.Text := GetWebPage('http://www.delphibbs.com/delphibbs/listq.asp');
哇,这个代码可以用,但没有初始化呀,怪,怎么就可以用了?
 
多谢小雨哥:)
 
beta: P 计划中你放 photo 的地方好象不太对头,我手脚算是比较快的,都没看到。:-(
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
喜爱 DFW 的一个重要原因,是这里的热情。比如发一个帖子,问如何搜索本地电脑上已打开
的端口,一般总会呼啦围上一群富翁,提出各自熟悉的领域的解决办法,但往往由于并不清
楚发贴人究竟想干什么,大多数回贴会有点隔靴搔痒,但确实令人大开眼界,从而看到问题
的许多方面。
有时候在努力解决一个问题时,确实只需要提个醒,就可以省掉许多摸地雷式的寻找一个特
定的 API 的时间,从而可以化更多的时间处理程序本身的算法。毕竟,程序真正体现优美的
还是蕴涵其中的智慧无限的算法啊,何必化很多时间在微软早就做好的 API 上呢?
不说废话了,看下面的 API 吧:
函数原型:
DWORD GetTcpTable(
PMIB_TCPTABLE pTcpTable, // TCP 连接表缓存
PDWORD pdwSize, // 缓存大小
BOOL bOrder // 排序与否
);
这个 API 可以获得当前电脑上全部的 TCP 连接信息(地址、端口、状态)。转为 Delphi 为:
function GetTcpTable(
pTcpTable:pMIB_TCPTable;
pdwSize:pDWORD;
bOrder:Boolean):DWORD;stdcall;
这个函数使用了一个 PMIB_TCPTable 的数据结构,它的 Delphi 定义如下:
PMIB_TCPTable=^TMIB_TCPTable;
TMIB_TCPTable = record
dwNumEntries:DWORD;
// 数组元素的个数
Table:array[1..1024] of TMIB_TCPRow;
// TCP 连接的数组
end;
这个结构的第二个元素的 Delphi 定义如下:
TMIB_TCPRow = record
dwState:DWORD;
// 连接状态
dwLocalAddr:DWORD;
// 本机地址
dwLocalPort:DWORD;
// 本机端口
dwRemoteAddr:DWORD;
// 远程地址
dwRemotePort:DWORD;
// 远程端口
end;
从中,我们可以看到这个函数的全部秘密了。
有关这个函数的例子代码和更多的信息,见 千中元 的网站(http://www.51google.net/)。
 
Windows NT、Windows 2000、Windows XP 都可以把程序做为服务启动。Delphi 也有向导
直接帮助建立服务应用程序。当一个服务应用程序被建立后,就可以使用服务安装功能安
装它。
一个服务应用程序,必须完成 2 个关键的函数,即:
StartServiceCtrlDispatcher 和 RegisterServiceCtrlHandler 后才能被系统做为服务启
动。当使用 Delphi 向导建立服务应用程序时,这 2 个函数是被封装了的,不需要做其他
的处理,但如果手工建立一个服务应用,就必须手工编写它。
StartServiceCtrlDispatcher 函数的目的是告诉系统,这个服务应用的入口主函数。系统
在启动服务时,就去执行这个函数指定的主入口函数,在主入口函数中,完成另一个函数的
调用 RegisterServiceCtrlHandler ,这个函数是注册一个应用服务控制函数,以便系统可
以控制这个服务应用。
安装一个服务应用是很简单的,代码如下:
-------------------------------------
function InstallService:Boolean;
var
schSCManager,schService:THANDLE;
strDir:array[0..1023]of char;
lpszBinaryPathName:pChar;
begin
schSCManager:=OpenSCManager(nil,nil,SC_MANAGER_ALL_ACCESS);

if schSCManager=0 then
begin
MessageBox(0,'联接服务控制管理器失败','Error',MB_OK);
Result:=false;
exit;
end;

GetCurrentDirectory(1024,strDir);
// 取到应用程序所在的目录
strlcat(strDir,'/ScvProject.exe',1024);
// 当前目录下的服务应用
lpszBinaryPathName:=strDir;
schService:=CreateService(
schSCManager, // 服务控制管理句柄
'MyService', // 服务名称 需要和 服务应用名 相同
'My Service Display Name', // 显示的服务名称
SERVICE_ALL_ACCESS, // 存取权利
SERVICE_WIN32_OWN_PROCESS, // 服务类型
SERVICE_DEMAND_START, // 启动类型
SERVICE_ERROR_NORMAL, // 错误控制类型
lpszBinaryPathName, // 服务程序
nil, // 组服务名称
nil, // 组标识
nil, // 依赖的服务
nil, // 启动服务帐号
nil);
// 启动服务口令
if schService = 0 then
begin
MessageBox(0,'无法建立指定的服务对象','Error',MB_OK);
Result:=false;
exit;
end;

CloseServiceHandle(schService);
MessageBox(0,'已经成功地安装了服务对象','信息',MB_OK);
Result:=true;
end;

删除一个服务的代码如下:
----------------------------------------------
function UnInstallService:Boolean;
var
schSCManager:THANDLE;
hService:SC_HANDLE;
begin
schSCManager:=OpenSCManager(nil,nil,SC_MANAGER_ALL_ACCESS);
if schSCManager=0 then
begin
MessageBox(0,'联接服务控制管理器失败','Error',MB_OK);
Result:=false;
exit;
end;

hService:=OpenService(schSCManager,'MyService',SERVICE_ALL_ACCESS);
if hService=0 then
begin
MessageBox(0,'联接服务数据库失败','Error',MB_OK);
Result:=false;
exit;
end;

if not DeleteService(hService) then
begin
MessageBox(0,'无法删除指定的服务对象','Error',MB_OK);
Result:=false;
exit;
end;

if not CloseServiceHandle(hService) then
begin
MessageBox(0,'无法关闭服务控制器数据库','Error',MB_OK);
Result:=false;
exit;
end
else
begin
MessageBox(0,'反安装服务成功','信息',MB_OK);
Result:=true;
end;
end;

注意使用这两个函数时,要 uses WinSvc 这个单元。这两个函数中,其中:
'MyService' 是用 Delphi 向导建立服务应用时在属性编辑器中的 ServiceStartName = 'MyService' ;
'/ScvProject.exe' 就是用 Delphi 向导建立的服务应用程序 ;
'My Service Display Name' 将显示在系统服务列表中。
 
//beta: P 计划中你放 photo 的地方好象不太对头,我手脚算是比较快的,都没看到。:-(
你没有看到怎么知道我放上去了?:)
 
这,,这,,这不是.... :-0 :)
原贴:http://www.delphibbs.com/delphibbs/dispq.asp?lid=825494
/////////////// 大富翁P计划 ///////////////////////
来自:beta, 时间:2002-2-10 15:34:00, ID:918396
呵呵,有意思,我 小beta 也来。(谁说戴墨镜就是流氓来着?)
http://xmophy.home.chinaren.com/photo/beta01.jpg
http://xmophy.home.chinaren.com/photo/beta02.jpg
http://xmophy.home.chinaren.com/photo/beta03.jpg
(按时间逆序排列,前两张可是在 漓江 照的喔)
雁孤行,可别忘了把我的也加进相夹哦:-)
///////////////////////////////////////////////////////
 
我不知道大家是不是常用 GetLastError 这个 API 来确定系统返回的错误消息的,在
MS 的 VC++ 工具里,有一个叫做 Error Lookup 的工具,可以将 GetLastError 这个
函数返回的错误代码,转换为文字。其实 GetLastError 是一个很好的调试函数,但
由于它返回的是一个代表错误号的数字,必须经过转换才能看明白。下面就用 Delphi
写一个转换这个函数返回的数字成文字的代码:
procedure ShowOsError(ErrID:DWord);
var
Buffer:pointer;
begin
GetMem(Buffer,1024);
FormatMessage(4352, nil,ErrID,LANG_SYSTEM_DEFAULT,@Buffer,0,nil);
messagebox(0,Buffer,'Error',MB_OK);
LocalFree(Longint(Buffer));
end;

这个 ErrID ,就是 GetLastError 执行后的值:
ErrID:=GetLastError;
比如内存分配不足的错误代码是 122 ,代入这段代码就可以看到信息了。
由于 FormatMessage 这个函数会对 Buffer 自动做大小处理,所以我们不能完全按照
Delphi 中的函数定义那样,将 Buffer 定义为 PChar ,而是定义为 Pointer ,不然
就不能正常地释放这个变量,或者需要使用转换代码去释放。但使用了指针的话,直接
用 LocalFree 这个 API 就可以释放掉这个变量了,以免内存泄漏。
把它做成工具,挂到 Delphi 的工具菜单里,我们就可以随时得到系统错误的正确信息了。
还有就是直接使用 Delphi 包装函数 SysErrorMessage(GetLastError) 如下:
MessageBox(0,PChar(SysErrorMessage(GetLastError)),'Error',MB_OK);
 
数据丢失( 详见:http://www.delphibbs.com/delphibbs/dispq.asp?lid=1646369 )
本贴丢失“计划任务”一篇,由于我没有留底稿,正在联系补贴,稍后补上。
另外,上面的一篇的 LocalFree 的使用是错误的,不想更正了,特此道歉。
 
记得有位富翁问如何真正清除掉 IE 的历史文件夹的内容( 即:清除 History 记录)。
前几天没时间回答,今天看到 DFW 数据丢失,再去找这个帖子,翻了 71 页都没找到,
实在没有耐心再找了,就在这个帖子下回答一下吧:
原贴中先天有问题
1.原贴的 IID_IUrlHistoryStg2 的 GUID 定义是错误的。
2.IUrlHistoryStg2 中的 ClearHistory 并没有正式实现。
3.STATURL 结构中有 2 个参数的定义方法不很妥当。
不知道那个帖子是不是还存在了,这里干脆把全部定义和实现都写在下面,方便大家使用:
===============================================================================
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Activex, Comobj, StdCtrls;
const
// GUID 定义:
IID_IEnumStatUrl : TGUID='{3C374A42-BAE4-11CF-BF7D-00AA006946EE}';
IID_IUrlHistoryStg: TGUID='{3C374A41-BAE4-11CF-BF7D-00AA006946EE}';
IID_IUrlHistoryStg2: TGUID='{AFA0DC11-C313-11d0-831A-00C04FD5AE38}';
IID_IURLHistoryNotify:TGUID='{BC40BEC1-C493-11d0-831B-00C04FD5AE38}';
CLSID_CUrlHistory: TGUID = '{3C374A40-BAE4-11CF-BF7D-00AA006946EE}';
type
// TSTATURL 数据结构:
PSTATURL=^TSTATURL;
STATURL = record
cbSize: DWORD;
// 结构的大小
pwcsUrl: Pointer;
// URL 是 PWideChar ,原贴定义为 DWord
pwcsTitle: Pointer;
// History 标题,原贴定义为 DWord
ftLastVisited: FILETIME;
ftLastUpdated: FILETIME;
ftExpires: FILETIME;
dwFlags: DWORD;
end;
TSTATURL=STATURL;
IEnumSTATURL = interface(IUnknown)
['{3C374A42-BAE4-11CF-BF7D-00AA006946EE}']
function Next(celt: Integer;
out elt;
pceltFetched: PLongint): HRESULT;
stdcall;
function Skip(celt: Longint): HRESULT;
stdcall;
function Reset: HResult;
stdcall;
function Clone(out ppenum: IEnumSTATURL): HResult;
stdcall;
function SetFilter(poszFilter: PWideChar;
dwFlags: DWORD): HResult;
stdcall;
end;

IUrlHistoryStg = interface(IUnknown)
['{3C374A41-BAE4-11CF-BF7D-00AA006946EE}']
function AddUrl(pocsUrl: PWideChar;
pocsTitle: PWideChar;
dwFlags: Integer):
HResult;
stdcall;
function DeleteUrl(pocsUrl: PWideChar;
dwFlags: Integer): HResult;
stdcall;
function QueryUrl(pocsUrl: PWideChar;
dwFlags: Integer;
var lpSTATURL:
STATURL): HResult;
stdcall;
function BindToObject(pocsUrl: PWideChar;
var riid: TIID;
out ppvOut:
Pointer): HResult;
stdcall;
function EnumUrls(out ppenum: IEnumSTATURL): HResult;
stdcall;
end;

IUrlHistoryStg2 = interface(IUrlHistoryStg)
['{AFA0DC11-C313-11d0-831A-00C04FD5AE38}']
function AddUrlAndNotify(pocsUrl: PWideChar;
pocsTitle: PWideChar;
dwFlags: Integer;
fWriteHistory: Integer;
var poctNotify: Pointer;
const punkISFolder: IUnknown): HResult;
stdcall;
function ClearHistory: HResult;
stdcall;
end;

IUrlHistoryNotify = interface(IOleCommandTarget)
['{BC40BEC1-C493-11d0-831B-00C04FD5AE38}']
end;

type
TForm1 = class(TForm)
Button1: TButton;
// Caption:='清除历史记录'
procedure Button1Click(Sender: TObject);
end;

var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
// 清除历史记录
var
UrlHistory: IUrlHistoryStg2;
Enum:IEnumSTATURL;
urlSTATURL:TSTATURL;
fetched:Longint;
P:pWideChar;
begin
// 初始化 STATURL 数据结构
ZeroMemory(@urlSTATURL,SizeOf(TSTATURL));
// 创建 IUrlHistoryStg2 实例
if CoCreateInstance(CLSID_CUrlHistory,nil,
CLSCTX_INPROC_SERVER,
IID_IUrlHistoryStg2,
UrlHistory)=1 then
begin
MessageBox(0,'IUrlHistoryStg2 没有创建','',MB_OK);
exit;
end;

// 获得枚举接口 -> IEnumSTATURL
if UrlHistory.EnumUrls(Enum)=1 then
MessageBox(0,'IEnumSTATURL 接口没有找到','',MB_OK);
// 找到一个,删除一个
while Enum.Next(1,urlSTATURL,@fetched)<>1do
begin
P:=urlSTATURL.pwcsUrl;
if UrlHistory.DeleteUrl(P,0)=1 then
begin
MessageBox(0,'删除出错','',MB_OK);
Break;
end;
end;

end;
end.
===============================================================================
这个枚举接口的使用有很典型的意义,在 MS 的 COM 对象中,有很多都定义了枚举内部元
素的接口,一般都有 Next 方法,具体的使用就是上面的样子。原贴中想用 IUrlHistoryStg2
的 ClearHistory 方法一劳永逸地清除掉历史记录,目前还没有被 MS 支持。
 
小雨哥:“占位手记”是什么?
 
to 秀:
“占位手记”只是个名称而已,不用深究,可以认为是小雨哥的编程手记或编程经验的总结,
小雨哥是个高手啊!而且人还热情,真好![:D]
 
==================================================================================
soul 说丢失了 2 天的数据,我看了看本贴中“计划任务”这篇果然没有了,所以向有保留本
贴的富翁要了过来,再次贴上。感谢 千中元 。
==================================================================================
计划任务是一个 COM服务程序,在 98 以前,计划任务可以在托盘里看到并被
停止,但在 2000 以后,它做为了一个服务在系统启动时就同时启动了。计划
任务可以通过编程建立或删除计划任务项目,可以编程调用和编辑已有项目的
计划内容,由于 Delphi 不直接支持计划任务的接口,所以必须手工自己转化
计划任务中用到的有关数据类型和接口声明,但是好在用 Delphi 编程的高手
如云,象这种转化头文件的烦琐工作,早就有人做好了,拿来用就是。
计划任务由以下接口组成:
ITaskScheduler : 这个接口是最先需要建立的,通过它可以给项目一个标题
ITask : 它继承自 IScheduledWorkItem 接口,当获得了前面一个
接口后,可以用这个接口实现一个计划任务项目的所有工
作。如设置执行的程序,安排起止时间等等。
IScheduledWorkItem :
IEnumWorkItems : 这个接口特意安排来列举当前所有的计划任务项目。
ITaskTrigger : 设置触发事件的接口。
建立 ITaskScheduler 接口很简单,只要使用 CoCreateInstance 这个 API 或者
Delphi 封装函数 CreateComObject 就可以建立它,但我在实际的编程中,发现使
用 Delphi 的封装函数居然并不是直接获取这个接口,先必须获取 IUnknown 然后
再使用 as 转换过去,这样不是很麻烦吗,所以我直接用:
var
TaskSch:ITaskScheduler;
begin
CoCreateInstance(CLSID_CTaskScheduler,
nil,
CLSCTX_INPROC_SERVER,
IID_ITaskScheduler,
TaskSch);
end;
来获得 ITaskScheduler 接口,一旦获得这个接口,就可以使用这个接口的一个方
法:ITaskScheduler.NewWorkItem 来建立一个新项目了。同时,它也返回一个 ITask
的接口给我们,为了将最终建立的项目保存为磁盘文件,必须利用系统的 IPersistFile
接口,这个接口中有保存和载入磁盘文件的方法。于是可以建立一个任务项目:
var
UnK:IUnknown;
Task:ITask;
Trig:ITaskTrigger;
PerFile:IPersistFile;
bgein
TaskSch.NewWorkItem('测试',CLSID_CTask,IID_ITask,Unk);
Task:=Unk as ITask;
Task.SetApplicationName('C:/Windows/Notepad.exe');
// 设置需要执行的程序
Task.SetComment('这是一个测试项目');
// 设置描述
// 获得 ITaskTrigger 接口
Task.CreateTrigger(NewTrigger,Trig);
// 初始化 TTaskTrigger 数据结构
ZeroMemory(@Trigger,SizeOf(TTaskTrigger));
// 设置具体的数值
with Triggerdo
begin
wbegin
Year:=2003;
wbegin
Month:=3;
wbegin
Day:=1;
cbTriggerSize:=SizeOf(TTaskTrigger);
wStartHour:=8;
TriggerType:= TASK_TIME_TRIGGER_DAILY;
Type_.Daily.DaysInterval:= 1;
end;

Trig.SetTrigger(@Trigger);
Task.QueryInterface(IID_IPersistFile,PerFile);
PerFile.Save(nil,true);
end;

取到转化好的头文件后,编程还是比较简单的,在实际编程中,我们会遇到 PChar 、
String 、WideChar 的问题,如果转换不当,就会有乱码。Delphi 提供给我们 2 个
封装函数:WideCharTOString 将 WideChar 转为 String
StringToWideChar 将 string 转为 WideChar
一般的,我们使用这样的方法进行转化:
var
Buff:array[0..1024] of WideChar;
TempStr:string;
FileName:string;
WChar:pWideChar;
begin
FileName:='C:/Windows/Notepad.exe';
// 从 OpenDlg 取到的文件名
WChar:=StringToWideChar(FileName,Buff,Length(FileName)+1);
// 转为 WideChar
TempStr:=WideCharTOString(WChar);
// 转为 string
end;
从中可以看到,我使用了 Buff 做中间转换,省掉了对 WChar 分配内存和释放内存的步
骤,不过,这样一来需要注意的是,WChar 指向的是 Buff 首地址,并没有自己的内存。
关于这个计划任务的头文件在 JDEI 项目组有免费下载,包括例子程序。
我在 http://www.51google.net/ 的 webANYwhere 下也放了头文件和我的一个演示程序。
 
小雨哥:
你有空帮我看看我的这个问题,谢谢!
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1649856
 
"大富翁P计划" 我看了老半天,也没有看到beta.[:(]雁孤行倒是发现了。[:)]
我倒是想帖,可是一没有数码相片,二没有地方上传,叫我怎么办?[:D]
to 小雨哥 兄: 您怎么找到这么些好东西的,我能不能请教一下?
好像比较狠,呵呵。我能不能用大富翁Points贿赂一下?[:)]
 
顶部