extern "C" int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR /*lpCmdLine*/, int /*nShowCmd*/) { #ifdef CRASH_HANDLER rde::CrashHandler::Init(); #endif // disable auto-rotate on tablets #if (WINVER <= 0x0601) SetDisplayAutoRotationPreferences = (pSDARP) GetProcAddress(GetModuleHandle(TEXT("user32.dll")), "SetDisplayAutoRotationPreferences"); if(SetDisplayAutoRotationPreferences) SetDisplayAutoRotationPreferences(ORIENTATION_PREFERENCE_LANDSCAPE); #else SetDisplayAutoRotationPreferences(ORIENTATION_PREFERENCE_LANDSCAPE); #endif g_hinst = hInstance; #if _WIN32_WINNT >= 0x0400 & defined(_ATL_FREE_THREADED) HRESULT hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED); #else HRESULT hRes = CoInitialize(NULL); #endif _ASSERTE(SUCCEEDED(hRes)); _Module.Init(ObjectMap, hInstance, &LIBID_VPinballLib); bool fFile = false; bool fPlay = false; bool bRun = true; TCHAR szTableFileName[_MAX_PATH] = {0}; int nRet = 0; int nArgs; LPSTR *szArglist = CommandLineToArgvA(GetCommandLine(), &nArgs); for(int i=0; i < nArgs; ++i) { if (lstrcmpi(szArglist[i], _T("-UnregServer"))==0 || lstrcmpi(szArglist[i], _T("/UnregServer"))==0) { _Module.UpdateRegistryFromResource(IDR_VPINBALL, FALSE); nRet = _Module.UnregisterServer(TRUE); bRun = false; break; } if (lstrcmpi(szArglist[i], _T("-RegServer"))==0 || lstrcmpi(szArglist[i], _T("/RegServer"))==0) { _Module.UpdateRegistryFromResource(IDR_VPINBALL, TRUE); nRet = _Module.RegisterServer(TRUE); bRun = false; break; } const bool editfile = (lstrcmpi(szArglist[i], _T("-Edit"))==0 || lstrcmpi(szArglist[i], _T("/Edit"))==0); const bool playfile = (lstrcmpi(szArglist[i], _T("-Play"))==0 || lstrcmpi(szArglist[i], _T("/Play"))==0); if ((editfile || playfile) && (i+1 < nArgs)) { fFile = true; fPlay = playfile; // Remove leading - or / char* filename; if((szArglist[i+1][0] == '-') || (szArglist[i+1][0] == '/')) filename = szArglist[i+1]+1; else filename = szArglist[i+1]; // Remove " " if(filename[0] == '"') { strcpy_s(szTableFileName,filename+1); szTableFileName[lstrlen(szTableFileName)] = '\0'; } else strcpy_s(szTableFileName,filename); // Add current path char szLoadDir[MAX_PATH]; if(szTableFileName[1] != ':') { GetCurrentDirectory(MAX_PATH,szLoadDir); strcat_s(szLoadDir,"\\"); strcat_s(szLoadDir,szTableFileName); strcpy_s(szTableFileName,szLoadDir); } else // Or set from table path if(playfile) { PathFromFilename(szTableFileName, szLoadDir); SetCurrentDirectory(szLoadDir); } if(playfile) VPinball::SetOpenMinimized(); break; } } free(szArglist); // load and register VP type library for COM integration char szFileName[_MAX_PATH]; if (GetModuleFileName(hInstance, szFileName, _MAX_PATH)) { ITypeLib *ptl = NULL; MAKE_WIDEPTR_FROMANSI(wszFileName, szFileName); if (SUCCEEDED(LoadTypeLib(wszFileName, &ptl))) { // first try to register system-wide (if running as admin) HRESULT hr = RegisterTypeLib(ptl, wszFileName, NULL); if (!SUCCEEDED(hr)) { // if failed, register only for current user hr = RegisterTypeLibForUser(ptl, wszFileName, NULL); if (!SUCCEEDED(hr)) MessageBox(0, "Could not register type library. Try running Visual Pinball as administrator.", "Error", MB_ICONWARNING); } ptl->Release(); } else MessageBox(0, "Could not load type library.", "Error", MB_ICONSTOP); } if (bRun) { #if _WIN32_WINNT >= 0x0400 & defined(_ATL_FREE_THREADED) hRes = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED); _ASSERTE(SUCCEEDED(hRes)); hRes = CoResumeClassObjects(); #else hRes = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE); #endif _ASSERTE(SUCCEEDED(hRes)); INITCOMMONCONTROLSEX iccex; iccex.dwSize = sizeof(INITCOMMONCONTROLSEX); iccex.dwICC = ICC_COOL_CLASSES; InitCommonControlsEx(&iccex); { EditableRegistry::RegisterEditable<Bumper>(); EditableRegistry::RegisterEditable<Decal>(); EditableRegistry::RegisterEditable<DispReel>(); EditableRegistry::RegisterEditable<Flasher>(); EditableRegistry::RegisterEditable<Flipper>(); EditableRegistry::RegisterEditable<Gate>(); EditableRegistry::RegisterEditable<Kicker>(); EditableRegistry::RegisterEditable<Light>(); EditableRegistry::RegisterEditable<LightSeq>(); EditableRegistry::RegisterEditable<Plunger>(); EditableRegistry::RegisterEditable<Primitive>(); EditableRegistry::RegisterEditable<Ramp>(); EditableRegistry::RegisterEditable<Rubber>(); EditableRegistry::RegisterEditable<Spinner>(); EditableRegistry::RegisterEditable<Surface>(); EditableRegistry::RegisterEditable<Textbox>(); EditableRegistry::RegisterEditable<Timer>(); EditableRegistry::RegisterEditable<Trigger>(); } g_pvp = new VPinball(); g_pvp->AddRef(); g_pvp->Init(); g_haccel = LoadAccelerators(g_hinst,MAKEINTRESOURCE(IDR_VPACCEL)); if (fFile) { g_pvp->LoadFileName(szTableFileName); if (fPlay) g_pvp->DoPlay(); } // VBA APC handles message loop (bastards) g_pvp->MainMsgLoop(); g_pvp->Release(); DestroyAcceleratorTable(g_haccel); _Module.RevokeClassObjects(); Sleep(dwPause); //wait for any threads to finish } _Module.Term(); CoUninitialize(); #ifdef _CRTDBG_MAP_ALLOC #ifdef DEBUG_XXX //disable this in perference to DevPartner _CrtSetDumpClient(MemLeakAlert); #endif _CrtDumpMemoryLeaks(); #endif //SET_CRT_DEBUG_FIELD( _CRTDBG_LEAK_CHECK_DF ); return nRet; }
// (Un)Register the ActiveX server in the registry. // The QAxFactory implementation provides the information. HRESULT UpdateRegistry(BOOL bRegister) { qAxIsServer = false; const QChar dot(QLatin1Char('.')); const QChar slash(QLatin1Char('/')); QString file = QString::fromWCharArray(qAxModuleFilename); const QString module = QFileInfo(file).baseName(); const QString appId = qAxFactory()->appID().toString().toUpper(); const QString libId = qAxFactory()->typeLibID().toString().toUpper(); const QString libFile = qAxInit(); TLIBATTR *libAttr = 0; if (qAxTypeLibrary) qAxTypeLibrary->GetLibAttr(&libAttr); if (!libAttr) return SELFREG_E_TYPELIB; bool userFallback = false; if (bRegister) { if (RegisterTypeLib(qAxTypeLibrary, reinterpret_cast<wchar_t *>(const_cast<ushort *>(libFile.utf16())), 0) == TYPE_E_REGISTRYACCESS) { #ifndef Q_CC_MINGW // MinGW does not have RegisterTypeLibForUser() implemented so we cannot fallback in this case RegisterTypeLibForUser(qAxTypeLibrary, reinterpret_cast<wchar_t *>(const_cast<ushort *>(libFile.utf16())), 0); userFallback = true; #endif } } else { if (UnRegisterTypeLib(libAttr->guid, libAttr->wMajorVerNum, libAttr->wMinorVerNum, libAttr->lcid, libAttr->syskind) == TYPE_E_REGISTRYACCESS) { #ifndef Q_CC_MINGW // MinGW does not have RegisterTypeLibForUser() implemented so we cannot fallback in this case UnRegisterTypeLibForUser(libAttr->guid, libAttr->wMajorVerNum, libAttr->wMinorVerNum, libAttr->lcid, libAttr->syskind); userFallback = true; #endif } } if (userFallback) qWarning("QAxServer: Falling back to registering as user for %s due to insufficient permission.", qPrintable(module)); qAxTypeLibrary->ReleaseTLibAttr(libAttr); // check whether the user has permission to write to HKLM\Software\Classes // if not, use HKCU\Software\Classes QString keyPath(QLatin1String("HKEY_LOCAL_MACHINE\\Software\\Classes")); QScopedPointer<QSettings> settings(new QSettings(keyPath, QSettings::NativeFormat)); if (userFallback || !settings->isWritable()) { keyPath = QLatin1String("HKEY_CURRENT_USER\\Software\\Classes"); settings.reset(new QSettings(keyPath, QSettings::NativeFormat)); } // we try to create the ActiveX widgets later on... bool delete_qApp = false; if (!qApp) { static int argc = 0; // static lifetime, since it's passed as reference to QApplication, which has a lifetime exceeding the stack frame (void)new QApplication(argc, 0); delete_qApp = true; } if (bRegister) { if (qAxOutProcServer) { settings->setValue(QLatin1String("/AppID/") + appId + QLatin1String("/."), module); settings->setValue(QLatin1String("/AppID/") + module + QLatin1String(".EXE/AppID"), appId); } const QStringList keys = qAxFactory()->featureList(); for (const QString &classNameIn : keys) { QObject *object = qAxFactory()->createObject(classNameIn); const QMetaObject *mo = qAxFactory()->metaObject(classNameIn); const QString classId = qAxFactory()->classID(classNameIn).toString().toUpper(); const QString className = qax_clean_type(classNameIn, mo); if (object) { // don't register subobject classes QString classVersion = mo ? QString::fromLatin1(mo->classInfo(mo->indexOfClassInfo("Version")).value()) : QString(); if (classVersion.isNull()) classVersion = QLatin1String("1.0"); bool insertable = mo && !qstricmp(mo->classInfo(mo->indexOfClassInfo("Insertable")).value(), "yes"); bool control = object->isWidgetType(); QString classMajorVersion = classVersion.left(classVersion.indexOf(dot)); uint olemisc = OLEMISC_SETCLIENTSITEFIRST |OLEMISC_ACTIVATEWHENVISIBLE |OLEMISC_INSIDEOUT |OLEMISC_CANTLINKINSIDE |OLEMISC_RECOMPOSEONRESIZE; if (!control) olemisc |= OLEMISC_INVISIBLEATRUNTIME; else if (object->findChild<QMenuBar*>() && !qax_disable_inplaceframe) olemisc |= OLEMISC_WANTSTOMENUMERGE; const QString versionLessProgId = module + dot + className; const QString progId = versionLessProgId + dot + classMajorVersion; QString key = slash + progId; settings->setValue(key + QLatin1String("/."), className + QLatin1String(" Class")); settings->setValue(key + QLatin1String("/CLSID/."), classId); if (insertable) settings->setValue(key + QLatin1String("/Insertable/."), QVariant(QLatin1String(""))); key = slash + module + dot + className; settings->setValue(key + QLatin1String("/."), className + QLatin1String(" Class")); settings->setValue(key + QLatin1String("/CLSID/."), classId); settings->setValue(key + QLatin1String("/CurVer/."), progId); key = QLatin1String("/CLSID/") + classId; settings->setValue(key + QLatin1String("/."), className + QLatin1String(" Class")); if (file.endsWith(QLatin1String("exe"), Qt::CaseInsensitive)) settings->setValue(key + QLatin1String("/AppID"), appId); if (control) settings->setValue(key + QLatin1String("/Control/."), QVariant(QLatin1String(""))); if (insertable) settings->setValue(key + QLatin1String("/Insertable/."), QVariant(QLatin1String(""))); if (file.endsWith(QLatin1String("dll"), Qt::CaseInsensitive)) settings->setValue(key + QLatin1String("/InProcServer32/."), file); else settings->setValue(key + QLatin1String("/LocalServer32/."), QLatin1Char('\"') + file + QLatin1String("\" -activex")); settings->setValue(key + QLatin1String("/MiscStatus/."), control ? QLatin1String("1") : QLatin1String("0")); settings->setValue(key + QLatin1String("/MiscStatus/1/."), QString::number(olemisc)); settings->setValue(key + QLatin1String("/Programmable/."), QVariant(QLatin1String(""))); settings->setValue(key + QLatin1String("/ToolboxBitmap32/."), QLatin1Char('\"') + file + QLatin1String("\", 101")); settings->setValue(key + QLatin1String("/TypeLib/."), libId); settings->setValue(key + QLatin1String("/Version/."), classVersion); settings->setValue(key + QLatin1String("/VersionIndependentProgID/."), versionLessProgId); settings->setValue(key + QLatin1String("/ProgID/."), progId); QString mime = QLatin1String(mo->classInfo(mo->indexOfClassInfo("MIME")).value()); if (!mime.isEmpty()) { QStringList mimeTypes = mime.split(QLatin1Char(';')); for (int m = 0; m < mimeTypes.count(); ++m) { mime = mimeTypes.at(m); if (mime.isEmpty()) continue; QString extension; while (mime.contains(QLatin1Char(':'))) { extension = mime.mid(mime.lastIndexOf(QLatin1Char(':')) + 1); mime.chop(extension.length() + 1); // Prepend '.' before extension, if required. extension = extension.trimmed(); if (!extension.startsWith(dot)) extension.prepend(dot); } if (!extension.isEmpty()) { key = slash + extension; settings->setValue(key + QLatin1String("/."), module + dot + className); settings->setValue(key + QLatin1String("/Content Type"), mime); mime.replace(slash, QLatin1Char('\\')); key = QLatin1String("/MIME/Database/Content Type/") + mime; settings->setValue(key + QLatin1String("/CLSID"), classId); settings->setValue(key + QLatin1String("/Extension"), extension); } } } delete object; qCDebug(lcAxRegistration).nospace().noquote() << "Registered \"" << progId << "\"/" << classId << ", \"" << file << "\" at \"" << keyPath << "\", insertable=" << insertable << ", control=" << control << ", olemisc=" << hex << showbase << olemisc << ", mime=" << mime; } qAxFactory()->registerClass(classNameIn, settings.data()); } } else { if (qAxOutProcServer) { settings->remove(QLatin1String("/AppID/") + appId + QLatin1String("/.")); settings->remove(QLatin1String("/AppID/") + module + QLatin1String(".EXE")); } const QStringList keys = qAxFactory()->featureList(); for (const QString &classNameIn : keys) { const QMetaObject *mo = qAxFactory()->metaObject(classNameIn); const QString classId = qAxFactory()->classID(classNameIn).toString().toUpper(); const QString className = qax_clean_type(classNameIn, mo); QString classVersion = mo ? QString::fromLatin1(mo->classInfo(mo->indexOfClassInfo("Version")).value()) : QString(); if (classVersion.isNull()) classVersion = QLatin1String("1.0"); const QString classMajorVersion = classVersion.left(classVersion.indexOf(dot)); qAxFactory()->unregisterClass(classNameIn, settings.data()); const QString progId = module + dot + className + dot + classMajorVersion; QString key = slash + progId; settings->remove(key + QLatin1String("/CLSID/.")); settings->remove(key + QLatin1String("/Insertable/.")); settings->remove(key + QLatin1String("/.")); settings->remove(key); key = slash + module + dot + className; settings->remove(key + QLatin1String("/CLSID/.")); settings->remove(key + QLatin1String("/CurVer/.")); settings->remove(key + QLatin1String("/.")); settings->remove(key); key = QLatin1String("/CLSID/") + classId; settings->remove(key + QLatin1String("/AppID")); settings->remove(key + QLatin1String("/Control/.")); settings->remove(key + QLatin1String("/Insertable/.")); settings->remove(key + QLatin1String("/InProcServer32/.")); settings->remove(key + QLatin1String("/LocalServer32/.")); settings->remove(key + QLatin1String("/MiscStatus/1/.")); settings->remove(key + QLatin1String("/MiscStatus/.")); settings->remove(key + QLatin1String("/Programmable/.")); settings->remove(key + QLatin1String("/ToolboxBitmap32/.")); settings->remove(key + QLatin1String("/TypeLib/.")); settings->remove(key + QLatin1String("/Version/.")); settings->remove(key + QLatin1String("/VersionIndependentProgID/.")); settings->remove(key + QLatin1String("/ProgID/.")); settings->remove(key + QLatin1String("/.")); settings->remove(key); QString mime = QLatin1String(mo->classInfo(mo->indexOfClassInfo("MIME")).value()); if (!mime.isEmpty()) { QStringList mimeTypes = mime.split(QLatin1Char(';')); for (int m = 0; m < mimeTypes.count(); ++m) { mime = mimeTypes.at(m); if (mime.isEmpty()) continue; QString extension; while (mime.contains(QLatin1Char(':'))) { extension = mime.mid(mime.lastIndexOf(QLatin1Char(':')) + 1); mime.chop(extension.length() + 1); // Prepend '.' before extension, if required. extension = extension.trimmed(); if (extension[0] != dot) extension.prepend(dot); } if (!extension.isEmpty()) { key = slash + extension; settings->remove(key + QLatin1String("/Content Type")); settings->remove(key + QLatin1String("/.")); settings->remove(key); mime.replace(slash, QLatin1Char('\\')); key = QLatin1String("/MIME/Database/Content Type/") + mime; settings->remove(key + QLatin1String("/Extension")); settings->remove(key + QLatin1String("/CLSID")); settings->remove(key + QLatin1String("/.")); settings->remove(key); } } } qCDebug(lcAxRegistration).nospace().noquote() << "Unregistered \"" << progId << "\"/" << classId << ", \"" << file << "\" from \"" << keyPath << '"'; } } if (delete_qApp) delete qApp; qAxCleanup(); if (settings->status() == QSettings::NoError) return S_OK; qWarning() << module << ": Error writing to " << keyPath; return SELFREG_E_CLASS; }
virtual BOOL InitInstance() { #ifdef CRASH_HANDLER rde::CrashHandler::Init(); #endif // disable auto-rotate on tablets #if (WINVER <= 0x0601) SetDisplayAutoRotationPreferences = (pSDARP)GetProcAddress(GetModuleHandle(TEXT("user32.dll")), "SetDisplayAutoRotationPreferences"); if (SetDisplayAutoRotationPreferences) SetDisplayAutoRotationPreferences(ORIENTATION_PREFERENCE_LANDSCAPE); #else SetDisplayAutoRotationPreferences(ORIENTATION_PREFERENCE_LANDSCAPE); #endif g_hinst = theInstance; #if _WIN32_WINNT >= 0x0400 & defined(_ATL_FREE_THREADED) hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED); #else hRes = CoInitialize(NULL); #endif _ASSERTE(SUCCEEDED(hRes)); _Module.Init(ObjectMap, theInstance, &LIBID_VPinballLib); fFile = false; fPlay = false; fPov = false; bRun = true; int nRet = 0; memset(szTableFileName, 0, _MAX_PATH); // Start VP with file dialog open and then also playing that one? int stos; HRESULT hr = GetRegInt("Editor", "SelectTableOnStart", &stos); if (hr != S_OK) stos = 1; // The default = on if (stos) { fFile = true; fPlay = true; fPov = false; } int nArgs; LPSTR *szArglist = CommandLineToArgvA(GetCommandLine(), &nArgs); for (int i = 0; i < nArgs; ++i) { if (lstrcmpi(szArglist[i], _T("-h")) == 0 || lstrcmpi(szArglist[i], _T("/h")) == 0 || lstrcmpi(szArglist[i], _T("-Help")) == 0 || lstrcmpi(szArglist[i], _T("/Help")) == 0 || lstrcmpi(szArglist[i], _T("-?")) == 0 || lstrcmpi(szArglist[i], _T("/?")) == 0) { ShowError("-UnregServer Unregister VP functions\n-RegServer Register VP functions\n\n-DisableTrueFullscreen Force-disable True Fullscreen setting\n\n-Edit [filename] load file into VP\n-Play [filename] load and play file\n-Pov [filename] load, export pov and close"); bRun = false; break; } if (lstrcmpi(szArglist[i], _T("-UnregServer")) == 0 || lstrcmpi(szArglist[i], _T("/UnregServer")) == 0) { _Module.UpdateRegistryFromResource(IDR_VPINBALL, FALSE); nRet = _Module.UnregisterServer(TRUE); bRun = false; break; } if (lstrcmpi(szArglist[i], _T("-RegServer")) == 0 || lstrcmpi(szArglist[i], _T("/RegServer")) == 0) { _Module.UpdateRegistryFromResource(IDR_VPINBALL, TRUE); nRet = _Module.RegisterServer(TRUE); bRun = false; break; } disableTrueFullscreen |= (lstrcmpi(szArglist[i], _T("-DisableTrueFullscreen")) == 0 || lstrcmpi(szArglist[i], _T("/DisableTrueFullscreen")) == 0); const bool editfile = (lstrcmpi(szArglist[i], _T("-Edit")) == 0 || lstrcmpi(szArglist[i], _T("/Edit")) == 0); const bool playfile = (lstrcmpi(szArglist[i], _T("-Play")) == 0 || lstrcmpi(szArglist[i], _T("/Play")) == 0); const bool povfile = (lstrcmpi(szArglist[i], _T("-Pov")) == 0 || lstrcmpi(szArglist[i], _T("/Pov")) == 0); if ((editfile || playfile || povfile) && (i + 1 < nArgs)) { fFile = true; fPlay = playfile; fPov = povfile; // Remove leading - or / char* filename; if ((szArglist[i + 1][0] == '-') || (szArglist[i + 1][0] == '/')) filename = szArglist[i + 1] + 1; else filename = szArglist[i + 1]; // Remove " " if (filename[0] == '"') { strcpy_s(szTableFileName, filename + 1); szTableFileName[lstrlen(szTableFileName) - 1] = '\0'; } else strcpy_s(szTableFileName, filename); // Add current path char szLoadDir[MAX_PATH]; if (szTableFileName[1] != ':') { GetCurrentDirectory(MAX_PATH, szLoadDir); strcat_s(szLoadDir, "\\"); strcat_s(szLoadDir, szTableFileName); strcpy_s(szTableFileName, szLoadDir); } else // Or set from table path if (playfile) { PathFromFilename(szTableFileName, szLoadDir); SetCurrentDirectory(szLoadDir); } if (playfile || povfile) VPinball::SetOpenMinimized(); break; } } free(szArglist); // load and register VP type library for COM integration char szFileName[_MAX_PATH]; if (GetModuleFileName(theInstance, szFileName, _MAX_PATH)) { ITypeLib *ptl = NULL; MAKE_WIDEPTR_FROMANSI(wszFileName, szFileName); if (SUCCEEDED(LoadTypeLib(wszFileName, &ptl))) { // first try to register system-wide (if running as admin) hr = RegisterTypeLib(ptl, wszFileName, NULL); if (!SUCCEEDED(hr)) { // if failed, register only for current user hr = RegisterTypeLibForUser(ptl, wszFileName, NULL); if (!SUCCEEDED(hr)) MessageBox(0, "Could not register type library. Try running Visual Pinball as administrator.", "Error", MB_ICONWARNING); } ptl->Release(); } else MessageBox(0, "Could not load type library.", "Error", MB_ICONSTOP); } //SET_CRT_DEBUG_FIELD( _CRTDBG_LEAK_CHECK_DF ); return TRUE; }