转载请标明是引用于 http://blog.csdn.net/chenyujing1234
欢迎大家拍砖
一、OpenEvent返回内存无法访问
1、问题描述
在winlogon.exe调用的gina.dll里创建一个线程,在线程里创建事件:
DWORD WINAPI CXRedGinaApp::XRedMonitorProc(LPVOID pParam)
{
HWND hForgroundWindow = NULL;
LDB(L"==>XRedMonitorProc");
// 循环等待得到事件句柄,此句柄在XLogon.dll加载时创建
while (true)
{
//g_CXRedGinaApp.m_RequestEvent = ::OpenEvent(EVENT_ALL_ACCESS, FALSE, XRED_REQUEST_EVENT);
g_CXRedGinaApp.m_RequestEvent = CreateEvent(NULL, FALSE, FALSE, XRED_REQUEST_EVENT);
if (NULL != g_CXRedGinaApp.m_RequestEvent && INVALID_HANDLE_VALUE != g_CXRedGinaApp.m_RequestEvent)
{
//g_CXRedGinaApp.m_RequestedEvent = ::OpenEvent(EVENT_ALL_ACCESS, FALSE, XRED_REQUESTED_EVENT);
g_CXRedGinaApp.m_RequestedEvent = CreateEvent(NULL, FALSE, FALSE, XRED_REQUESTED_EVENT);
if (NULL != g_CXRedGinaApp.m_RequestedEvent && INVALID_HANDLE_VALUE != g_CXRedGinaApp.m_RequestedEvent)
{
break;
}
else
{
CloseHandle(g_CXRedGinaApp.m_RequestEvent);
}
}
然后在开机会用另一应用程序去OpenEvent,结果返回“内存无法访问”
2、解决方法
改为在winlogon.exe调用的gina.dll里创建一个线程,在线程里打开事件:
DWORD WINAPI CXRedGinaApp::XRedMonitorProc(LPVOID pParam)
{
HWND hForgroundWindow = NULL;
LDB(L"==>XRedMonitorProc");
// 循环等待得到事件句柄,此句柄在XLogon.dll加载时创建
while (true)
{
g_CXRedGinaApp.m_RequestEvent = ::OpenEvent(EVENT_ALL_ACCESS, FALSE, XRED_REQUEST_EVENT);
//g_CXRedGinaApp.m_RequestEvent = CreateEvent(NULL, FALSE, FALSE, XRED_REQUEST_EVENT);
if (NULL != g_CXRedGinaApp.m_RequestEvent && INVALID_HANDLE_VALUE != g_CXRedGinaApp.m_RequestEvent)
{
g_CXRedGinaApp.m_RequestedEvent = ::OpenEvent(EVENT_ALL_ACCESS, FALSE, XRED_REQUESTED_EVENT);
//g_CXRedGinaApp.m_RequestedEvent = CreateEvent(NULL, FALSE, FALSE, XRED_REQUESTED_EVENT);
if (NULL != g_CXRedGinaApp.m_RequestedEvent && INVALID_HANDLE_VALUE != g_CXRedGinaApp.m_RequestedEvent)
{
break;
}
else
{
CloseHandle(g_CXRedGinaApp.m_RequestEvent);
}
}
然后在开机会用另一应用程序去CreateEvent,成功。
扩展解决方法(实现证明此方法是可行的):
在winlogon.exe调用的gina.dll里创建一个线程,在线程里创建事件时在事件名前加Global\\。
此时createEvent返回3 ,即"系统找不到指定的路径".
这是什么原因呢?查证后才知是global的第一个G要大写的,改正后试看看,成功了。
二、共享内存无法使用
在做win7下的登录凭证时用到应用层与CredentialProvider.dll的通信(CredentialProvider.dll被logonUI.exe调用),在两边通过文件映射传递数据。
1、问题描述
两边都映射文件成功了,可是在应用层写入数据,在CredentialProvider里却读不到数据。
// 共享数据段名称
#define XERD_LOGON_SHARE_DATA TEXT("XRED_LOGON_SHARE_DATA")
bool CShareData::Init(bool bInitData)
{
bool bReturn = true;
m_hFileMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE|SEC_COMMIT, 0, sizeof(XRED_SHAREDATA_T), XERD_LOGON_SHARE_DATA);
if (NULL != m_hFileMapping)
{
if(NULL == (m_lpShareData = (LPXRED_SHAREDATA_T)MapViewOfFile(m_hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0)))
{
CloseHandle(m_hFileMapping);
m_hFileMapping = NULL;
bReturn = false;
}
}
else
{
bReturn = false;
}
if (bInitData)
{
ZeroMemory(m_lpShareData, sizeof(XRED_SHAREDATA_T));
}
return bReturn;
}
2、解决方法:
在文件映射的名称前加Global\\
// 共享数据段名称
#define XERD_LOGON_SHARE_DATA TEXT("Global\\XRED_LOGON_SHARE_DATA")
3、原因
通常使用CreateFileMapping建立共享内存时名称中没有加入"Global\\",这使得共享的内存只能在当前用户下被另一个或多个进程访问,例如:
CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 1024, TEXT("MyShare"));
当把程序放到服务器上并运行,然后用远程桌面连接服务器时的用户身份作为了另一用户,这时运行访问共享内存的程序将产生错误[代码是2]。根据错误代码认为是权限问题,通常会去添加安全描述符,也就是设置CreateFileMapping的LPSECURITY_ATTRIBUTES参数,会这样做:
SECURITY_DESCRIPTORSECURITY_DESCRIPTOR secutityDese;
InitializeSecurityDescriptor(&secutityDese, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&secutityDese,TRUE,NULL,FALSE);
SECURITY_ATTRIBUTES securityAttr;
SECURITY_ATTRIBUTESsecurityAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
securityAttr.bInheritHandle = FALSE;
securityAttr.lpSecurityDescriptor = &secutityDese;
CreateFileMapping(INVALID_HANDLE_VALUE, &securityAttr, PAGE_READWRITE | SEC_COMMIT, 0, 1024, TEXT("MyShare"));
既使我们这样做发现没有任何效果,错误依旧!
Global\\*** 可以保证:在创建命名时间对象时指定名字是全局的,使用全局名称创建的内核对象无论出于服务,还是内核中,应用层都可以打开并使用这个内核对象。
然后改为使用全局名称,用远程桌面登陆到服务器在不同的用户下就能够运行访问共享内存的程序了!
CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 1024, TEXT("Global\\MyShare"));