/************************************************************************ MeOS - Orienteering Software Copyright (C) 2009-2024 Melin Software HB This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Melin Software HB - software@melin.nu - www.melin.nu Eksoppsvägen 16, SE-75646 UPPSALA, Sweden ************************************************************************/ // meos.cpp : Defines the entry point for the application. // #include "stdafx.h" #include "resource.h" #include #include "oEvent.h" #include "xmlparser.h" #include "recorder.h" #include "gdioutput.h" #include "commctrl.h" #include "SportIdent.h" #include "TabBase.h" #include "TabCompetition.h" #include "TabAuto.h" #include "TabClass.h" #include "TabCourse.h" #include "TabControl.h" #include "TabSI.h" #include "TabList.h" #include "TabTeam.h" #include "TabSpeaker.h" #include "TabMulti.h" #include "TabRunner.h" #include "TabClub.h" #include "progress.h" #include "inthashmap.h" #include #include "localizer.h" #include "intkeymap.hpp" #include "intkeymapimpl.hpp" #include "download.h" #include "meos_util.h" #include #include "random.h" #include "metalist.h" #include "gdiconstants.h" #include "socket.h" #include "autotask.h" #include "meosexception.h" #include "parser.h" #include "restserver.h" #include "autocomplete.h" #include "image.h" #include "csvparser.h" #include "generalresult.h" int defaultCodePage = 1252; Image image; gdioutput *gdi_main=0; oEvent *gEvent=0; SportIdent *gSI=0; Localizer lang; AutoTask *autoTask = 0; #ifdef _DEBUG bool enableTests = true; #else bool enableTests = false; #endif vector gdi_extra; void initMySQLCriticalSection(bool init); HWND hWndMain; HWND hWndWorkspace; #define MAX_LOADSTRING 100 #pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") void removeTempFiles(); void Setup(bool overwrite, bool overwriteAll); // Global Variables: HINSTANCE hInst; // current instance TCHAR szTitle[MAX_LOADSTRING]; // The title bar text TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text TCHAR szWorkSpaceClass[MAX_LOADSTRING]; // The title bar text // Foward declarations of functions included in this code module: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK WorkSpaceWndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam); void registerToolbar(HINSTANCE hInstance); extern const wchar_t *szToolClass; HHOOK g_hhk; //- handle to the hook procedure. HWND hMainTab = nullptr; HIMAGELIST imageList = nullptr; list *tabList = nullptr; void scrollVertical(gdioutput *gdi, int yInc, HWND hWnd); static size_t currentFocusIx = 0; void resetSaveTimer() { if (autoTask) autoTask->resetSaveTimer(); } void LoadPage(const string &name) { list::iterator it; for (it=tabList->begin(); it!=tabList->end(); ++it) { if (it->name==name) it->loadPage(*gdi_main); } } void LoadClassPage(gdioutput &gdi) { LoadPage("Klasser"); } void dumpLeaks() { _CrtDumpMemoryLeaks(); } void LoadPage(gdioutput &gdi, TabType type) { gdi.setWaitCursor(true); TabBase *t = gdi.getTabs().get(type); if (t) t->loadPage(gdi); gdi.setWaitCursor(false); } // Path to settings file static wchar_t settings[260]; // Startup path wchar_t programPath[MAX_PATH]; // Exe path wchar_t exePath[MAX_PATH]; void mainMessageLoop(HACCEL hAccelTable, DWORD time) { MSG msg; BOOL bRet; if (time > 0) { time += GetTickCount(); } // Main message loop: while ( (bRet = GetMessage(&msg, NULL, 0, 0)) != 0 ) { if (bRet == -1) return; if (gEvent != 0) RestServer::computeRequested(*gEvent); if (hAccelTable == 0 || !TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } if (time != 0) { if (GetTickCount() > time) return; } } } INT_PTR CALLBACK splashDialogProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ); int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { hInst = hInstance; // Store instance handle in our global variable atexit(dumpLeaks); // _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); if (strstr(lpCmdLine, "-s") != 0) { Setup(true, false); exit(0); } else if (strstr(lpCmdLine, "-test") != 0) { enableTests = true; } HWND hSplash = nullptr; if (strstr(lpCmdLine, "-nosplash") == 0) { hSplash = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_SPLASH), nullptr, splashDialogProc); ShowWindow(hSplash, SW_SHOW); UpdateWindow(hSplash); } DWORD splashStart = GetTickCount(); for (int k = 0; k < 100; k++) { RunnerStatusOrderMap[k] = 0; } RunnerStatusOrderMap[StatusOK] = 0; RunnerStatusOrderMap[StatusNoTiming] = 1; RunnerStatusOrderMap[StatusOutOfCompetition] = 2; RunnerStatusOrderMap[StatusMAX] = 3; RunnerStatusOrderMap[StatusMP] = 4; RunnerStatusOrderMap[StatusDNF] = 5; RunnerStatusOrderMap[StatusDQ] = 6; RunnerStatusOrderMap[StatusCANCEL] = 7; RunnerStatusOrderMap[StatusDNS] = 8; RunnerStatusOrderMap[StatusUnknown] = 9; RunnerStatusOrderMap[StatusNotCompetiting] = 10; lang.init(); StringCache::getInstance().init(); for (RunnerStatus st : getAllRunnerStatus()) { if (st != StatusOK) assert(RunnerStatusOrderMap[st] > 0); oAbstractRunner::encodeStatus(st); } GetCurrentDirectory(MAX_PATH, programPath); bool utfRecode = false; if (utfRecode) { vector dyn; expandDirectory(L".", L"*.cpp", dyn); expandDirectory(L".", L"*.h", dyn); expandDirectory(L"./meosdb", L"*.cpp", dyn); expandDirectory(L"./meosdb", L"*.h", dyn); for (auto &f : dyn) csvparser::convertUTF(f); } GetModuleFileName(NULL, exePath, MAX_PATH); int lastDiv = -1; for (int i = 0; i < MAX_PATH; i++) { if (exePath[i] == 0) break; if (exePath[i] == '\\' || exePath[i] == '/') lastDiv = i; } if (lastDiv != -1) exePath[lastDiv] = 0; else exePath[0] = 0; getUserFile(settings, L"meoswpref.xml"); Parser::test(); int rInit = (GetTickCount() / 100); InitRanom(rInit, rInit/379); tabList=new list; HACCEL hAccelTable; gdi_main = new gdioutput("main", 1.0); gdi_extra.push_back(gdi_main); try { gEvent = new oEvent(*gdi_main); gEvent->setMainEvent(); } catch (meosException &ex) { gdi_main->alert(wstring(L"Failed to create base event: ") + ex.wwhat()); return 0; } catch (std::exception &ex) { gdi_main->alert(string("Failed to create base event: ") + ex.what()); return 0; } if (fileExists(settings)) { gEvent->loadProperties(settings); } else { wchar_t oldSettings[260]; // Read from older version getUserFile(oldSettings, L"meospref.xml"); gEvent->loadProperties(oldSettings); } gEvent->clear(); lang.get().addLangResource(L"English", L"104"); lang.get().addLangResource(L"Svenska", L"103"); lang.get().addLangResource(L"Deutsch", L"105"); lang.get().addLangResource(L"Dansk", L"106"); lang.get().addLangResource(L"Český", L"108"); lang.get().addLangResource(L"Français", L"110"); lang.get().addLangResource(L"Español", L"111"); lang.get().addLangResource(L"Russian", L"107"); lang.get().addLangResource(L"Ukrainian", L"112"); lang.get().addLangResource(L"Portuguese", L"113"); if (fileExists(L"extra.lng")) { lang.get().addLangResource(L"Extraspråk", L"extra.lng"); } else { wchar_t lpath[260]; getUserFile(lpath, L"extra.lng"); if (fileExists(lpath)) lang.get().addLangResource(L"Extraspråk", lpath); } wstring defLang = gEvent->getPropertyString("Language", L"Svenska"); defaultCodePage = gEvent->getPropertyInt("CodePage", 1252); // Backward compatibility if (defLang==L"103") defLang = L"Svenska"; else if (defLang==L"104") defLang = L"English"; gEvent->setProperty("Language", defLang); try { lang.get().loadLangResource(defLang); } catch (std::exception &) { lang.get().loadLangResource(L"Svenska"); } try { vector res; #ifdef _DEBUG expandDirectory(L".\\..\\Lists\\", L"*.lxml", res); expandDirectory(L".\\..\\Lists\\", L"*.listdef", res); #endif if (exePath[0]) { expandDirectory(exePath, L"*.lxml", res); expandDirectory(exePath, L"*.listdef", res); } expandDirectory(programPath, L"*.lxml", res); expandDirectory(programPath, L"*.listdef", res); wchar_t listpath[MAX_PATH]; getUserFile(listpath, L""); expandDirectory(listpath, L"*.lxml", res); expandDirectory(listpath, L"*.listdef", res); wstring err; set processed; for (size_t k = 0; kgetListContainer().load(MetaListContainer::InternalList, xlist, true); } catch (meosException &ex) { wstring errLoc = L"Kunde inte ladda X\n\n(Y)#" + wstring(listpath) + L"#" + lang.tl(ex.wwhat()); if (err.empty()) err = lang.tl(errLoc); else err += L"\n" + lang.tl(errLoc); } catch (std::exception &ex) { wstring errLoc = L"Kunde inte ladda X\n\n(Y)#" + wstring(listpath) + L"#" + lang.tl(ex.what()); if (err.empty()) err = lang.tl(errLoc); else err += L"\n" + lang.tl(errLoc); } } if (!err.empty()) gdi_main->alert(err); } catch (meosException &ex) { gdi_main->alert(ex.wwhat()); } catch (std::exception &ex) { gdi_main->alert(ex.what()); } gEvent->openRunnerDatabase(L"database"); wcscpy_s(szTitle, L"MeOS"); wcscpy_s(szWindowClass, L"MeosMainClass"); wcscpy_s(szWorkSpaceClass, L"MeosWorkSpace"); MyRegisterClass(hInstance); registerToolbar(hInstance); int defSize = 0; { RECT desktop; const HWND hDesktop = GetDesktopWindow(); // Get the size of screen to the variable desktop GetWindowRect(hDesktop, &desktop); int d = max(desktop.right, desktop.bottom); if (d <= 1024) defSize = 0; else if (d <= 2000) defSize = 1; else if (d <= 2500) defSize = 2; else defSize = 3; } gdi_main->setFont(gEvent->getPropertyInt("TextSize", defSize), gEvent->getPropertyString("TextFont", L"Arial")); if (hSplash != nullptr) { DWORD startupToc = GetTickCount() - splashStart; Sleep(min(1000, max(0, 700 - startupToc))); } // Perform application initialization: if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } RECT rc; GetClientRect(hWndMain, &rc); SendMessage(hWndMain, WM_SIZE, 0, MAKELONG(rc.right, rc.bottom)); gdi_main->init(hWndWorkspace, hWndMain, hMainTab); gdi_main->getTabs().get(TCmpTab)->loadPage(*gdi_main); image.loadImage(IDI_MEOSEDIT, Image::ImageMethod::Default); autoTask = new AutoTask(hWndMain, *gEvent, *gdi_main); autoTask->setTimers(); // Install a hook procedure to monitor the message stream for mouse // messages intended for the controls in the dialog box. g_hhk = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, (HINSTANCE) NULL, GetCurrentThreadId()); hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_MEOS); DestroyWindow(hSplash); initMySQLCriticalSection(true); // Main message loop: mainMessageLoop(hAccelTable, 0); TabAuto::tabAutoRegister(nullptr); tabList->clear(); delete tabList; tabList = nullptr; delete autoTask; autoTask = 0; for (size_t k = 0; kgetHWNDMain()); if (k < gdi_extra.size()) { delete gdi_extra[k]; gdi_extra[k] = 0; } } } gdi_main = nullptr; gdi_extra.clear(); if (gEvent) gEvent->saveProperties(settings); delete gEvent; gEvent = nullptr; initMySQLCriticalSection(false); removeTempFiles(); #ifdef _DEBUG lang.get().debugDump(L"untranslated.txt", L"translated.txt"); #endif StringCache::getInstance().clear(); lang.unload(); return 0; } // // FUNCTION: MyRegisterClass() // // PURPOSE: Registers the window class. // // COMMENTS: // // This function and its usage is only necessary if you want this code // to be compatible with Win32 systems prior to the 'RegisterClassEx' // function that was added to Windows 95. It is important to call this function // so that the application will get 'well formed' small icons associated // with it. // ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = (WNDPROC)WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_MEOS); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = 0;//(LPCSTR)IDC_MEOS; wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); RegisterClassEx(&wcex); wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; wcex.lpfnWndProc = (WNDPROC)WorkSpaceWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_MEOS); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = 0; wcex.lpszMenuName = 0; wcex.lpszClassName = szWorkSpaceClass; wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); RegisterClassEx(&wcex); AutoCompleteInfo::registerAutoClass(); return true; } // GetMsgProc - monitors the message stream for mouse messages intended // for a control window in the dialog box. // Returns a message-dependent value. // nCode - hook code. // wParam - message flag (not used). // lParam - address of an MSG structure. LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam) { MSG *lpmsg; lpmsg = (MSG *) lParam; if (nCode < 0 || !(IsChild(hWndWorkspace, lpmsg->hwnd))) return (CallNextHookEx(g_hhk, nCode, wParam, lParam)); switch (lpmsg->message) { case WM_MOUSEMOVE: case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_RBUTTONDOWN: case WM_RBUTTONUP: if (gdi_main->getToolTip() != NULL) { MSG msg; msg.lParam = lpmsg->lParam; msg.wParam = lpmsg->wParam; msg.message = lpmsg->message; msg.hwnd = lpmsg->hwnd; SendMessage(gdi_main->getToolTip(), TTM_RELAYEVENT, 0, (LPARAM) (LPMSG) &msg); } break; default: break; } return (CallNextHookEx(g_hhk, nCode, wParam, lParam)); } void flushEvent(const string &id, const string &origin, DWORD data, int extraData) { for (size_t k = 0; kmakeEvent(id, origin, data, extraData, false); } } } LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam) { if (code<0) return CallNextHookEx(0, code, wParam, lParam); gdioutput *gdi = 0; if (size_t(currentFocusIx) < gdi_extra.size()) gdi = gdi_extra[currentFocusIx]; if (!gdi) gdi = gdi_main; HWND hWnd = gdi ? gdi->getHWNDTarget() : 0; bool ctrlPressed = (GetKeyState(VK_CONTROL) & 0x8000) == 0x8000; bool shiftPressed = (GetKeyState(VK_SHIFT) & 0x8000) == 0x8000; //if (code<0) return CallNextHookEx( if (wParam==VK_TAB) { if ( (lParam& (1<<31))) { SHORT state=GetKeyState(VK_SHIFT); if (gdi) { if (state&(1<<16)) gdi->TabFocus(-1); else gdi->TabFocus(1); } } return 1; } else if (wParam==VK_RETURN && (lParam & (1<<31))) { if (gdi) gdi->enter(); } else if (wParam==VK_UP) { bool c = false; if (gdi && (lParam & (1<<31))) c = gdi->upDown(1); if (gdi && gdi->hasAutoComplete()) return 1; if (!c && !(lParam & (1<<31)) && !(gdi && gdi->lockUpDown)) SendMessage(hWnd, WM_VSCROLL, MAKELONG(SB_LINEUP, 0), 0); } else if (wParam == VK_NEXT && !(lParam & (1<<31)) && !(gdi && gdi->lockUpDown)) { SendMessage(hWnd, WM_VSCROLL, MAKELONG(SB_PAGEDOWN, 0), 0); } else if (wParam == VK_PRIOR && !(lParam & (1<<31)) && !(gdi && gdi->lockUpDown)) { SendMessage(hWnd, WM_VSCROLL, MAKELONG(SB_PAGEUP, 0), 0); } else if (wParam==VK_DOWN) { bool c = false; if (gdi && (lParam & (1<<31))) c = gdi->upDown(-1); if (gdi && gdi->hasAutoComplete()) return 1; if (!c && !(lParam & (1<<31)) && !(gdi && gdi->lockUpDown)) SendMessage(hWnd, WM_VSCROLL, MAKELONG(SB_LINEDOWN, 0), 0); } else if (wParam==VK_LEFT && !(lParam & (1<<31))) { if (!gdi || !gdi->hasEditControl()) SendMessage(hWnd, WM_HSCROLL, MAKELONG(SB_LINEUP, 0), 0); } else if (wParam==VK_RIGHT && !(lParam & (1<<31))) { if (!gdi || !gdi->hasEditControl()) SendMessage(hWnd, WM_HSCROLL, MAKELONG(SB_LINEDOWN, 0), 0); } else if (wParam==VK_ESCAPE && (lParam & (1<<31))) { if (gdi) gdi->escape(); } else if (wParam==VK_F2) { ProgressWindow pw(hWnd); pw.init(); for (int k=0;k<=20;k++) { pw.setProgress(k*50); Sleep(100); } //pw.draw(); } else if (ctrlPressed && (wParam == VK_ADD || wParam == VK_SUBTRACT || wParam == VK_F5 || wParam == VK_F6)) { if (gdi) { if (wParam == VK_ADD || wParam == VK_F5) gdi->scaleSize(1.1); else gdi->scaleSize(1.0/1.1); } } else if (wParam == 'C' && ctrlPressed) { if (gdi) gdi->keyCommand(KC_COPY); } else if (wParam == 'V' && ctrlPressed) { if (gdi) gdi->keyCommand(KC_PASTE); } else if (wParam == 'F' && ctrlPressed) { if (gdi) { if (!shiftPressed) gdi->keyCommand(KC_FIND); else gdi->keyCommand(KC_FINDBACK); } } else if (wParam == 'A' && ctrlPressed) { if (gdi) gdi->keyCommand(KC_MARKALL); } else if (wParam == 'D' && ctrlPressed) { if (gdi) gdi->keyCommand(KC_CLEARALL); } else if (wParam == VK_DELETE) { if (gdi) gdi->keyCommand(KC_DELETE); } else if (wParam == 'I' && ctrlPressed) { if (gdi) gdi->keyCommand(KC_INSERT); } else if (wParam == 'P' && ctrlPressed) { if (gdi) gdi->keyCommand(KC_PRINT); } else if (wParam == VK_F5 && !ctrlPressed) { if (gdi) gdi->keyCommand(KC_REFRESH); } else if (wParam == 'M' && ctrlPressed) { if (gdi) gdi->keyCommand(KC_SPEEDUP); } else if (wParam == 'N' && ctrlPressed) { if (gdi) gdi->keyCommand(KC_SLOWDOWN); } else if (wParam == ' ' && ctrlPressed) { if (gdi) gdi->keyCommand(KC_AUTOCOMPLETE); } return 0; } // // FUNCTION: InitInstance(HANDLE, int) // // PURPOSE: Saves instance handle and creates main window // // COMMENTS: // // In this function, we save the instance handle in a global variable and // create and display the main program window. // BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; HWND hDskTop=GetDesktopWindow(); RECT rc; GetClientRect(hDskTop, &rc); int xp = gEvent->getPropertyInt("xpos", 50); int yp = gEvent->getPropertyInt("ypos", 20); int xs = gEvent->getPropertyInt("xsize", max(850, min(int(rc.right)-yp, (rc.right*9)/10))); int ys = gEvent->getPropertyInt("ysize", max(650, min(int(rc.bottom)-yp-40, (rc.bottom*8)/10))); gEvent->setProperty("ypos", yp + 16); gEvent->setProperty("xpos", xp + 32); gEvent->saveProperties(settings); // For other instance starting while running gEvent->setProperty("ypos", yp); gEvent->setProperty("xpos", xp); hWnd = CreateWindowEx(0, szWindowClass, szTitle, WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|WS_CLIPSIBLINGS, xp, yp, max(min(int(rc.right)-yp, xs), 200), max(min(int(rc.bottom)-yp-40, ys), 100), NULL, NULL, hInstance, NULL); if (!hWnd) return FALSE; hWndMain = hWnd; SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, 0, GetCurrentThreadId()); ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); hWnd = CreateWindowEx(0, szWorkSpaceClass, L"WorkSpace", WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS, 50, 200, 200, 100, hWndMain, NULL, hInstance, NULL); if (!hWnd) return FALSE; hWndWorkspace=hWnd; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } void destroyExtraWindows() { for (size_t k = 1; kgetHWNDMain()); } } } string uniqueTag(const char *base) { int j = 0; string b = base; while(true) { string tag = b + itos(j++); if (getExtraWindow(tag, false) == 0) return tag; } } vector getExtraWindows() { vector res; for (size_t k = 0; k < gdi_extra.size(); k++) { if (gdi_extra[k]) res.push_back(gdi_extra[k]->getTag()); } return res; } gdioutput *getExtraWindow(const string &tag, bool toForeGround) { for (size_t k = 0; khasTag(tag)) { if (toForeGround) SetForegroundWindow(gdi_extra[k]->getHWNDMain()); return gdi_extra[k]; } } return 0; } gdioutput *createExtraWindow(const string &tag, const wstring &title, int max_x, int max_y, bool fixedSize) { if (getExtraWindow(tag, false) != 0) throw meosException("Window already exists"); HWND hWnd; HWND hDskTop=GetDesktopWindow(); RECT rc; GetClientRect(hDskTop, &rc); int xp = gEvent->getPropertyInt("xpos", 50) + 16; int yp = gEvent->getPropertyInt("ypos", 20) + 32; for (size_t k = 0; kgetHWNDTarget(); RECT rcc; if (GetWindowRect(hWnd, &rcc)) { xp = max(rcc.left + 16, xp); yp = max(rcc.top + 32, yp); } } } if (xp > rc.right - 100) xp = rc.right - 100; if (yp > rc.bottom - 100) yp = rc.bottom - 100; int xs = max_x, ys = max_y; if (!fixedSize) { xs = gEvent->getPropertyInt("xsize", max(850, min(int(rc.right) - yp, 1124))); ys = gEvent->getPropertyInt("ysize", max(650, min(int(rc.bottom) - yp - 40, 800))); if (max_x > 0) xs = min(max_x, xs); if (max_y > 0) ys = min(max_y, ys); } hWnd = CreateWindowEx(0, szWorkSpaceClass, title.c_str(), WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|WS_CLIPSIBLINGS, xp, yp, max(xs, 200), max(ys, 100), 0, NULL, hInst, NULL); if (!hWnd) return 0; ShowWindow(hWnd, SW_SHOWNORMAL); UpdateWindow(hWnd); gdioutput *gdi = new gdioutput(tag, 1.0); gdi->setFont(gEvent->getPropertyInt("TextSize", 0), gEvent->getPropertyString("TextFont", L"Arial")); gdi->init(hWnd, hWnd, 0); gdi->isTestMode = gdi_main->isTestMode; if (gdi->isTestMode) { if (!gdi_main->cmdAnswers.empty()) { gdi->dbPushDialogAnswer(gdi_main->cmdAnswers.front()); gdi_main->cmdAnswers.pop_front(); } } else { gdi->initRecorder(&gdi_main->getRecorder()); } SetWindowLongPtr(hWnd, GWLP_USERDATA, gdi_extra.size()); currentFocusIx = gdi_extra.size(); gdi_extra.push_back(gdi); return gdi; } /** Returns the tag of the last extra window. */ const string &getLastExtraWindow() { if (gdi_extra.empty()) throw meosException("Empty"); else return gdi_extra.back()->getTag(); } void InsertSICard(gdioutput &gdi, SICard &sic); void createTabs(bool force, bool onlyMain, bool skipTeam, bool skipSpeaker, bool skipEconomy, bool skipLists, bool skipRunners, bool skipCourses, bool skipControls) { static bool onlyMainP = false; static bool skipTeamP = false; static bool skipSpeakerP = false; static bool skipEconomyP = false; static bool skipListsP = false; static bool skipRunnersP = false; static bool skipCoursesP = false; static bool skipControlsP = false; if (!force && onlyMain==onlyMainP && skipTeam==skipTeamP && skipSpeaker==skipSpeakerP && skipEconomy==skipEconomyP && skipLists==skipListsP && skipRunners==skipRunnersP && skipControls==skipControlsP && skipCourses == skipCoursesP) return; if (!tabList) return; onlyMainP = onlyMain; skipTeamP = skipTeam; skipSpeakerP = skipSpeaker; skipEconomyP = skipEconomy; skipListsP = skipLists; skipRunnersP = skipRunners; skipCoursesP = skipCourses; skipControlsP = skipControls; int oldid=TabCtrl_GetCurSel(hMainTab); TabObject *to = 0; for (list::iterator it=tabList->begin();it!=tabList->end();++it) { if (it->id==oldid) { to = &*it; } } if (gdi_main) gdi_main->updateTabFont(); int id = 0; TabCtrl_DeleteAllItems(hMainTab); for (list::iterator it=tabList->begin();it!=tabList->end();++it) { it->setId(-1); if (onlyMain && it->getType() != typeid(TabCompetition) && it->getType() != typeid(TabSI)) continue; if (skipTeam && it->getType() == typeid(TabTeam)) continue; if (skipSpeaker && it->getType() == typeid(TabSpeaker)) continue; if (skipEconomy && it->getType() == typeid(TabClub)) continue; if (skipRunners && it->getType() == typeid(TabRunner)) continue; if (skipCourses && it->getType() == typeid(TabCourse)) continue; if (skipControls && it->getType() == typeid(TabControl)) continue; if (skipLists && (it->getType() == typeid(TabList) || it->getType() == typeid(TabAuto))) continue; TCITEM ti; ti.pszText=(LPWSTR)lang.tl(it->name).c_str(); ti.mask = TCIF_TEXT; if (it->imageId >= 0) ti.mask |= TCIF_IMAGE; ti.iImage = it->imageId; it->setId(id++); TabCtrl_InsertItem(hMainTab, it->id, &ti); } if (to && (to->id)>=0) TabCtrl_SetCurSel(hMainTab, to->id); } void hideTabs() { TabCtrl_DeleteAllItems(hMainTab); } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; static bool connectionAlert = false; switch (message) { case WM_CREATE: tabList->emplace_back(gdi_main->getTabs().get(TCmpTab), "Tävling", 10); tabList->emplace_back(gdi_main->getTabs().get(TRunnerTab), "Deltagare", 6); tabList->emplace_back(gdi_main->getTabs().get(TTeamTab), "Lag(flera)", 7); tabList->emplace_back(gdi_main->getTabs().get(TListTab), "Listor", 5); { TabAuto *ta = (TabAuto *)gdi_main->getTabs().get(TAutoTab); tabList->emplace_back(ta, "Automater", 4); TabAuto::tabAutoRegister(ta); } tabList->emplace_back(gdi_main->getTabs().get(TSpeakerTab), "Speaker", 3); tabList->emplace_back(gdi_main->getTabs().get(TClassTab), "Klasser", 0); tabList->emplace_back(gdi_main->getTabs().get(TCourseTab), "Banor", 1); tabList->emplace_back(gdi_main->getTabs().get(TControlTab), "Kontroller", 2); tabList->emplace_back(gdi_main->getTabs().get(TClubTab), "Klubbar", 8); tabList->emplace_back(gdi_main->getTabs().get(TSITab), "SportIdent", 9); INITCOMMONCONTROLSEX ic; ic.dwSize=sizeof(ic); ic.dwICC=ICC_TAB_CLASSES ; InitCommonControlsEx(&ic); hMainTab = CreateWindowEx(0, WC_TABCONTROL, L"tabs", WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS, 0, 0, 300, 20, hWnd, 0, hInst, 0); imageList = ImageList_Create(24, 24, ILC_COLOR32, 1, 1); { ImageList_Add(imageList, image.loadImage(IDI_MEOSCLASS24, Image::ImageMethod::Default), nullptr); ImageList_Add(imageList, image.loadImage(IDI_MEOSCOURSE24, Image::ImageMethod::Default), nullptr); ImageList_Add(imageList, image.loadImage(IDI_MEOSCONTROL24, Image::ImageMethod::Default), nullptr); ImageList_Add(imageList, image.loadImage(IDI_MEOSANNOUNCER24, Image::ImageMethod::Default), nullptr); ImageList_Add(imageList, image.loadImage(IDI_MEOSSERVICES24, Image::ImageMethod::Default), nullptr); ImageList_Add(imageList, image.loadImage(IDI_MEOSLIST24, Image::ImageMethod::Default), nullptr); ImageList_Add(imageList, image.loadImage(IDI_MEOSRUNNER24, Image::ImageMethod::Default), nullptr); ImageList_Add(imageList, image.loadImage(IDI_MEOSTEAM24, Image::ImageMethod::Default), nullptr); ImageList_Add(imageList, image.loadImage(IDI_MEOSCLUBS24, Image::ImageMethod::Default), nullptr); ImageList_Add(imageList, image.loadImage(IDI_MEOSCARD24, Image::ImageMethod::Default), nullptr); ImageList_Add(imageList, image.loadImage(IDI_MEOSCOMPETITION24, Image::ImageMethod::Default), nullptr); TabCtrl_SetImageList(hMainTab, imageList); } createTabs(true, true, false, false, false, false, false, false, false); SetTimer(hWnd, 4, 10000, 0); //Connection check break; case WM_MOUSEWHEEL: { int dz = GET_WHEEL_DELTA_WPARAM(wParam); scrollVertical(gdi_main, -dz, hWndWorkspace); } break; case WM_SIZE: { int h = 30; if (gdi_main) { h = max(h, gdi_main->getFontHeight(0, L"") + gdi_main->scaleLength(6)); } MoveWindow(hMainTab, 0, 0, LOWORD(lParam), h, 1); MoveWindow(hWndWorkspace, 0, h, LOWORD(lParam), HIWORD(lParam) - h, 1); RECT rc; GetClientRect(hWndWorkspace, &rc); PostMessage(hWndWorkspace, WM_SIZE, wParam, MAKELONG(rc.right, rc.bottom)); } break; case WM_WINDOWPOSCHANGED: if (gEvent) { LPWINDOWPOS wp = (LPWINDOWPOS) lParam; // points to size and position data if (wp->x>=0 && wp->y>=0 && wp->cx>300 && wp->cy>200) { gEvent->setProperty("xpos", wp->x); gEvent->setProperty("ypos", wp->y); gEvent->setProperty("xsize", wp->cx); gEvent->setProperty("ysize", wp->cy); } else { Sleep(0); } } return DefWindowProc(hWnd, message, wParam, lParam); case WM_TIMER: if (!gdi_main) return 0; if (wParam==1) { if (autoTask) autoTask->autoSave(); } else if (wParam==2) { // Interface timeouts (no synch) if (autoTask) autoTask->interfaceTimeout(gdi_extra); } else if (wParam==3) { if (autoTask) autoTask->synchronize(gdi_extra); } else if (wParam==4) { // Verify database link if (gEvent) gEvent->verifyConnection(); //OutputDebugString("Verify link\n"); //Sleep(0); if (gdi_main) { if (gEvent->hasClientChanged()) { gdi_main->makeEvent("Connections", "verify_connection", 0, 0, false); gEvent->validateClients(); } } } break; case WM_ACTIVATE: if (LOWORD(wParam) != WA_INACTIVE) currentFocusIx = 0; return DefWindowProc(hWnd, message, wParam, lParam); case WM_NCACTIVATE: if (gdi_main && gdi_main->hasToolbar()) gdi_main->activateToolbar(wParam != 0); return DefWindowProc(hWnd, message, wParam, lParam); case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR) lParam; if (pnmh->hwndFrom==hMainTab && gdi_main && gEvent) { if (pnmh->code==TCN_SELCHANGE) { int id=TabCtrl_GetCurSel(hMainTab); for (list::iterator it=tabList->begin();it!=tabList->end();++it) { if (it->id==id) { try { gdi_main->setWaitCursor(true); string cmd = "showTab("+ string(it->getTab().getTypeStr()) + "); //" + it->name; it->loadPage(*gdi_main); gdi_main->getRecorder().record(cmd); } catch (meosException &ex) { gdi_main->alert(ex.wwhat()); } catch(std::exception &ex) { gdi_main->alert(ex.what()); } gdi_main->setWaitCursor(false); } } } else if (pnmh->code==TCN_SELCHANGING) { if (gdi_main == 0) { MessageBeep(-1); return true; } else { if (!gdi_main->canClear()) return true; return false; } } } break; } case WM_USER: //The card has been read and posted to a synchronized //queue by different thread. Read and process this card. { SICard sic(ConvertedTimeStatus::Unknown); while (gSI && gSI->getCard(sic)) InsertSICard(*gdi_main, sic); break; } case WM_USER+1: MessageBox(hWnd, lang.tl(L"Kommunikationen med en SI-enhet avbröts.").c_str(), L"SportIdent", MB_OK); break; case WM_USER + 3: //OutputDebugString("Get punch from queue\n"); if (autoTask) autoTask->advancePunchInformation(gdi_extra); break; case WM_USER + 4: if (autoTask) autoTask->synchronize(gdi_extra); break; case WM_USER + 5: if (gdi_main) gdi_main->addInfoBox("ainfo", L"info:advanceinfo", 10000); break; case WM_USER + 6: if (gdi_main && lParam) { gdioutput* g = (gdioutput*)lParam; wstring msg = g->getDelayedAlert(); if (!connectionAlert) { connectionAlert = true; gdi_main->alert(msg); connectionAlert = false; } } break; case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // Parse the menu selections: switch (wmId) { case IDM_EXIT: //DestroyWindow(hWnd); PostMessage(hWnd, WM_CLOSE, 0,0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // TODO: Add any drawing code here... EndPaint(hWnd, &ps); break; case WM_CLOSE: if (!gEvent || gEvent->empty() || gdi_main->ask(L"Vill du verkligen stänga MeOS?")) DestroyWindow(hWnd); break; case WM_DESTROY: delete gSI; gSI=0; for (size_t k = 0; k < gdi_extra.size(); k++) { if (gdi_extra[k]) gdi_extra[k]->clearPage(false, false); } if (gEvent) { try { gEvent->save(); } catch (meosException &ex) { MessageBox(hWnd, lang.tl(ex.wwhat()).c_str(), L"Fel när tävlingen skulle sparas", MB_OK); } catch(std::exception &ex) { MessageBox(hWnd, lang.tl(ex.what()).c_str(), L"Fel när tävlingen skulle sparas", MB_OK); } try { gEvent->saveRunnerDatabase(L"database", true); } catch (meosException &ex) { MessageBox(hWnd, lang.tl(ex.wwhat()).c_str(), L"Fel när löpardatabas skulle sparas", MB_OK); } catch(std::exception &ex) { MessageBox(hWnd, lang.tl(ex.what()).c_str(), L"Fel när löpardatabas skulle sparas", MB_OK); } if (gEvent) gEvent->saveProperties(settings); delete gEvent; gEvent=0; } PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } void scrollVertical(gdioutput *gdi, int yInc, HWND hWnd) { SCROLLINFO si; si.cbSize=sizeof(si); si.fMask=SIF_ALL; GetScrollInfo(hWnd, SB_VERT, &si); if (si.nPage==0) yInc = 0; int yPos=gdi->getOffsetY(); int a=si.nMax-signed(si.nPage-1) - yPos; if ( (yInc = max( -yPos, min(yInc, a)))!=0 ) { yPos += yInc; RECT ScrollArea, ClipArea; GetClientRect(hWnd, &ScrollArea); ClipArea=ScrollArea; ScrollArea.top=-gdi->getHeight()-100; ScrollArea.bottom+=gdi->getHeight(); ScrollArea.right=gdi->getWidth()-gdi->getOffsetX()+15; ScrollArea.left = -2000; gdi->setOffsetY(yPos); bool inv = true; //Inv = false works only for lists etc. where there are not controls in the scroll area. RECT invalidArea; ScrollWindowEx (hWnd, 0, -yInc, &ScrollArea, &ClipArea, (HRGN) NULL, &invalidArea, SW_SCROLLCHILDREN | (inv ? SW_INVALIDATE : 0)); // gdi->UpdateObjectPositions(); si.cbSize = sizeof(si); si.fMask = SIF_POS; si.nPos = yPos; SetScrollInfo(hWnd, SB_VERT, &si, TRUE); if (inv) UpdateWindow(hWnd); else { HDC hDC = GetDC(hWnd); IntersectClipRect(hDC, invalidArea.left, invalidArea.top, invalidArea.right, invalidArea.bottom); gdi->draw(hDC, ScrollArea, invalidArea); ReleaseDC(hWnd, hDC); } } } void updateScrollInfo(HWND hWnd, gdioutput &gdi, int nHeight, int nWidth) { SCROLLINFO si; si.cbSize = sizeof(si); si.fMask = SIF_PAGE|SIF_RANGE; int maxx, maxy; gdi.clipOffset(nWidth, nHeight, maxx, maxy); si.nMin=0; if (maxy>0) { si.nMax=maxy+nHeight; si.nPos=gdi.getOffsetY(); si.nPage=nHeight; } else { si.nMax=0; si.nPos=0; si.nPage=0; } SetScrollInfo(hWnd, SB_VERT, &si, true); si.nMin=0; if (maxx>0) { si.nMax=maxx+nWidth; si.nPos=gdi.getOffsetX(); si.nPage=nWidth; } else { si.nMax=0; si.nPos=0; si.nPage=0; } SetScrollInfo(hWnd, SB_HORZ, &si, true); } LRESULT CALLBACK WorkSpaceWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; LONG_PTR ix = GetWindowLongPtr(hWnd, GWLP_USERDATA); gdioutput *gdi = 0; if (ix < LONG_PTR(gdi_extra.size())) gdi = gdi_extra[ix]; if (gdi) { LRESULT res = gdi->ProcessMsg(message, lParam, wParam); if (res) return res; } switch (message) { case WM_CREATE: break; case WM_SIZE: //SCROLLINFO si; //si.cbSize=sizeof(si); //si.fMask=SIF_PAGE|SIF_RANGE; int nHeight; nHeight = HIWORD(lParam); int nWidth; nWidth = LOWORD(lParam); updateScrollInfo(hWnd, *gdi, nHeight, nWidth); /* int maxx, maxy; gdi->clipOffset(nWidth, nHeight, maxx, maxy); si.nMin=0; if (maxy>0) { si.nMax=maxy+nHeight; si.nPos=gdi->GetOffsetY(); si.nPage=nHeight; } else { si.nMax=0; si.nPos=0; si.nPage=0; } SetScrollInfo(hWnd, SB_VERT, &si, true); si.nMin=0; if (maxx>0) { si.nMax=maxx+nWidth; si.nPos=gdi->GetOffsetX(); si.nPage=nWidth; } else { si.nMax=0; si.nPos=0; si.nPage=0; } SetScrollInfo(hWnd, SB_HORZ, &si, true); */ InvalidateRect(hWnd, NULL, true); break; case WM_KEYDOWN: //gdi->keyCommand(; break; case WM_VSCROLL: { int nScrollCode = (int) LOWORD(wParam); // scroll bar value //int hwndScrollBar = (HWND) lParam; // handle to scroll bar int yInc; int yPos=gdi->getOffsetY(); RECT rc; GetClientRect(hWnd, &rc); int pagestep = max(50, int(0.9*rc.bottom)); switch(nScrollCode) { // User clicked shaft left of the scroll box. case SB_PAGEUP: yInc = -pagestep; break; // User clicked shaft right of the scroll box. case SB_PAGEDOWN: yInc = pagestep; break; // User clicked the left arrow. case SB_LINEUP: yInc = -10; break; // User clicked the right arrow. case SB_LINEDOWN: yInc = 10; break; // User dragged the scroll box. case SB_THUMBTRACK: { // Initialize SCROLLINFO structure SCROLLINFO si; ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_TRACKPOS; if (!GetScrollInfo(hWnd, SB_VERT, &si) ) return 1; // GetScrollInfo failed yInc = si.nTrackPos - yPos; break; } default: yInc = 0; } scrollVertical(gdi, yInc, hWnd); gdi->storeAutoPos(gdi->getOffsetY()); break; } case WM_HSCROLL: { int nScrollCode = (int) LOWORD(wParam); // scroll bar value //int hwndScrollBar = (HWND) lParam; // handle to scroll bar int xInc; int xPos=gdi->getOffsetX(); switch(nScrollCode) { case SB_ENDSCROLL: InvalidateRect(hWnd, 0, false); return 0; // User clicked shaft left of the scroll box. case SB_PAGEUP: xInc = -80; break; // User clicked shaft right of the scroll box. case SB_PAGEDOWN: xInc = 80; break; // User clicked the left arrow. case SB_LINEUP: xInc = -10; break; // User clicked the right arrow. case SB_LINEDOWN: xInc = 10; break; // User dragged the scroll box. case SB_THUMBTRACK: { // Initialize SCROLLINFO structure SCROLLINFO si; ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_TRACKPOS; if (!GetScrollInfo(hWnd, SB_HORZ, &si) ) return 1; // GetScrollInfo failed xInc = si.nTrackPos - xPos; break; } //xInc = HIWORD(wParam) - xPos; //break; default: xInc = 0; } SCROLLINFO si; si.cbSize=sizeof(si); si.fMask=SIF_ALL; GetScrollInfo(hWnd, SB_HORZ, &si); if (si.nPage==0) xInc = 0; int a=si.nMax-signed(si.nPage-1) - xPos; if ((xInc = max( -xPos, min(xInc, a)))!=0) { xPos += xInc; RECT ScrollArea, ClipArea; GetClientRect(hWnd, &ScrollArea); ClipArea=ScrollArea; gdi->setOffsetX(xPos); ScrollWindowEx (hWnd, -xInc, 0, 0, &ClipArea, (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE|SW_SCROLLCHILDREN); si.cbSize = sizeof(si); si.fMask = SIF_POS; si.nPos = xPos; SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); UpdateWindow (hWnd); } break; } case WM_MOUSEWHEEL: { int dz = GET_WHEEL_DELTA_WPARAM(wParam); scrollVertical(gdi, -dz, hWnd); gdi->storeAutoPos(gdi->getOffsetY()); } break; case WM_TIMER: if (wParam == 1001) { double autoScroll, pos; gdi->getAutoScroll(autoScroll, pos); SCROLLINFO si; si.cbSize = sizeof(si); si.fMask = SIF_ALL; GetScrollInfo(hWnd, SB_VERT, &si); int dir = gdi->getAutoScrollDir(); int dy = 0; if ((dir<0 && si.nPos <= si.nMin) || (dir>0 && (si.nPos + int(si.nPage)) >= si.nMax)) { autoScroll = -autoScroll; gdi->setAutoScroll(-1); // Mirror double nextPos = pos + autoScroll; dy = int(nextPos - si.nPos); gdi->storeAutoPos(nextPos); //gdi->setData("AutoScroll", -int(data)); } else { double nextPos = pos + autoScroll; dy = int(nextPos - si.nPos); gdi->storeAutoPos(nextPos); //gdi->setData("Discrete", DWORD(nextPos*1e3)); } scrollVertical(gdi, dy, hWnd); } else MessageBox(hWnd, L"Runtime exception", 0, MB_OK); break; case WM_ACTIVATE: { int fActive = LOWORD(wParam); if (fActive != WA_INACTIVE) currentFocusIx = ix; return DefWindowProc(hWnd, message, wParam, lParam); } case WM_USER + 2: if (gdi) LoadPage(*gdi, TabType(wParam)); break; case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // Parse the menu selections: switch (wmId) { case 0: break; default: return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); RECT rt; GetClientRect(hWnd, &rt); if (gdi && (ps.rcPaint.right|ps.rcPaint.left|ps.rcPaint.top|ps.rcPaint.bottom) != 0 ) gdi->draw(hdc, rt, ps.rcPaint); /*{ HANDLE icon = LoadImage(hInst, (LPCTSTR)IDI_MEOS, IMAGE_ICON, 64, 64, LR_SHARED); DrawIconEx(hdc, 0,0, (HICON)icon, 64, 64, 0, NULL, DI_NORMAL | DI_COMPAT); }*/ EndPaint(hWnd, &ps); break; case WM_ERASEBKGND: return 0; break; case WM_DESTROY: if (ix > 0) { gdi->makeEvent("CloseWindow", "meos", 0, 0, false); gdi_extra[ix] = 0; delete gdi; while(!gdi_extra.empty() && gdi_extra.back() == 0) gdi_extra.pop_back(); } break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } // Message handler for about box. LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_INITDIALOG: return TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return TRUE; } break; } return FALSE; } namespace setup { const int nFiles=7; const wchar_t *fileList[nFiles]={L"baseclass.xml", L"wfamily.mwd", L"wgiven.mwd", L"wclub.mwd", L"wclass.mwd", L"database.wclubs", L"database.wpersons"}; } void Setup(bool overwrite, bool overwriteAll) { static bool isSetup=false; if (isSetup && overwrite==false) return; isSetup=true; //Run at most once. vector > toInstall; for(int k=0;k dyn; if (overwrite) expandDirectory(dir, L"*.meos", dyn); for (size_t k = 0; k < dyn.size(); k++) toInstall.push_back(make_pair(dyn[k], true)); wchar_t bf[260]; for(size_t k=0; k tempFiles; static wstring tempPath; wstring getTempPath() { wchar_t tempFile[MAX_PATH]; if (tempPath.empty()) { wchar_t path[MAX_PATH]; GetTempPath(MAX_PATH, path); GetTempFileName(path, L"meos", 0, tempFile); DeleteFile(tempFile); if (CreateDirectory(tempFile, NULL)) tempPath = tempFile; else throw std::exception("Failed to create temporary file."); } return tempPath; } void registerTempFile(const wstring &tempFile) { tempFiles.insert(tempFile); } wstring getTempFile() { getTempPath(); wchar_t tempFile[MAX_PATH]; if (GetTempFileName(tempPath.c_str(), L"ix", 0, tempFile)) { tempFiles.insert(tempFile); return tempFile; } else throw std::exception("Failed to create temporary file."); } void removeTempFile(const wstring &file) { DeleteFile(file.c_str()); tempFiles.erase(file); } void removeTempFiles() { vector dir; for (set::iterator it = tempFiles.begin(); it!= tempFiles.end(); ++it) { wchar_t c = *it->rbegin(); if (c == '/' || c == '\\') dir.push_back(*it); else DeleteFile(it->c_str()); } tempFiles.clear(); bool removed = true; while (removed) { removed = false; for (size_t k = 0; k