0xc00007b o instalando controladores desde debajo del programa

Entrada


Buen dia ¿Está familiarizado con la excepción 0xc00007b ? Desde la transferencia del motor de rayos X a x64, ha habido muchos informes sobre el problema 0cx00007b. En el 90% de los casos, esto fue un problema con la falta de un controlador OpenAL de 64 bits.


Ideas para resolver el problema.


Al principio, respondimos constantemente que necesita instalar el controlador, después de un par de meses escribimos un FAQ sobre el inicio y posibles problemas. Pero tales informes no desaparecieron, a las personas en nuestro CIS no les gusta particularmente leer, por lo que decidimos resolver el problema radicalmente: instale el controlador debajo del motor, si no hay ninguno.


Paso 1: iniciar el programa cuando dll no es suficiente


La forma más fácil de conectar bibliotecas entre sí es construir ( comentario pragma ), pero en nuestro caso esto no se puede hacer.


Por lo tanto, paso 1: enlace explícito o extern "C" .


Lo que necesitamos: desatar exe de las bibliotecas del motor. Esto se hace de la siguiente manera:


1) Eliminamos la función para iniciar el motor en la biblioteca dinámica:


 extern "C" --// LoadLibrary,     ,  API { void ENGINE_API RunApplication(LPCSTR commandLine) { ... // Your code } } 

2) Llame a la función desde nuestro 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; } 

Paso 2: verificación del conductor


Bueno, todo es simple, tenemos un sistema (tal vez alguien se sorprenderá, pero el sistema operativo no siempre está en la sección C :) y verifique el dll en la carpeta del controlador:


 /// 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; } 

Paso 3: archivo no encontrado


En primer lugar, debemos pedirle al administrador los derechos de usuario, porque tendrá que trabajar con el directorio del sistema:


 // ,      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()); } } 

Etapa dos: copia la biblioteca al sistema


 { ... // 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; // ,    ,    } } 

Conclusión


Por supuesto, el método es muy divertido, pero adecuado para tales proyectos. ¡Buena suerte a todos!

Source: https://habr.com/ru/post/es431842/


All Articles