Event事件的访问问题

做个本地UDP通讯, 涉及到大数据分包传送, 使用Event来通知数据包收到状态

测试程序很正常, 发送端CreateEvent, 接收端SetEvent

 

可是到了实际项目里却出现无法访问, 错误代码2(找不到文件), 查看资料发现因为项目发送端是Service, 接收端是桌面程序, 不再同一用户范围, 导致找不到事件对象

MSDN关于CreateEvent描述:  https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createeventa

关于命名空间的描述: https://docs.microsoft.com/zh-cn/windows/win32/termserv/kernel-object-namespaces

根据资料描述, 要在事件名前面加"Global\"以定义事件是全局对象

var
  lEventHandle: THandle;
  lEventName: string;
begin
  lEventName := TGUID.NewGuid.ToString;
  
  lEventHandle := CreateEvent(nil, False, False, PChar('Global\' + lEventName));
  ...
  WaitForSingleObject(lEventHandle, 1000)
  CloseHandle(lEventHandle);
end;

 

改完以后测试, 发现错误2解决了, 但是出现另一个问题, 错误代码5, 拒绝访问, 继续查资料, 发现还是不同用户的问题, 由于Service运行于system账户, 权限高于用户账户, 所以用户账户进程无法访问

关于权限说明资料: https://docs.microsoft.com/zh-cn/previous-versions/windows/desktop/legacy/aa379560(v=vs.85)

权限设置(SetSecurityDescriptorDacl)资料: https://docs.microsoft.com/zh-cn/windows/win32/api/securitybaseapi/nf-securitybaseapi-setsecuritydescriptordacl?redirectedfrom=MSDN

于是设置CreateEvent第一个参数, 降低权限:

var
  lEventHandle: THandle;
  lSA: TSecurityAttributes;
  lSD: TSecurityDescriptor;
  lEventName: string;
begin
  lEventName := TGUID.NewGuid.ToString;
  
  InitializeSecurityDescriptor(@lSD, SECURITY_DESCRIPTOR_REVISION);
  SetSecurityDescriptorDacl(@lSD, True, nil{这里设置为nil, 不限制访问}, False);
  lSA.nLength := SizeOf(lSA);
  lSA.lpSecurityDescriptor := @lSD;
  lSA.bInheritHandle := False;
  lEventHandle := CreateEvent(@lSA, False, False, PChar('Global\' + lEventName));
  ...
  WaitForSingleObject(lEventHandle, 1000)
  CloseHandle(lEventHandle);
end;

 

终于能访问了....

 

PS:

期间遇到了个坑, 项目机制是先由客户端发包, 然后服务端接收再返回, 在没设置权限时, 测试时是写死EventName, 导致客户端先CreateEvent后服务端open

此时又有个BUG: 服务端Open完了忘了close, 导致后服务端返回时的CreateEvent实际是沿用了客户端创建的Event

所以客户端也能正常访问

结果改为动态EventName以后, 由于服务返回时EventName变了, 所以就出现了拒绝访问

搞的我调试发现使用固定值的EventName就能正常, 改为动态GUID就不正常, 还以为创建GUID会影响权限, 查了好久...心累...

posted on 2020-03-11 14:54  黑暗煎饼果子  阅读(199)  评论(0编辑  收藏  举报