0xc00007b أو تثبيت برامج التشغيل من ضمن البرنامج

الدخول


يوم جيد. هل أنت على دراية بالاستثناء 0xc00007b ؟ منذ نقل محرك X-Ray إلى x64 ، كان هناك الكثير من التقارير حول مشكلة 0cx00007b. في 90 ٪ من الحالات ، كانت هذه مشكلة مع عدم وجود سائق OpenAL 64 بت.


أفكار لحل المشكلة


في البداية ، أجبنا باستمرار على أنك تحتاج إلى تثبيت برنامج التشغيل ، وبعد بضعة أشهر كتبنا أسئلة وأجوبة حول بدء التشغيل والمشاكل المحتملة. لكن هذه التقارير لم تختف ، لا يحب الأشخاص في CIS القراءة بشكل خاص ، لذلك قررنا حل المشكلة بشكل جذري: تثبيت برنامج التشغيل من أسفل المحرك ، إذا لم يكن هناك أي شيء.


الخطوة 1: بدء البرنامج عندما دلل ليست كافية


أسهل طريقة لتوصيل المكتبات مع بعضها البعض هي بناء ( تعليق براغما ) ، ولكن في حالتنا لا يمكن القيام بذلك.


لذلك ، الخطوة 1: ربط واضح أو مرحبا extern "C" .


ما نحتاج إليه: فك إكس من مكتبات المحركات. يتم ذلك بالطريقة التالية:


1) نأخذ وظيفة لبدء تشغيل المحرك في المكتبة الديناميكية:


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

2) استدعاء وظيفة من إكس لدينا:


 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: فحص السائق


حسنًا ، كل شيء بسيط ، نحصل على نظام واحد (ربما يفاجأ شخص ما ، لكن نظام التشغيل ليس دائمًا في قسم 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; // ,    ,    } } 

الخاتمة


بالطبع ، الطريقة مضحكة للغاية ، ولكنها مناسبة لمثل هذه المشاريع. حظا سعيدا للجميع!

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


All Articles