- PVSM.RU - https://www.pvsm.ru -
Доброго времени суток. Знакомо ли вам исключение 0xc00007b? С момента перевода движка X-Ray под x64 [1] приходило очень много репортов о проблеме 0cx00007b. В 90% случаев, это была проблема с отсутствием 64 битного драйвера OpenAL.
Первое время мы постоянно отвечали, что нужно установить драйвер, спустя пару месяцев написали FAQ по запуску и вероятным проблемам. Но подобные репорты не уходили, народ у нас в СНГ читать не особо любит, поэтому мы решили решить проблему радикально: устанавливать драйвер из-под движка, если таковой отсутствует.
Самый простой способ подключения библиотек друг к другу — компоновка(pragma comment [2]), но в нашем случае так делать нельзя.
Итак, шаг 1: явная линковка [3] или привет extern "C"
.
Что нам требуется: отвязать exe от библиотек движка. Делается это следующим способом:
1) Выносим функцию запуска движка в динамическую библиотеку:
extern "C" --// LoadLibrary, если мне не изменяет память, Сишное API
{
void ENGINE_API RunApplication(LPCSTR commandLine)
{
... // Your code
}
}
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;
}
Ну, тут всё просто, получаем системный(может кто-то удивится, но 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;
}
Первым делом нам нужно попросить права администратора у пользователя, т.к. работать придётся с системным каталогом:
// Проверяем, запущенны ли мы от администратора
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; // Говорим, что всё в порядке, можно запускать движок
}
}
Конечно, способ весьма забавный, но для подобных проектов подойдёт. Всем удачи!
Автор: ForserX
Источник [4]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/c-3/300930
Ссылки в тексте:
[1] X-Ray под x64: https://github.com/xrOxygen/xray-oxygen/
[2] pragma comment: https://ru.wikipedia.org/wiki/%D0%90%D0%B2%D1%82%D0%BE%D1%81%D0%B2%D1%8F%D0%B7%D1%8B%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5
[3] явная линковка: https://msdn.microsoft.com/ru-ru/library/784bt7z7.aspx
[4] Источник: https://habr.com/post/431842/?utm_source=habrahabr&utm_medium=rss&utm_campaign=431842
Нажмите здесь для печати.