Windows安全桌面与用户桌面间的通信

这段时间在做一个指纹相关的项目,其中有一个功能就是要替换msgina.dll,来实现Windows的指纹登陆。因为指纹设备有时候会死掉,而且设备死掉的时候很麻烦,常常会导致进程崩溃,msgina.dll是由winlogon来调用的,如果设备死掉了,可能导致winlogon进程崩溃,用户将无法登陆系统。为了确保设备死掉不会影响用户正常登陆windows,我们不得不把指纹设备相关的所有代码都移植到另一个进程中,由一个独立的进程来提供指纹扫描和比对服务。同时这个进程还要给其它的应用提供指纹服务。这样,就涉及到不同的桌面间进程的通信的问题。而且这个问题还相当的头痛。    首先来介绍下windows下桌面的概念:在Windows NT/Windows 2000/Windows XP中, WinSta0 是表示物理屏幕、鼠标和键盘的Windows系统对象的名字。Winlogon在WinSta0 Windows系统中创建了SAS窗口(窗口标题是"SAS Window")和如下三个桌面。 Winlogon 桌面 应用程序桌面 (Default,用户桌面) 屏幕保护桌面 winlogon桌面是一个特殊的桌面,windows对这个桌面进行了一些特殊的处理,使得winlogon桌面与用户桌面之间的进程通信有些麻烦。       一开始我们尝试直接用postmessage和sendmessage,但是发现在winlogon桌面中调用Findwindow查找窗口会失败,这说明窗口在不同的桌面间是不可见的。于是我把接收方的窗口句柄写到一个注册表项里,在要发送消息的时候,从注册表中取出窗口句柄,结果发现这样发生消息,可以成功。但是用同样的方法,由应用程序给winlogon发生消息,结果发生失败,即使发生WM_COPYDATA也不行。事实证明:       从winlogon桌面往用户桌面的应用程序发生消息是允许的,从用户桌面往winlogon桌面发送消息是被禁止的。我感觉这个不符合访问控制的原则。按理说,winlogon是一个高安全级别的桌面,允许信息从高安全级别的桌面往低安全级别的桌面流动,而不允许低安全级别的桌面(用户桌面)往高安全级别的桌面发生消息,这好像不太合理。      传递消息的方式看来是不行了,于是就尝试管道通信了。一开始我们在重启windows后,windows登录框初始化的时候,启动这个服务进程,这样没有问题,管道通信可以。但是发现如果进入系统后,点击应用程序显示了程序界面后,再锁定计算机,这时候,就不行了,看日志,结果发现给管道发生消息会失败。用spy++来查看服务进程中窗口的句柄,我们发现,如果服务进程是由winlogon进程以隐藏方式启动的,在点击图标显示了用户界面后,窗口的句柄都会发生变化。按理说,这些窗口都是已经创建好了的,为什么窗口句柄都会发生变化呢?我们猜测,是不是程序在用户桌面显示后,就是从winlogon桌面切换到用户桌面的时候,窗口句柄会进行一次转换,当然这只是我们的一种猜测。结果我们发现,winlogon与用户桌面中的进程不能进行管道通信。     共享内存的方式我们没有试过,因为这样通信还需要我们去监控共享内存的变化,不是很方便。最好我们选择了往注册表写要发生的消息,然后接收方监控注册表变化,当注册表的值发生变化的时候,就读取注册表的内容。监控注册表键值变化可以用RegNotifyChangeKeyValue 下面是MSDN中使用它的一个例子。 #include #include   void main(int argc, char *argv[]) {    DWORD  dwFilter = REG_NOTIFY_CHANGE_NAME |                      REG_NOTIFY_CHANGE_ATTRIBUTES |                      REG_NOTIFY_CHANGE_LAST_SET |                      REG_NOTIFY_CHANGE_SECURITY;      HANDLE hEvent;    HKEY   hMainKey;    HKEY   hKey;    LONG   lErrorCode;      // Display the usage error message.    if (argc != 3)    {       printf("Usage: notify [HKLM/HKU/HKCU/HKCR/HCC] [subkey]/n");       return;    }      // Convert parameters to appropriate handles.    if (strcmp("HKLM", argv[1]) == 0) hMainKey=HKEY_LOCAL_MACHINE;    else if(strcmp("HKU", argv[1]) == 0) hMainKey=HKEY_USERS;    else if(strcmp("HKCU", argv[1]) == 0) hMainKey=HKEY_CURRENT_USER;    else if(strcmp("HKCR", argv[1]) == 0) hMainKey=HKEY_CLASSES_ROOT;    else if(strcmp("HCC", argv[1]) == 0) hMainKey=HKEY_CURRENT_CONFIG;    else    {       printf("Usage: notify [HKLM/HKU/HKCU/HKCR/HCC] [subkey]/n");       return;    }      // Open a key.    lErrorCode = RegOpenKeyEx(hMainKey, argv[2], 0, KEY_NOTIFY, &hKey);    if (lErrorCode != ERROR_SUCCESS)    {       printf("Error in RegOpenKeyEx./n");       return;    }      // Create an event.    hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);    if (hEvent == NULL)    {       printf("Error in CreateEvent./n");       return;    }      // Watch the registry key for a change of value.    lErrorCode = RegNotifyChangeKeyValue(hKey,                                         TRUE,                                         dwFilter,                                         hEvent,                                         TRUE);    if (lErrorCode != ERROR_SUCCESS)    {       printf("Error in RegNotifyChangeKeyValue./n");       return;    }      // Wait for an event to occur.    if (WaitForSingleObject(hEvent, INFINITE) == WAIT_FAILED)    {       printf("Error in WaitForSingleObject./n");       return;    }      // Close the key.    lErrorCode = RegCloseKey(hKey);    if (lErrorCode != ERROR_SUCCESS)    {       printf("Error in RegCloseKey./n");       return;    }       // Close the handle.    if (!CloseHandle(hEvent))    {       printf("Error in CloseHandle./n");       return;    } } 我们需要用一个单独的线程,专门去监控注册表的变化。用这种方法总算解决了winlogon与其它进程间的通信问题。对于前面我们遇到的问题,和初步试验得出的结论,我也不知道是否正确,希望有这方面经验的朋友可以指点下^_^

你可能感兴趣的:(Windows安全桌面与用户桌面间的通信)