Vista上的IPC(服务和应用程序)
我正在Vista上创建一个应用程序,其中包括服务和控制台应用程序。两者都以相同的用户帐户运行
在服务中,我正在创建一个事件并等待该事件。在控制台应用程序中,我正在打开同一事件(问题从此处开始)并调用SetEvent函数。我无法在控制台应用程序中打开事件(错误5,访问被拒绝)。我在网上搜索并看到一些有关完整性级别的信息(我不确定问题是否与完整性级别有关)。和应用程序具有不同的完整性级别。
这是代码的一部分,发生IPC
服务
DWORD
WINAPI IpcThread(LPVOID lpParam)
{
HANDLE ghRequestEvent = NULL ;
ghRequestEvent = CreateEvent(NULL, FALSE,
FALSE, "Global\Event1") ; //creating the event
if(NULL == ghRequestEvent)
{
//error
}
while(1)
{
WaitForSingleObject(ghRequestEvent, INFINITE) //waiting for the event
//here some action related to event
}
}
控制台应用
在应用程序中,打开事件并设置事件
unsigned int
event_notification()
{
HANDLE ghRequestEvent = NULL ;
ghRequestEvent = OpenEvent(SYNCHRONIZE|EVENT_MODIFY_STATE, FALSE, "Global\Event1") ;
if(NULL == ghRequestEvent)
{
//error
}
SetEvent(ghRequestEvent) ;
}
我同时具有管理特权(我以Administraor登录并通过右键单击并使用选项"以管理员身份运行")运行控制台应用程序,同时运行了两个应用程序(服务和控制台应用程序)。
我在控制台应用程序(在其中打开事件)中遇到的错误是错误5(访问被拒绝。)。
因此,如果我们告诉如何在Vista中的服务和应用程序之间执行IPC,这将非常有帮助。
提前致谢
纳瓦内斯
解决方案
服务和应用程序是作为具有不同完整性级别的同一用户运行,还是作为不同用户运行?
如果是前者,那么有关完整性级别的MSDN文章可能会有所帮助。他们有一些示例代码,用于降低文件的完整性级别。我不确定这是否与某个事件相关。
#include <sddl.h>
#include <AccCtrl.h>
#include <Aclapi.h>
void SetLowLabelToFile()
{
// The LABEL_SECURITY_INFORMATION SDDL SACL to be set for low integrity
#define LOW_INTEGRITY_SDDL_SACL_W L"S:(ML;;NW;;;LW)"
DWORD dwErr = ERROR_SUCCESS;
PSECURITY_DESCRIPTOR pSD = NULL;
PACL pSacl = NULL; // not allocated
BOOL fSaclPresent = FALSE;
BOOL fSaclDefaulted = FALSE;
LPCWSTR pwszFileName = L"Sample.txt";
if (ConvertStringSecurityDescriptorToSecurityDescriptorW(
LOW_INTEGRITY_SDDL_SACL_W, SDDL_REVISION_1, &pSD;, NULL))
{
if (GetSecurityDescriptorSacl(pSD, &fSaclPresent;, &pSacl;,
&fSaclDefaulted;))
{
// Note that psidOwner, psidGroup, and pDacl are
// all NULL and set the new LABEL_SECURITY_INFORMATION
dwErr = SetNamedSecurityInfoW((LPWSTR) pwszFileName,
SE_FILE_OBJECT, LABEL_SECURITY_INFORMATION,
NULL, NULL, NULL, pSacl);
}
LocalFree(pSD);
}
}
如果是后者,则可以查看此链接,该链接建议创建一个NULL ACL并将其与该对象相关联(在示例中,它是一个命名管道,但是对于确定的事件,该方法是相似的:
BYTE sd[SECURITY_DESCRIPTOR_MIN_LENGTH]; SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = &sd; InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); SetSecurityDescriptorDacl(&sd, TRUE, (PACL) 0, FALSE); CreateNamedPipe(..., &sa);
首先,重要的是要在概念上了解所需的内容。一旦了解了这一点,我们就可以从那里接受它。
在服务器上,它看起来应该类似于:
{
HANDLE hEvent;
hEvent = CreateEvent(null, true, false, TEXT("MyEvent"));
while (1)
{
WaitForSingleObject (hEvent);
ResetEvent (hEvent);
/* Do something -- start */
/* Processing 1 */
/* Processing 2 */
/* Do something -- end */
}
}
在客户端上:
{
HANDLE hEvent;
hEvent = OpenEvent(0, false, TEXT("MyEvent"));
SetEvent (hEvent);
}
需要注意的几点:
- ResetEvent应该尽早在WaitForSingleObject或者WaitForMultipleObjects之后。如果多个客户端正在使用服务器,并且第一个客户端的处理需要时间,则第二个客户端可能会设置事件,并且在服务器处理第一个请求时可能不会捕获该事件。
- 我们应该实现某种机制,该机制将通知客户端服务器已完成处理。
- 在执行任何win32服务之前,请先将服务器作为简单的应用程序运行。这将消除任何与安全性相关的问题。
我注意到我们正在"全局"名称空间中创建对象,但是正在尝试在本地名称空间中打开该对象。在公开通话中为名称添加" Global "是否有帮助?
另外,在//错误区域中,是否有任何内容可以让我们知道它不是被创建的?
@Navaneeth:
优秀的反馈。由于错误是"访问被拒绝",因此我会将所需的访问权限从EVENT_ALL_ACCESS更改为我们真正不需要的访问权限
(SYNCHRONIZE | EVENT_MODIFY_STATE)
SYNCHRONIZE让我们等待事件,而EVENT_MODIFY_STATE让我们调用SetEvent,ResetEvent和PulseEvent。
我们可能需要更多的访问权限,但这非常不寻常。
" 1800信息"是正确的,这是一个UIPI问题;无论如何不要在新代码中使用事件,如果触发事件时目标阻塞恰好在用户模式的APC代码中,则事件信号可能会丢失。 Win32中编写服务/应用程序的标准方法是使用RPC调用来跨越UIPI边界。

