2015-02-14 4 views
0

Я пытаюсь получить имя всех моих открытых процессов. Это то, что у меня есть: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).

Кроме того, это, Что отображения в окне сообщения: enter image description here

Есть идеи?

+0

Как насчет того, чтобы попробовать вашу программу у администратора? –

+1

'GetLastError' бессмысленно, если функция действительно не сработала. Кажется, вы не проверяете ошибку. –

+0

@YoungHyunYoo Я попытался запустить VS в качестве администратора и все еще испытываю ту же ошибку. – Pedrumj

ответ

3

Четвертый аргумент GetModuleFileNameEx() должен быть размером массива, переданного в третьем аргументе. Вы проходите в _len2. Но вы установили _len2 в ноль, а не в размер вашего массива lpFilename (100). Таким образом, GetModuleFileNameEx() видит, что это не имеет никакого отношения, и даже не касается вашего массива lpFilename. Данные кучи не обязательно инициализируются нулями, поэтому lpFilename все еще содержит случайный мусор, следовательно, содержимое случайного сообщения.

Я собираюсь предположить, что GetModuleFileNameEx() вернул ноль, потому что ему ничего не нужно было писать, но не установил последний код ошибки, потому что ничего не произошло, поэтому ошибка отказа в доступе оставлена ​​с более ранней части программа.

еще несколько заметок:

Имейте в виду, что сказал Джонатан Поттер о правильном пути, чтобы проверить возвраты ошибок из функций Windows API. У вас есть значение от GetModuleFileNameEx() в _len. MSDN говорит, что GetModuleFileNameEx() возвращает ноль при ошибке. Поэтому вам нужно проверить _len, чтобы узнать, равен ли он нулю до получения последнего значения ошибки, иначе это не будет иметь смысла. Как упоминалось ранее, GetModuleFileNameEx() не должен удалить последнее значение ошибки, если оно выполнено успешно.

HANDLE hndProccesse = new HANDLE; определенно неправильно, но не является ошибкой в ​​вашей программе (это is утечка памяти, хотя!). HANDLE сам по себе является указателем, поэтому было разрешено запустить new. Но делать это бессмысленно, так как HANDLE s возвращаются операционной системой и вообще не должен использоваться в качестве указателей. Вместо этого учитывайте их непрозрачные значения.

На предмет утечек памяти, вы никогда не delete[] каждый из lpFilename с создаваемым в цикле, и не вам delete[]pProcessIds. Это может быть не важно для небольшой программы, которую вы указали выше, но если ваша программа когда-либо будет расти, вы определенно захотите ее исправить.

В общем случае используйте MAX_PATH в качестве номинальной длины буфера имени файла вместо 100. Это то, что используют различные функции оболочки. (Более длинный не повредит, но короче будет.)

1

Чтобы получить полезное описание ошибки, вам необходимо использовать FormatMessage. Пример показан ниже. Этот пример точно так же, как ваш, но все, что он делает, включает проверку ошибок. ЭТО НЕ РЕШАЕТ ПРОБЛЕМУ!

#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; 
} 
+0

Я решил исправить звонок после 'CloseHandle', но я забыл и лег спать. Вот почему я использовал их во временных переменных. Для проверки только после сбоя, я понимаю, что .. Однако я только разместил это, чтобы показать OP, как получить полезное сообщение об ошибке из возвращаемого значения 'GetLastError'. Сказав это, я исправил это. – Brandon