GetModuleFileNameEx,拒绝访问错误
GetModuleFileNameEx, Access Denied Error
我正在尝试获取所有打开进程的名称。这是我的:
#include "stdafx.h"
#include <Psapi.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pCmdLine, int iCmdShow)
{
bool _result;
DWORD *pProcessIds = new DWORD[1000];
DWORD cb;
DWORD pBytesReturned;
_result = EnumProcesses(pProcessIds, 1000, &pBytesReturned);
HANDLE hndProccesse;
for (int i = 0; i < pBytesReturned / sizeof(DWORD); ++i)
{
hndProccesse = OpenProcess(STANDARD_RIGHTS_ALL, false, *pProcessIds);
DWORD _len;
DWORD _len2 =0;
LPWSTR lpFilename = new WCHAR[100];
_len =GetModuleFileNameEx(hndProccesse,NULL, lpFilename, _len2);
DWORD _errr;
_errr = GetLastError();
MessageBox(NULL, lpFilename, NULL, 0);
CloseHandle(hndProccesse);
pProcessIds ++;
}
return 0;
}
在 GetModuleFileNameEx
之前一切正常,但出现拒绝访问错误 (5)。
此外,这是消息框上显示的内容:
有什么想法吗?
GetModuleFileNameEx()
的第四个参数必须是第三个参数中传递的数组的大小。你传入 _len2
。但是您将 _len2
设置为零,而不是 lpFilename
数组的大小 (100)。所以 GetModuleFileNameEx()
认为它无事可做,甚至不会触及你的 lpFilename
数组。堆数据不一定初始化为零,因此 lpFilename
仍然包含随机垃圾,因此包含随机消息框内容。
我会猜测 GetModuleFileNameEx()
returned 零因为它不需要写任何东西,但没有设置最后一个错误代码,因为没有失败,所以访问被拒绝错误是程序较早部分遗留下来的。
更多注意事项:
请记住 Jonathan Potter 所说的关于检查来自 Windows API 函数的错误 return 的正确方法。 _len
中 GetModuleFileNameEx()
的 return 值。 MSDN 说 GetModuleFileNameEx()
return 错误为零。所以在得到最后一个错误值之前需要先检查_len
是否为0,否则没有意义。如前所述,如果成功,GetModuleFileNameEx()
不必清除 最后一个错误值。
HANDLE hndProccesse = new HANDLE;
肯定是错误的,但不是您程序中的错误(不过 是 内存泄漏!)。 HANDLE
本身就是一个指针,这就是为什么new
被允许为运行的原因。但这样做是没有意义的,因为 HANDLE
是由操作系统 return 编辑的,通常 不应该 用作指针。将它们视为不透明值。
关于内存泄漏的主题,您永远不会 delete[]
在循环中创建的每个 lpFilename
,您也不会 delete[]
pProcessIds
。这对于您上面发布的小程序可能并不重要,但如果您的程序不断增长,您肯定会想要修复它。
通常,使用 MAX_PATH
作为文件名缓冲区的标称长度而不是 100。这是各种 shell 函数使用的。 (更长的时间也不会受伤,但更短的时间。)
您需要使用 FormatMessage 来获取有用的错误描述。下面显示了一个示例。这个示例与您的示例完全一样,但它所做的只是包含错误检查。它不能解决问题![=11=]
#include <windows.h>
#include <Psapi.h>
void ShowError(DWORD err)
{
LPTSTR lpMsgBuf = nullptr;
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPTSTR>(&lpMsgBuf), 0, nullptr);
MessageBoxA(NULL, lpMsgBuf, "ERROR", 0);
LocalFree(lpMsgBuf);
}
int main()
{
DWORD* pProcessIds = new DWORD[1000];
DWORD pBytesReturned = 0;
bool res = EnumProcesses(&pProcessIds[0], 1000, &pBytesReturned);
if (!res)
{
DWORD err = GetLastError();
MessageBoxW(NULL, L"ENUMPROCESSES FAILED", L"Error", 0);
ShowError(err);
delete[] pProcessIds;
return EXIT_FAILURE;
}
for (unsigned int i = 0; i < pBytesReturned / sizeof(DWORD); ++i)
{
if (pProcessIds[i] == 0) //error.. process id is 0..
continue;
wchar_t lpFilename[256] = {0};
HANDLE hndProccess = OpenProcess(STANDARD_RIGHTS_ALL, false, pProcessIds[i]);
if (hndProccess == NULL || hndProccess == INVALID_HANDLE_VALUE)
{
DWORD err = GetLastError();
MessageBoxW(NULL, L"FAILED TO OPEN PROCESS", L"ERROR", 0);
ShowError(err);
delete[] pProcessIds;
return EXIT_FAILURE;
}
int len = GetModuleFileNameExW(hndProccess, NULL, lpFilename, sizeof(lpFilename) / sizeof(lpFilename[0]));
if (len <= 0)
{
DWORD err = GetLastError();
if (err)
{
MessageBoxW(NULL, L"FAILED TO GET MODULEFILENAME", L"ERROR", 0);
ShowError(err);
delete[] pProcessIds;
return EXIT_FAILURE;
}
}
CloseHandle(hndProccess);
MessageBoxW(NULL, lpFilename, L"NAME", 0);
}
delete[] pProcessIds;
return 0;
}
我正在尝试获取所有打开进程的名称。这是我的:
#include "stdafx.h"
#include <Psapi.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pCmdLine, int iCmdShow)
{
bool _result;
DWORD *pProcessIds = new DWORD[1000];
DWORD cb;
DWORD pBytesReturned;
_result = EnumProcesses(pProcessIds, 1000, &pBytesReturned);
HANDLE hndProccesse;
for (int i = 0; i < pBytesReturned / sizeof(DWORD); ++i)
{
hndProccesse = OpenProcess(STANDARD_RIGHTS_ALL, false, *pProcessIds);
DWORD _len;
DWORD _len2 =0;
LPWSTR lpFilename = new WCHAR[100];
_len =GetModuleFileNameEx(hndProccesse,NULL, lpFilename, _len2);
DWORD _errr;
_errr = GetLastError();
MessageBox(NULL, lpFilename, NULL, 0);
CloseHandle(hndProccesse);
pProcessIds ++;
}
return 0;
}
在 GetModuleFileNameEx
之前一切正常,但出现拒绝访问错误 (5)。
此外,这是消息框上显示的内容:
有什么想法吗?
GetModuleFileNameEx()
的第四个参数必须是第三个参数中传递的数组的大小。你传入 _len2
。但是您将 _len2
设置为零,而不是 lpFilename
数组的大小 (100)。所以 GetModuleFileNameEx()
认为它无事可做,甚至不会触及你的 lpFilename
数组。堆数据不一定初始化为零,因此 lpFilename
仍然包含随机垃圾,因此包含随机消息框内容。
我会猜测 GetModuleFileNameEx()
returned 零因为它不需要写任何东西,但没有设置最后一个错误代码,因为没有失败,所以访问被拒绝错误是程序较早部分遗留下来的。
更多注意事项:
请记住 Jonathan Potter 所说的关于检查来自 Windows API 函数的错误 return 的正确方法。 _len
中 GetModuleFileNameEx()
的 return 值。 MSDN 说 GetModuleFileNameEx()
return 错误为零。所以在得到最后一个错误值之前需要先检查_len
是否为0,否则没有意义。如前所述,如果成功,GetModuleFileNameEx()
不必清除 最后一个错误值。
HANDLE hndProccesse = new HANDLE;
肯定是错误的,但不是您程序中的错误(不过 是 内存泄漏!)。 HANDLE
本身就是一个指针,这就是为什么new
被允许为运行的原因。但这样做是没有意义的,因为 HANDLE
是由操作系统 return 编辑的,通常 不应该 用作指针。将它们视为不透明值。
关于内存泄漏的主题,您永远不会 delete[]
在循环中创建的每个 lpFilename
,您也不会 delete[]
pProcessIds
。这对于您上面发布的小程序可能并不重要,但如果您的程序不断增长,您肯定会想要修复它。
通常,使用 MAX_PATH
作为文件名缓冲区的标称长度而不是 100。这是各种 shell 函数使用的。 (更长的时间也不会受伤,但更短的时间。)
您需要使用 FormatMessage 来获取有用的错误描述。下面显示了一个示例。这个示例与您的示例完全一样,但它所做的只是包含错误检查。它不能解决问题![=11=]
#include <windows.h>
#include <Psapi.h>
void ShowError(DWORD err)
{
LPTSTR lpMsgBuf = nullptr;
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPTSTR>(&lpMsgBuf), 0, nullptr);
MessageBoxA(NULL, lpMsgBuf, "ERROR", 0);
LocalFree(lpMsgBuf);
}
int main()
{
DWORD* pProcessIds = new DWORD[1000];
DWORD pBytesReturned = 0;
bool res = EnumProcesses(&pProcessIds[0], 1000, &pBytesReturned);
if (!res)
{
DWORD err = GetLastError();
MessageBoxW(NULL, L"ENUMPROCESSES FAILED", L"Error", 0);
ShowError(err);
delete[] pProcessIds;
return EXIT_FAILURE;
}
for (unsigned int i = 0; i < pBytesReturned / sizeof(DWORD); ++i)
{
if (pProcessIds[i] == 0) //error.. process id is 0..
continue;
wchar_t lpFilename[256] = {0};
HANDLE hndProccess = OpenProcess(STANDARD_RIGHTS_ALL, false, pProcessIds[i]);
if (hndProccess == NULL || hndProccess == INVALID_HANDLE_VALUE)
{
DWORD err = GetLastError();
MessageBoxW(NULL, L"FAILED TO OPEN PROCESS", L"ERROR", 0);
ShowError(err);
delete[] pProcessIds;
return EXIT_FAILURE;
}
int len = GetModuleFileNameExW(hndProccess, NULL, lpFilename, sizeof(lpFilename) / sizeof(lpFilename[0]));
if (len <= 0)
{
DWORD err = GetLastError();
if (err)
{
MessageBoxW(NULL, L"FAILED TO GET MODULEFILENAME", L"ERROR", 0);
ShowError(err);
delete[] pProcessIds;
return EXIT_FAILURE;
}
}
CloseHandle(hndProccess);
MessageBoxW(NULL, lpFilename, L"NAME", 0);
}
delete[] pProcessIds;
return 0;
}