DELPHI与移动设备编程问题!!!!(ActiveSync的连接状态)(200分)

  • 主题发起人 主题发起人 vclsaga
  • 开始时间 开始时间
V

vclsaga

Unregistered / Unconfirmed
GUEST, unregistred user!
问题同标题,我现在的程序能实现通过ActiveSync连接后将数据从移动设备中下载至PC,方法是,调用RAPI.DLL里的函数,代码如下:
type
{结构声明}
TRapiInit = record
cbSize:DWORD;
heRapiInit:THandle;
hrRapiInit:HResult;
end;
TForm1 = class(TForm)
RzBitBtn1: TRzBitBtn;
procedure RzBitBtn1Click(Sender: TObject);
private
{ Private declarations }
public
procedure CreateParams(var Params: TCreateParams);override;
{ Public declarations }
end;

var
Form1: TForm1;
{函数声明}
function copyFileFromDevice(LocalFile: string; RemoteFile: string):bool;
function CeRapiInit():integer; stdcall; external 'RAPI.DLL';
function CeRapiUninit():integer; stdcall; external 'RAPI.DLL';
function CeDeleteFile(local: WideString): Boolean;stdcall;external 'RAPI.DLL';
function CeRapiInitEx(var rapiinit: TRapiInit):Integer;stdcall;external 'RAPI.DLL';
function CeCreateFile(lpFileName: WideString; dwDesiredAccess: cardinal; dwShareMode: cardinal; lpSecurityAttributes: pSecurityAttributes; dwCreationDisposition: cardinal; dwFlagsAndAttributes: cardinal; hTemplateFile: cardinal):cardinal; stdcall;external 'RAPI.DLL';
function CeReadFile(hFile: cardinal;var lpBuffer; nNumberOfBytesToRead: cardinal; var lpNumberOfBytesRead: cardinal; lpOverlapped: poverlapped):bool; stdcall; external 'RAPI.DLL';
function CeWriteFile(hFile: cardinal;const lpBuffer; nNumberOfBytesToWrite: cardinal; var lpNumberOfBytesWritten: cardinal; lpOverlapped: poverlapped):bool; stdcall; external 'RAPI.DLL';
function CeCloseHandle(IntPtr: thandle):integer; stdcall; external 'RAPI.DLL';

{----------从移动设备复制文件到PC机中----------}
function copyFileFromDevice(LocalFile: string;RemoteFile: string):bool;
var
fs: TFileStream;
ahandle: thandle;
FTempBuffer: array[0..$1000] of byte;
nwrite,nRead: dword;
ini: integer;
begin
result := true;
ini := CeRapiInit();
if (ini<>0) then
begin
exit;
end;
ahandle := CeCreateFile(RemoteFile, $80000000, 0, 0, 3, $80, 0);
if ahandle=-1 then
begin
//showmessage('在设备上创建文件失败!');
MessageBox(0,'下载文件失败,请检查设备是否正确连接!','提示:',MB_OK OR MB_ICONWARNING);
CeRapiUninit();
result := false;
exit;
end;

if fileexists(localfile) then
deletefile(localfile);
fs:=tfileStream.Create(localfile,fmCreate);
CeReadFile(ahandle,FtempBuffer,sizeof(fTempBuffer),nRead,0);
if nRead<=0 then
begin
MessageBox(0,'数据采集器中没有barcode.txt文件,无法导出!','错误提示:',MB_OK OR MB_ICONWARNING);
fs.Free;
CeRapiUninit();
Exit;
end;
while nRead>0 do
begin
fs.Write(fTempBuffer,nRead);
if not CeReadFile(ahandle,FtempBuffer,sizeof(fTempBuffer),nRead,0) then
begin
result:=false;
break;
end;
end;
CeCloseHandle(ahandle);
fs.Free;
CeRapiUninit();
end;

procedure TForm1.RzBitBtn1Click(Sender: TObject);
var
ri: TRapiInit;
hRes: HRESULT;
dwRet: DWORD;
fpath, f: string;
sa: SECURITY_ATTRIBUTES;
Msg: string;
begin
Msg := '1、请检查设备是否正确连接!'+#13+'2、系统中是否安装通讯软件Microsoft ActiveSync V4.5!';
fpath := 'C:/ShineJit/';
f := 'barcode.txt';
if not DirectoryExists(fpath) then
begin
sa.nLength := SizeOf(sa);
sa.lpSecurityDescriptor := 0;
sa.bInheritHandle := True;
CreateDirectory(PChar(fpath),sa.lpSecurityDescriptor);
end;
ri.cbSize := sizeof(ri);
hRes := CeRapiInitEx(ri);
dwRet := WaitForSingleObject(ri.heRapiInit, 2000);
if ((dwRet <> WAIT_OBJECT_0) or (SUCCEEDED(ri.hrRapiInit) = FALSE)) then
begin
// Could not initialize Rapi
MessageBox(0,PChar(Msg),'导出失败:',MB_OK OR MB_ICONWARNING);
CeRapiUninit;
Exit;
end;
if copyFileFromDevice(fpath+'barcode.txt','barcode.txt') and CeDeleteFile(f) then
MessageBox(Handle,'数据下载成功!','提示:',MB_OK OR MB_ICONINFORMATION);
end;

现提出问题是,我在连接设备后,程序如何判断出设备是处于连接状态还是断开状态?
查了相关资料有个方法是ActiveSync连接后发送一个消息WM_NETCONNECT,参数WParams=0,但我如何能够利用我的程序截取该消息,然后判断出ActiveSync的工作状态?
谢谢各位了!!!!
 
自己顶一下!!!!
 
在线急等!!!!!各位高手!!!!!
 
帮顶。。。楼主挺强,用delphi做和ppc通信的事
 
你看看这个资料
使用PnP通知
使用PnP通知


在一个即插即用(PnP)的环境里,驱动程序和应用程序需要对机器里的设备配置的变化作出反应。例如,一个应用程序需要知道何时感兴趣的设备已经被添加到机器上,而一个驱动程序需要知道何时一个变化发生在一个特定的设备上。

当特定的PnP事件发生时,PnP管理器提供一个机制来通知驱动程序和应用程序。。本章描述了在内核模式代码里怎样使用PnP通知。用户模式应用程序的编写者应该看平台SDK文档获得关于RegisterDeviceNotification功能和相关的功能的信息。

本章包括以下的主题:

1.1 PnP通知总览

1.2 编写PnP通知回调例程指南

1.3 使用PnP设备接口改变通知

1.4 使用PnP目标设备改变通知

1.5 使用PnP硬件profile改变通知

1.6 使用PnP定制通知

参见《Windows2000驱动程序开发参考》的卷一获得当一个设备的电源状态变化时关于使用PoRegisterDeviceNotify来为通知注册。为了了解系统状态、时间和策略变化的通知的有关内容,请看内核模式驱动程序设计指南里有关系统定义的回调的信息。

1.1 PnP通知总览
当特定的事件发生在指定的设备上或者在整个系统上时,PnP管理器提供一个机制来通知的驱动程序和应用程序。一个驱动程序能够为下面种类的事件的通知而注册。

n EventCategoryInterfaceChange

当一个驱动程序为设备接口上这个种类的事件而注册时,PnP管理器通知驱动程序下面的事件:

n GUID_DEVICE_INTERFACE_ARRIVAL

表明一个特定类的设备接口已经启用。例如,一个用户给机器添加一个新的硬盘和卷管理器使一个新的卷可用(类“卷”的一个设备接口)。

n GUID_DEVICE_INTERFACE_REMOVAL

表明指定类的一个设备接口已经被禁止。

在《Windows2000驱动程序开发参考》的卷一中参看IoRegisterDeviceInterface和相关的例程获得设备接口的更多信息。

n EventCategoryTargetDeviceChange

当一个驱动程序为设备上这类事件注册时,当在设备上发生下面的事件时,PnP管理器通知驱动程序:

n GUID_TARGET_DEVICE_QUERY_REMOVE

表明PnP管理器准备删除设备的驱动程序。几种操作能够引起这个事件,包括一个用户请求从机器上删除指定的设备,或者一个用户发布设备的一个更新驱动程序请求。这个通知请求设备的驱动程序或者支持或者否决到来的删除操作。

n GUID_TARGET_DEVICE_REMOVE_COMPLETE

表明指定的设备已经从机器中删除,或者一个用户正在改变设备的驱动程序。

n GUID_TARGET_DEVICE_REMOVE_CANCELLED

表明指定的设备上的一个到来的删除操作已经被取消。

n GUID_Xxx(定制事件)

表明一个定制事件已经发生在一个指定的设备上。

你能够定义设备的一个定制事件。当驱动程序(或另外的相关组件)通知PnP管理器定制事件已经发生时,PnP管理器通知设备上为目标设备的改变通知而注册的任何组件。

不象设备接口的改变的注册过程,它可被认为是设备接口里一个“被动的”权利,而为目标设备的改变的注册表明设备里一个“主动的”权利。

n EventCategoryHardwareProfileChange

本类包括下面的事件:

n GUID_HWPROFILE_QUERY_CHANGE

表明一个用户已经请求改变机器的硬件profile。PnP管理器使用这个通知询问已注册的组件,是否它能够改变硬件profile而没有中断系统操作。已注册的组件典型地使这些查询请求成功。

n GUID_HWPROFILE_CHANGE_COMPLETE

表明一个机器的硬件profile已经改变。如果一个驱动程序维护profile专用的设置,它应该在一个硬件profile改变之后更新这些设置。

n GUID_HWPROFILE_CHANGE_CANCELLED

表明一个到来的硬件profile改变已经被取消。

为了内核模式组件,PnP通知如下工作:

1. 通过调用IoRegisterPlugPlayNotification,驱动程序注册一个种类事件的通知。

一个PnP通知的回调例程保留被注册状态直到驱动程序明确地删除注册。

2. 当已注册的种类里有一个事件发生时,PnP管理器调用驱动程序的回调例程。

3. 驱动程序通过调用IoUnregisterPlugPlayNotification删除回调注册。

对一个驱动程序来说,在一个关闭的过程中生成一个同步事件或者等待一个同步事件是非法的。

为获得PnP通知的更多信息,看本章里下面的部分:

1.1 编写PnP通知回调例程指南

1.2 使用PnP设备接口改变通知

1.3 使用PnP目标设备改变通知

1.4 使用PnP硬件profile改变通知

1.5 使用PnP定制通知

1.2 编写PnP通知回调例程的指南
PnP管理器在IRQL PASSIVE_LEVEL上调用通知回调例程。

为保证PnP子系统的平稳操作,一个PnP通知回调例程必须遵循下面的指南:

1. 一个通知回调例程不能够阻塞。

2. 一个通知回调例程不能够调用、或者引起对同步例程或任何例程的调用。在这里,同步例程生成PnP事件;这些任何例程则阻塞了等待设备安装或删除。

在一个通知回调过程中调用这样的例程能够引起系统死锁。

举个例子,一个驱动程序不能够在一个通知回调例程里调用IoReportTargetDeviceChange,相反,它应该调用IoReportTargetDeviceChangeAsynchronous。

3. 一个通知回调例程应该为它没有明确失效的任何事件返回成功状态。

当一个驱动程序为一个事件种类上的通知注册时,PnP管理器通知驱动程序那个种类里的所有事件,包括当前的和将来的。如果一个驱动程序为它没有处理的事件返回一个错误状态,驱动程序因错误而将冒险使一个新的查询事件失效。

例如,当驱动程序使一个查询通知失效而否决正被处理的事件时,一个驱动程序正确地返回一个错误状态。

4. 一个通知回调例程应该是可分页的代码。

1.3 使用PnP设备接口改变通知
一个驱动程序为EventCategoryDeviceInterfaceChange通知而注册,以便当机器上一个特别类的设备接口到达(可用的)或者被删除(不能用的)时,它能够被通知。例如,一个合成的电池驱动程序可能为电池类的设备接口的通知来注册,这样它就能够提供完整可用的电池电力信息给操作系统。

下面的子部分讨论怎样注册设备接口的改变通知和怎样在一个PnP通知回调例程里处理设备接口改变事件。

在《Windows2000驱动程序开发参考》的卷一中参看IoRegisterDeviceInterface和相关的例程,来获得设备接口的有关信息。

1.3.1 为设备接口改变通知注册
通过调用IoRegisterPlugPlayNotification,一个驱动程序为设备接口的到达和删除事件的通知注册。

在Windows2000驱动程序开发参考的卷一中参看IoRegisterPlugPlayNotification获得关于调用例程的总体信息,下面的信息应用于设备接口改变通知而调用这个例程:

n 指定EventCategoryDeviceInterfaceChange的一个EventCategory。

n EventCategoryData必须指向设备接口类的GUID。

一个接口类的GUID在典型情况下带有支持接口的结构、常数等等的头文件里被定义。

n 指定PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES的一个EventCategoryFlags。

这个标记指示PnP管理器,为指定类的设备接口在将来的到达和离开而注册回调例程,并立即为已经运行的相关设备接口调用回调例程。

一个驱动程序能够调用IoGetDeviceInterfaces来得到一个特定类存在的接口的一个列表,然后注册它的回调例程而不用这个标记,但是使用标记变得更容易,且避免了潜在的时钟问题。

n 指定一个驱动程序定义的环境,如果适当的话,PnP管理器将传递它给回调例程。

打开一个设备的句柄来响应设备接口的到达通知的驱动程序,将在设备上为EventCategoryTargetDeviceChange事件注册。(参见4.4节。)

一个驱动程序通过用由IoRegisterPlugPlayNotification返回的NotificationEntry调用IoUnregisterPlugPlayNotification来取消通知注册。

1.3.2 处理设备接口改变事件
当一个驱动程序或者一个用户模式组件能够允许或者禁止一个设备接口,PnP管理器调用设备接口类上为EventCategoryDeviceInterfaceChange注册的任何通知回调例程。PnP管理器指定GUID_DEVICE_INTERFACE_ARRIVAL或GUID_DEVICE_INTERFACE_REMOVAL的一个NotificationStructrue.Event。

当处理一个GUID_DEVICE_INTERFACE_ARRIVAL事件时,为了处理新的接口,一个通知回调例程应该执行驱动程序定义的任务。

例如,一个回调例程可能排队一个工作者例程来打开设备。一个回调例程不必直接打开设备。如果接口的提供者引起了阻塞PnP事件,且如果通知回调例程在回调线程里试图打开设备时,它能够引起一个锁死。

一个回调例程可能使它自己的一个设备接口能够响应新设备接口的可用性。

当处理一个GUID_DEVICE_INTERFACE_REMOVAL事件时,当接口启用时,一个通知回调例程应该取消它执行的任何操作。

1.4 使用PnP目标设备改变通知
一个驱动程序在一个设备上为EventCategoryTargetDeviceChange通知而注册,这样当驱动程序将要被删除时,驱动程序能够被通知。例如,如果一个驱动打开设备的一个句柄,驱动程序应该在一个设备上为EventCategoryTargetDeviceChange通知而注册,这样当PnP管理器需要删除设备时,驱动程序能够关闭它的句柄。

驱动程序也能够为定制通知使用EventCategoryTargetDeviceChange通知。(参见4.6节)

下面的子部分讨论了怎样注册目标设备的改变通知,和怎样在一个PnP通知回调例程里处理目标设备改变事件。

4.4.1 注册目标设备改变通知

4.4.2 处理一个GUID_TARGET_DEVICE_QUERY_REMOVE事件

4.4.3 处理一个GUID_TARGET_DEVICE_REMOVE_COMPLETE事件

4.4.4 处理一个GUID_TARGET_DEVICE_REMOVE_CANCELLED事件

参见第3章当PnP管理器发送删除IRP给一个设备的驱动程序时,启动、停止和删除设备的有关描述。

1.4.1 注册目标设备改变通知
通过调用IoRegisterPlugPlayNotification,一个驱动程序注册了目标设备改变事件的通知。

在《Windows2000驱动程序开发参考》的卷一中阅读IoRegisterPlugPlayNotification 获得调用例程的总体信息。下面的信息应用于目标设备改变通知的调用例程:

n 指定EventCategoryTargetDeviceChange的一个EventCategory。

n EventCategoryData必须为了设备指向文件对象,在这个设备上通知被请求。

如果驱动程序的回调例程需要访问文件对象,驱动程序应该在调用IoRegisterPlugPlayNotification之前删除文件对象上的一个引用。

如果驱动程序的回调例程不需要访问文件对象,驱动程序不许要引用该对象。

在文件对象关闭之后,驱动程序继续为设备接收通知直到驱动程序删除它的通知注册。举个例子,这个设计允许驱动程序接收GUID_TARGET_DEVICE_REMOVE_CANCELLED事件的通知。

n 指定一个驱动程序定义的、PnP管理器将传递给回调例程的环境。

一个驱动程序可能使用环境参数来维护文件对象当前的状态信息(如是否它已经被关闭/删除)。

一个驱动程序也可能使用环境来存储它最初用来打开设备的路径。在一个取消的删除操作之后,一个驱动程序能够使用这个例程重新打开设备。(参见4.4.4节获得更多信息。)

一个驱动程序通过用由IoRegisterPlugPlayNotification返回的NotificationEntry调用IoUnregisterPlugPlayNotification来删除一个通知注册。如果过去当驱动程序为通知注册时已经删除文件对象上的一个引用,且该引用仍旧未完成,驱动程序必须在它删除注册表之后释放引用。

1.4.2 处理一个GUID_TARGET_DEVICE_QUERY_REMOVE事件
在PnP管理器给一个设备的驱动程序发送一个IRP_MN_QUERY_REMOVE_DEVICE IRP之前,它调用设备上为EventCategoryTargetDeviceChange而注册的任何通知回调例程。PnP管理器指定GUID_TARGET_DEVICE_QUERY_REMOVE的一个NotificationStructrue.Event。

作为这样的一个通知的响应,回调例程决定设备是否可被删除而没有中断系统。

如果不应该删除设备,回调例程返回STATUS_SUCCESSFUL。为响应这个状态,PnP管理器放弃查询删除处理,且设备不会被删除。

如果能够被删除设备,回调例程应该执行任何适当的操作来准备删除设备,如关闭设备上的任何句柄打开(如果可能的话)。如果在设备上句柄维持打开状态,PnP管理器不能够删除设备并放弃查询删除处理。

当成功地处理一个GUID_TARGET_DEVICE_QUERY_REMOVE事件时,一个通知回调例程应该:

n 关闭设备的任何打开句柄。

n 如果驱动程序在文件对象上有一个未完成的引用,间接访问文件对象。

n 保留将来的EventCategoryTargetDeviceChange通知的注册状态,由于到来的删除操作也许会取消,所以这是重要的。

关闭设备的一个句柄没有取消为PnP目标设备改变通知而注册一个驱动程序。PnP管理器仍旧能够调用驱动程序的通知回调例程,但是在这样的调用里,在NotificationStructure里的文件对象是不合法的。

1.4.3 处理一个GUID_TARGET_DEVICE_REMOVE_COMPLETE事件
PnP管理器在给一个设备的驱动程序发送IRP_MN_REMOVE_DEVICE IRP之前,它调用设备上为EventCategoryTargetDeviceChange注册的任何内核模式通知回调例程。PnP管理器指定GUID_TARGET_DEVICE_REMOVE_COMPLETE的一个NotificationStructrue.Event。

当处理一个GUID_TARGET_DEVICE_REMOVE_COMPLETE事件时,一个通知回调例程应该:

n 删除设备上的通知注册。

设备已经删除,这样驱动程序调用IoUnregisterPlugPlayNotification来删除通知注册。

机器中设备可能仍旧物理地存在,但是所有的设备对象已经被删除,且设备是不可用的。

n 如果驱动程序没有接收到一个从前的查询删除通知时,执行突然删除处理。

如果一个驱动程序是突然的删除,PnP管理器给已注册的驱动程序发送一个删除完成通知而不必有一个先前的查询删除通知。在这种状况下,一个驱动程序必须执行任何必要的清除,如关闭设备的任何句柄并删除任何文件对象的未完成引用。

1.4.4 处理一个GUID_TARGET_DEVICE_REMOVE_CANCELLED事件
如果一个IRP_MN_QUERY_REMOVE_DEVICE 请求失效,PnP管理器给设备的驱动程序发送一个IRP_MN_CANCEL_REMOVE_DEVICE IRP。在取消删除IRP成功完成之后,调用设备上为EventCategoryTargetDeviceChange注册的任何通知回调例程。PnP管理器指定一个GUID_TARGET_DEVICE_REMOVE_CANCELLED的NotificationStructrue.Event。

当处理一个GUID_TARGET_DEVICE_REMOVE_CANCELLED事件时,一个通知回调例程应该为目标设备通知注册。

由于驱动程序关闭了以前的注册句柄来响应查询删除通知,驱动程序必须打开一个新的句柄。驱动程序必须做下面的事情:

1. 用IoUnregisterPlugPlayNotification删除旧的注册。

2. 打开设备的一个新的句柄。

3. 用IoRegisterPlugPlayNotification为新的句柄上的通知而注册。

1.5 使用PnP硬件profile改变通知
一个驱动程序为EventCategoryTargetDeviceChange通知注册,以便当机器从一个硬件profile转变为另一个时驱动程序能够被通知,例如,当一个袖珍计算机被连接或断开连接时,一个驱动程序能够使用这个机制被通知。

下面的子部分讨论怎样注册硬件profile改变通知和怎样在一个PnP通知回调例程里处理硬件profile改变事件。

4.3.1 注册硬件profile改变通知

4.3.2 处理硬件profile改变事件



1.5.1 注册硬件profile改变通知
一个驱动程序通过调用IoRegisterPlugPlayNotification来注册硬件profile的改变通知。

在《Windows2000驱动程序开发参考》的卷一中参看IoRegisterPlugPlayNotification 获得调用例程的总体信息。下面的信息应用于为硬件profile改变通知而调用这个例程:

n 指定EventCategoryHardwareProfileChange的一个EventCategory。

n EventCategoryData必须为NULL。

n 指定一个驱动程序定义的环境,如果适当,PnP管理器将传递它给回调例程。

一个驱动程序通过用由IoRegisterPlugPlayNotification返回的NotificationEntry调用IoUnregisterPlugPlayNotification来删除通知注册。

1.5.2 处理硬件profile改变事件
在一个硬件profile改变的特定时间,PnP管理器调用为EventCategoryHardwareProfileChange而注册的回调例程:

n 在机器的硬件profile改变之前,PnP管理器调用已注册的通知回调例程,并指定GUID_HWPROFILE_QUERY_CHANGE的一个NotificationStructrue.Event。

n 在一个机器的硬件profile改变完成之后,PnP管理器调用已注册的通知回调例程,并指定GUID_HWPROFILE_CHANGE_COMPLETE的一个NotificationStructrue.Event。

n 如果机器的硬件profile改变取消,PnP管理器调用已注册的通知回调例程,并指定GUID_HWPROFILE_CHANGE_CANCELLED的一个NotificationStructrue.Event。

对一个GUID_HWPROFILE_QUERY_CHANGE事件,PnP管理器调用用户模式回调例程,然后调用内核模式回调例程。为响应一个GUID_HWPROFILE_QUERY_CHANGE事件,典型情况下,一个驱动程序的通知回调例程返回STATUS_SUCCESS。

对一个GUID_HWPROFILE_CHANGE_COMPLETE事件,PnP管理器调用内核模式回调例程,然后调用用户模式回调例程。为响应这样的一个事件,一个驱动程序的回调例程可能更新它的硬件profile专用设置。

对一个GUID_HWPROFILE_CHANGE_CANCELLED事件,PnP管理器调用内核模式回调例程,然后调用用户模式回调例程。为响应这样的一个事件,典型情况下,一个驱动程序的回调例程返回STATUS_SUCCESS。如果驱动程序执行任何操作来响应GUID_HWPROFILE_QUERY_CHANGE事件,驱动程序取消这些操作来响应取消事件。

1.6 使用PnP定制通知
通知能够使用目标设备改变通知机制的驱动程序设备上的定制事件。

程序编辑器定义了定制事件必须作下面的事情:

1. 为定制事件定义一个新的GUID。

用uuidgen或guidgen生成,在一个适当的头文件和文档里发布GUID。

2. 编写代码来触发定制事件。

在内核模式里,一个驱动程序用定制GUID和设备的一个PDO指针调用IoReportTargetDeviceChange,定制事件仅能够从内核模式被触发。

一个驱动程序编写者在一个如下的步骤里使用定制通知:

1. 驱动程序(或应用程序)为定制事件的通知注册。

在内核模式里,一个驱动程序调用IoRegisterPlugPlayNotification,并为设备上的一个EventCategoryTargetDeviceChange注册。

在用户模式里,一个应用程序注册使用RegisterDeviceNotification。参见SDK平台获得更多的信息。

2. 一个内核模式组件触发定制事件。

3. PnP管理器调用设备上已注册的通知例程。

它先调用被注册的用户模式回调例程,然后调用内核模式回调例程。

4. 当用户模式通知完成时,内核模式驱动程序通知回调例程响应该定制事件。

参看4.2节获得通知回调例程的总体指南,除过这些指南外,一个定制通知回调例程不必从回调例程线程内打开一个设备的句柄。
 
谢谢寻绎!!!!除了这个方法不知道还有没有更好的方法??????
 
参考
http://www.tech-archive.net/Archive/WindowsCE/microsoft.public.windowsce.embedded.vc/2005-11/msg00020.html
 
谢谢,tseug;这个网站我看了,但没有得到我想要的东西,我用C#找到了一个控件OpenNETCF.Desktop.Communication.DLL,里面有关于ActiveSync的一些操作事件,可以得到我想要的功能,也实现了功能,但是如果在给客户使用的时候就要安装.NET2.0环境了,很是麻烦,不知道各位高人有没有办法用DELPHI实现ActiveSync工作状态显示的功能!!!谢谢了!!!!
 
没找到?转一段

IDccManSink = interface(IUnknown)
['{A7B88840-A812-11CF-8011-00A0C90A8F78}']
function OnLogIpAddr(dwIpAddr: DWORD): HRESULT; stdcall;
function OnLogTerminated: HRESULT; stdcall;
function OnLogActive: HRESULT; stdcall;
function OnLogInactive: HRESULT; stdcall;
function OnLogAnswered: HRESULT; stdcall;
function OnLogListen: HRESULT; stdcall;
function OnLogDisconnection: HRESULT; stdcall;
function OnLogError: HRESULT; stdcall;
end;

IDccMan = interface(IUnknown)
['{A7B88841-A812-11CF-8011-00A0C90A8F78}']
function Advise(DccSink: IDccManSink; var pdwContext: DWORD):
HRESULT; stdcall;
function Unadvise(dwContext: DWORD): HRESULT; stdcall;
function ShowCommSettings: HRESULT; stdcall;
end;

TDccManSink = class(TInterfacedObject, IDccManSink)
public
function OnLogIpAddr(dwIpAddr: DWORD): HRESULT; stcall;
function OnLogTerminated: HRESULT; stdcall;
function OnLogActive: HRESULT; stdcall;
function OnLogInactive: HRESULT; stdcall;
function OnLogAnswered: HRESULT; stdcall;
function OnLogListen: HRESULT; stdcall;
function OnLogDisconnection: HRESULT; stdcall;
function OnLogError: HRESULT; stdcall;
end;

var
dccMan : IDccMan;
dccManSink : IDccManSink;
dccContext : DWORD;
begin
CoInitialize(nil);
dccMan := CreateComObject(CLSID_DccMan) as IDccMan;
dccManSink := TDccManSink.Create;
dccContext := 0;
dccMan.Advise(dccManSink, dccContext);
//...
dccMan.Unadvise(dccContext);
CoUninitialize;
end;
 
谢谢tseug!这段代码我在GOOGLE上也找到了,但是不会用,呵呵,好像是生成OCX控件的,如果你会的话方便指点一下,谢谢!!
 
哈哈,自己搞定!少后把源码帖上来!!!!
 
第一部分:创建一个单元文件,创建控件,不用多说大家都知道install component
我省略了......
unit AutoSink;

interface

uses
Windows, Classes, ActiveX, SysUtils, ComObj, Dialogs;

const
CLSID_DccMan : TGUID = '{499C0C20-A766-11cf-8011-00A0C90A8F78}';
IID_IDccMan : TGUID = '{A7B88841-A812-11cf-8011-00A0C90A8F78}';
IID_IDccManSink : TGUID = '{A7B88840-A812-11cf-8011-00A0C90A8F78}';

type
IDccManSink = interface(IUnknown)
['{A7B88840-A812-11cf-8011-00A0C90A8F78}']
function OnLogIpAddr(dwIpAddr : DWORD): HResult; stdcall;
function OnLogTerminated: HResult; stdcall;
function OnLogActive: HResult; stdcall;
function OnLogInactive: HResult; stdcall;
function OnLogAnswered: HResult; stdcall;
function OnLogListen: HResult; stdcall;
function OnLogDisconnection: HResult; stdcall;
function OnLogError: HResult; stdcall;
end;

LPDCCMANSINK = ^IDccManSink;
IDccMan = interface(IUnknown)
['{A7B88841-A812-11cf-8011-00A0C90A8F78}']
function Advise(pDccSink : LPDCCMANSINK; var pdwContext : DWORD): HResult; stdcall;
function Unadvise(dwContext : DWORD): HResult; stdcall;
function ShowCommSettings: HResult; stdcall;
function AutoconnectEnable: HResult; stdcall;
function AutoconnectDisable: HResult; stdcall;
function ConnectNow: HResult; stdcall;
function DisconnectNow: HResult; stdcall;
function SetIconDataTransferring: HResult; stdcall;
function SetIconNoDataTransferring: HResult; stdcall;
function SetIconError: HResult; stdcall;
end;
//LPDCCMAN = ^IDccMan;
{$M+}
{ Déclaration forward pour FOwner }
TDccMan = class;
{ Déclaration TDccEventSink }
TDccEventSink = class(TInterfacedObject, IUnknown, IDccManSink)
private
FNbRef : integer;
FOnLogEtat : string;
FOnLogIndex : integer;
FOwner : TDccMan;
public
{ IUnknown }
function QueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
{ IDccManSink}
function OnLogIpAddr(dwIpAddr : DWORD): HResult; stdcall;
function OnLogTerminated: HResult; stdcall;
function OnLogActive: HResult; stdcall;
function OnLogInactive: HResult; stdcall;
function OnLogAnswered: HResult; stdcall;
function OnLogListen: HResult; stdcall;
function OnLogDisconnection: HResult; stdcall;
function OnLogError: HResult; stdcall;

constructor Create(AOwner : TDccMan);
destructor Destroy; override;

function RehercheInterface(var p : LPDCCMANSINK) : HResult;
property OnLogEtat : string read FOnLogEtat stored '';
property OnLogIndex : integer read FOnLogIndex stored - 1;
published
//
end;
//pDccEventSink = ^TDccEventSink;
{ Déclaration TDccMan }
TDccMan = class
private
FIDccMan : IDccMan;
FdwContext : DWORD;
FDccSync : TDccEventSink;
FpIMS : LPDCCMANSINK;
FComLib : boolean;
FQI : boolean;
FAdvise : boolean;
FOnChange : TNotifyEvent;
procedure DoChange(Sender : TObject);
public
constructor Create;
destructor Destroy; override;
procedure Advise;
procedure Unadvise;
procedure ShowCommSettings;
function LitEtat : string;
function LitIndex : integer;
property ComLibOk : boolean read FComLib stored false;
property InterfaceOk : boolean read FQI stored false;
property NotificationOk : boolean read FAdvise stored false;
property Etat : string read LitEtat stored '';
property IndexOnLog : integer read LitIndex stored - 1;
published
property OnChange : TNotifyEvent read FOnChange write FOnChange;
end;

implementation
{ TDccMan implementation }

constructor TDccMan.Create;
var
hr : HRESULT;
begin
inherited Create;
CoInitialize(nil);
FComLib := false;
FQI := false;
FAdvise := false;
hr := CoCreateInstance(CLSID_DccMan, nil, CLSCTX_INPROC_SERVER or
CLSCTX_LOCAL_SERVER, IID_IDccMan, FIDccMan);
if SUCCEEDED(hr) then
begin
FComLib := true;
FDccSync := TDccEventSink.Create(Self);
hr := FDccSync.RehercheInterface(FpIMS);
if SUCCEEDED(hr) then FQI := true;
end;
end;

destructor TDccMan.Destroy;
begin
Unadvise;
if Assigned(FDccSync) then FDccSync.Free;
CoUninitialize;
inherited Destroy;
end;

procedure TDccMan.Advise;
var
hr : HRESULT;
begin
// apparemment on peut cumuler les appels
// si déjà Advise redonne l'état actuel (actif ou autre)
// peut être utile, mais le contexte a changé !!
if FQI and not FAdvise then
begin
hr := FIDccMan.Advise(FpIMS, FdwContext);
if SUCCEEDED(hr) then FAdvise := true;
end;
end;

procedure TDccMan.Unadvise;
begin
if FAdvise then
begin
FIDccMan.Unadvise(FdwContext);
FAdvise := false;
end;
end;

procedure TDccMan.ShowCommSettings;
begin
if FComLib then FIDccMan.ShowCommSettings;
end;

function TDccMan.LitEtat : string;
begin
if Assigned(FDccSync) then Result := FDccSync.FOnLogEtat
else Result := '';
end;

function TDccMan.LitIndex : integer;
begin
if Assigned(FDccSync) then Result := FDccSync.FOnLogIndex
else Result := - 1;
end;

procedure TDccMan.DoChange(Sender : TObject);
begin
if Assigned(FOnChange) then FOnChange(Self);
end;

{ TDccEventSink implementation }
constructor TDccEventSink.Create(AOwner : TDccMan);
begin
inherited Create;
FNbRef := 0;
FOwner := AOwner;
end;

destructor TDccEventSink.Destroy;
begin
_Release;
inherited Destroy;
end;

function TDccEventSink.QueryInterface(const IID: TGUID; out Obj): HRESULT;
begin
Result := E_NOINTERFACE;
if GetInterface(IID, Obj) then Result := S_OK;
end;

function TDccEventSink.RehercheInterface(var p : LPDCCMANSINK) : HResult;
begin
Result := QueryInterface(IID_IDccManSink, p);
end;

function TDccEventSink._AddRef: Integer;
begin
InterLockedIncrement(FNbRef);
{ FOnLogIndex := 200;
FOnLogEtat := Format('AddRef %d', [FNbRef]);
FOwner.DoChange(Self); }
Result := 2;
end;

function TDccEventSink._Release: Integer;
begin
InterLockedDecrement(FNbRef);
{ FOnLogIndex := 100;
FOnLogEtat := Format('Release %d', [FNbRef]);
FOwner.DoChange(Self); }
Result := 1;
end;

function TDccEventSink.OnLogIpAddr(dwIpAddr : DWORD): HResult;
begin
FOnLogIndex := 1;
FOnLogEtat := Format('IP Adress : %d.%d.%d.%d',
[dwIpAddr and $FF,
(dwIpAddr and $FF00) shr 8,
(dwIpAddr and $FF0000) shr 16,
dwIpAddr shr 24]);
FOwner.DoChange(Self);
Result := NO_ERROR;
end;

function TDccEventSink.OnLogTerminated: HResult;
begin
FOnLogIndex := 2;
FOnLogEtat := 'Closed';
FOwner.DoChange(Self);
Result := NO_ERROR;
end;

function TDccEventSink.OnLogActive: HResult;
begin
FOnLogIndex := 3;
FOnLogEtat := 'Active';
FOwner.DoChange(Self);
Result := NO_ERROR;
end;

function TDccEventSink.OnLogInActive: HResult;
begin
FOnLogIndex := 4;
FOnLogEtat := 'Inactive';
FOwner.DoChange(Self);
Result := NO_ERROR;
end;

function TDccEventSink.OnLogAnswered: HResult;
begin
FOnLogIndex := 5;
FOnLogEtat := 'Answer';
FOwner.DoChange(Self);
Result := NO_ERROR;
end;

function TDccEventSink.OnLogListen: HResult;
begin
FOnLogIndex := 6;
FOnLogEtat := 'Listen';
FOwner.DoChange(Self);
Result := NO_ERROR;
end;

function TDccEventSink.OnLogDisconnection: HResult;
begin
FOnLogIndex := 7;
FOnLogEtat := 'Disconnected';
FOwner.DoChange(Self);
Result := NO_ERROR;
end;

function TDccEventSink.OnLogError: HResult;
begin
FOnLogIndex := 8;
FOnLogEtat := 'Error';
FOwner.DoChange(Self);
Result := NO_ERROR;
end;

end.
 
第二部分,实例部分!很简单!
注:安装ACTIVESYNC软件,我使用的设备是SYMBOL MC1000;其它的移动设备应该都可以的!
unit Unit1;

interface

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

type
TRapiInit = record
cbSize:DWORD;
heRapiInit:THandle;
hrRapiInit:HResult;
end;
TForm1 = class(TForm)
RzBitBtn1: TButton;
Label1: TLabel;
procedure RzBitBtn1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
procedure CreateParams(var Params: TCreateParams);override;
procedure ChangeActif(Sender: TObject);
{ Public declarations }
end;

var
Form1: TForm1;
DccMan: TDccMan;
function copyFileFromDevice(LocalFile: string; RemoteFile: string):bool;
function CeRapiInit():integer; stdcall; external 'RAPI.DLL';
function CeRapiUninit():integer; stdcall; external 'RAPI.DLL';
function CeDeleteFile(local: WideString): Boolean;stdcall;external 'RAPI.DLL';
function CeRapiInitEx(var rapiinit: TRapiInit):Integer;stdcall;external 'RAPI.DLL';
function CeCreateFile(lpFileName: WideString; dwDesiredAccess: cardinal; dwShareMode: cardinal; lpSecurityAttributes: pSecurityAttributes; dwCreationDisposition: cardinal; dwFlagsAndAttributes: cardinal; hTemplateFile: cardinal):cardinal; stdcall;external 'RAPI.DLL';
function CeReadFile(hFile: cardinal;var lpBuffer; nNumberOfBytesToRead: cardinal; var lpNumberOfBytesRead: cardinal; lpOverlapped: poverlapped):bool; stdcall; external 'RAPI.DLL';
function CeWriteFile(hFile: cardinal;const lpBuffer; nNumberOfBytesToWrite: cardinal; var lpNumberOfBytesWritten: cardinal; lpOverlapped: poverlapped):bool; stdcall; external 'RAPI.DLL';
function CeCloseHandle(IntPtr: thandle):integer; stdcall; external 'RAPI.DLL';

implementation

{$R *.dfm}

function VoirSiConnect(attente : integer) : boolean;
var
ri: TRapiInit;
hRes: HRESULT;
dwRet: HRESULT;
begin
ri.cbSize := sizeof(ri);
hRes := CeRapiInitEx(ri);
if hRes = S_OK then
begin
dwRet := WaitForSingleObject(ri.heRapiInit, attente);
if ((dwRet <> WAIT_OBJECT_0) OR (ri.hrRapiInit <> S_OK))then
begin
CeRapiUninit;
Result := false;
end
else
begin
Result := true;
end;
end
else
begin
Result := false;
end;
end;

procedure CloreConnection;
begin
CeRapiUninit;
end;

procedure TForm1.ChangeActif(Sender: TObject);
var
LogEtat : string;
SActifIPAS, STermineAS, SActifAS, SInactifAS, SReponseAS: string;
SListenAS, SDeconnexionAS, SErreur,SDeconnectAS: string;
Connect: Boolean;
begin
SActifIPAS := '设备已连接';
STermineAS := '设备关闭';
SActifAS := '设备活动中';
SInactifAS := '非连接状态';
SReponseAS := '响映中...';
SListenAS := '侦测中...';
SDeconnexionAS := '连接断开';
SErreur := '连接错误';
SDeconnectAS := '关闭连接';
Connect := False;
case DccMan.IndexOnLog of
1 : LogEtat := SActifIPAS; // OnLogIpAddr
2 : LogEtat := STermineAS;
3 : LogEtat := SActifAS;
4 : LogEtat := SInactifAS;
5 : LogEtat := SReponseAS;
6 : LogEtat := SListenAS;
7 : LogEtat := SDeconnexionAS;
8 : LogEtat := SErreur;
end;
Label1.Caption := LogEtat;
if not Connect and (DccMan.IndexOnLog = 1) then
begin
Connect := VoirSiConnect(5000);
end;
if Connect and (DccMan.IndexOnLog <> 1) then
begin
Connect := false;
CloreConnection;
MessageBox(Handle, PChar(SDeconnectAS), '提示:', MB_OK or MB_ICONWARNING);
end;
end;

procedure TForm1.CreateParams(var Params: TCreateParams);
begin
inherited;
Params.Style := WS_SYSMENU;
end;

{----------从移动设备复制文件到PC机中----------}
function copyFileFromDevice(LocalFile: string;RemoteFile: string):bool;
var
fs: TFileStream;
ahandle: thandle;
FTempBuffer: array[0..$1000] of byte;
nwrite,nRead: dword;
ini: integer;
begin
result := true;
ini := CeRapiInit();
if (ini<>0) then
begin
exit;
end;
ahandle := CeCreateFile(RemoteFile, $80000000, 0, 0, 3, $80, 0);
if ahandle=-1 then
begin
//showmessage('在设备上创建文件失败!');
MessageBox(0,'下载文件失败,请检查设备是否正确连接!','提示:',MB_OK OR MB_ICONWARNING);
CeRapiUninit();
result := false;
exit;
end;

if fileexists(localfile) then
deletefile(localfile);
fs:=tfileStream.Create(localfile,fmCreate);
CeReadFile(ahandle,FtempBuffer,sizeof(fTempBuffer),nRead,0);
if nRead<=0 then
begin
MessageBox(0,'数据采集器中没有barcode.txt文件,无法导出!','错误提示:',MB_OK OR MB_ICONWARNING);
fs.Free;
CeRapiUninit();
Exit;
end;
while nRead>0 do
begin
fs.Write(fTempBuffer,nRead);
if not CeReadFile(ahandle,FtempBuffer,sizeof(fTempBuffer),nRead,0) then
begin
result:=false;
break;
end;
end;
CeCloseHandle(ahandle);
fs.Free;
CeRapiUninit();
end;

procedure TForm1.RzBitBtn1Click(Sender: TObject);
var
ri: TRapiInit;
hRes: HRESULT;
dwRet: DWORD;
fpath, f: string;
sa: SECURITY_ATTRIBUTES;
Msg: string;
begin
Msg := '1、请检查设备是否正确连接!'+#13+'2、系统中是否安装通讯软件Microsoft ActiveSync V4.5!';
fpath := 'C:/ShineJit/';
f := 'barcode.txt';
if not DirectoryExists(fpath) then
begin
sa.nLength := SizeOf(sa);
sa.lpSecurityDescriptor := 0;
sa.bInheritHandle := True;
CreateDirectory(PChar(fpath),sa.lpSecurityDescriptor);
end;
ri.cbSize := sizeof(ri);
hRes := CeRapiInitEx(ri);
dwRet := WaitForSingleObject(ri.heRapiInit, 2000);
if ((dwRet <> WAIT_OBJECT_0) or (SUCCEEDED(ri.hrRapiInit) = FALSE)) then
begin
// Could not initialize Rapi
MessageBox(0,PChar(Msg),'导出失败:',MB_OK OR MB_ICONWARNING);
CeRapiUninit;
Exit;
end;
if copyFileFromDevice(fpath+'barcode.txt','barcode.txt') and CeDeleteFile(f) then
MessageBox(Handle,'数据下载成功!','提示:',MB_OK OR MB_ICONINFORMATION);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
DccMan := TDccMan.Create;
DccMan.OnChange := ChangeActif;
DccMan.Advise;
end;

end.
 
多人接受答案了。
 
后退
顶部