Главная » Хабрахабр » 0cx00007b или установка драйверов из-под программы

0cx00007b или установка драйверов из-под программы

Вступление

Знакомо ли вам исключение 0cx00007b? Доброго времени суток. В 90% случаев, это была проблема с отсутствием 64 битного драйвера OpenAL. С момента перевода движка X-Ray под x64 приходило очень много репортов о проблеме 0cx00007b.

Идеи по решению проблемы

Но подобные репорты не уходили, народ у нас в СНГ читать не особо любит, поэтому мы решили решить проблему радикально: устанавливать драйвер из-под движка, если таковой отсутствует. Первое время мы постоянно отвечали, что нужно установить драйвер, спустя пару месяцев написали FAQ по запуску и вероятным проблемам.

Шаг 1: запуск программы, когда не хватает dll

Самый простой способ подключения библиотек друг к другу — компоновка(pragma comment), но в нашем случае так делать нельзя.

Делается это следующим способом:
1) Выносим функцию запуска движка в динамическую библиотеку: Итак, шаг 1: явная линковка или привет extern "C".
Что нам требуется: отвязать exe от библиотек движка.

extern "C" --// LoadLibrary, если мне не изменяет память, Сишное API

}

2) Вызываем функцию из нашего exe:

using RunFunc = void(__cdecl*)(const char*); // Объявляем удобный для себя тип функции bool OpenALFound = false; // Оно нам потом пригодится int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{ if(OpenALFound) { HMODULE hLib = LoadLibrary("xrEngine.dll"); // Получаем модуль с нашей функцией IsRunFunc RunFunc = (IsRunFunc)GetProcAddress(hLib, "RunApplication"); // Получаем функцию из модуля RunFunc(params); // Запускаем движок } return 0;
}

Шаг 2: Проверка драйвера

Ну, тут всё просто, получаем системный(может кто-то удивится, но OS не всегда на C:) раздел и проверяем dll в папке с драйверами:

/// R_ASSERT - внутренний макросс, проверяющий значение первого аргумента на истину, если лож - программа выведет сообщение об ошибке
... // WinMain code
TCHAR szOpenALDir[MAX_PATH] = { 0 }; // Получаем системный патч
R_ASSERT(GetSystemDirectory(szOpenALDir, MAX_PATH * sizeof(TCHAR))); #ifndef UNICODE _snprintf_s(szOpenALDir, MAX_PATH * sizeof(CHAR), "%s%s", szOpenALDir, "\\OpenAL32.dll");
#else _snwprintf_s(szOpenALDir, MAX_PATH * sizeof(WCHAR), L"%s%s", szOpenALDir, L"\\OpenAL32.dll");
#endif
DWORD dwOpenALInstalled = GetFileAttributes(szOpenALDir); // Атрибуты валидные, значит драйвер на месте. Всё в порядке, запускаем.
if (dwOpenALInstalled != INVALID_FILE_ATTRIBUTES)
{ OpenALFound = true;
}

Шаг 3: Файл не найден

работать придётся с системным каталогом: Первым делом нам нужно попросить права администратора у пользователя, т.к.

// Проверяем, запущенны ли мы от администратора
bool IsProcessWithAdminPrivilege()
{ SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; LPVOID pAdministratorsGroup = nullptr; BOOL bRet = FALSE; // init SID to control privileges AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pAdministratorsGroup); // ckeck membership CheckTokenMembership(nullptr, pAdministratorsGroup, &bRet); // clean pointer if (pAdministratorsGroup) { FreeSid(pAdministratorsGroup); pAdministratorsGroup = nullptr; } return !!bRet;
} {
...// WinMain code // Если нет прав администратора, попросим их и перезапустимся if (!IsProcessWithAdminPrivilege()) { TCHAR szPathToLib[MAX_PATH] = { 0 }; GetModuleFileName(nullptr, szPathToLib, ARRAYSIZE(szPathToLib)); SHELLEXECUTEINFO shellInfo = { sizeof(SHELLEXECUTEINFO) }; shellInfo.lpVerb = TEXT("runas"); shellInfo.lpFile = szPathToLib; shellInfo.hwnd = nullptr; shellInfo.nShow = SW_NORMAL; if (ShellExecuteEx(&shellInfo)) ExitProcess(GetCurrentProcessId()); }
}

Этап второй: копируем библиотеку в систему

{
...
// WinMain code TCHAR szPath[MAX_PATH] = { 0 }; // Для примера беру путь от исполняемого файла GetModuleFileName(GetModuleHandle(nullptr), szPath, MAX_PATH); PathRemoveFileSpec(szPath); #ifndef UNICODE _snprintf_s(szPath, MAX_PATH * sizeof(CHAR), "%s%s", szPath, "\\OpenAL32.dll");
#else _snwprintf_s(szPath, MAX_PATH * sizeof(WCHAR), L"%s%s", szPath, L"\\OpenAL32.dll");
#endif dwOpenALInstalled = GetFileAttributes(szPath); if (dwOpenALInstalled != INVALID_FILE_ATTRIBUTES) // Файл найдет, идём дальше { DWORD LibrarySize = 0; HANDLE hFile = CreateFile(szPath, GENERIC_READ, NULL, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); R_ASSERT(hFile != INVALID_HANDLE_VALUE); FILE_STANDARD_INFO fileInfo = { 0 }; GetFileInformationByHandleEx(hFile, FileStandardInfo, &fileInfo, sizeof(fileInfo)); LPVOID pImage = HeapAlloc(GetProcessHeap(), 0, fileInfo.EndOfFile.QuadPart); ReadFile(hFile, pImage, fileInfo.EndOfFile.QuadPart, &LibrarySize, nullptr); CloseHandle(hFile); hFile = CreateFile(szOpenALDir, GENERIC_WRITE, NULL, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); R_ASSERT(hFile != INVALID_HANDLE_VALUE); WriteFile(hFile, pImage, fileInfo.EndOfFile.QuadPart, &LibrarySize, nullptr); HeapFree(GetProcessHeap(), 0, pImage); CloseHandle(hFile); OpenALFound = true; // Говорим, что всё в порядке, можно запускать движок }
}

Вывод

Всем удачи! Конечно, способ весьма забавный, но для подобных проектов подойдёт.


Оставить комментарий

Ваш email нигде не будет показан
Обязательные для заполнения поля помечены *

*

x

Ещё Hi-Tech Интересное!

[Перевод] Учебный курс по React, часть 1: обзор курса, причины популярности React, ReactDOM и JSX

Представляем вашему вниманию первые 5 занятий учебного курса по React для начинающих. Оригинал курса на английском, состоящий из 48 уроков, опубликован на платформе Scrimba.com. Возможности этой платформы позволяют, слушая ведущего, иногда ставить воспроизведение на паузу и самостоятельно, в том же ...

[Перевод] Разбираем лямбда-выражения в Java

Мы открыли его для себя совсем недавно, но уже по достоинству оценили его возможности. От переводчика: LambdaMetafactory, пожалуй, один из самых недооценённых механизмов Java 8. 0 фреймворка CUBA улучшена производительность за счет отказа от рефлективных вызовов в пользу генерации лямбда ...