/* PROJECT: ReactOS Downloader * LICENSE: GPL - See COPYING in the top level directory * FILE: base/applications/downloader/xml.c * PURPOSE: Main program * PROGRAMMERS: Maarten Bosma, Lester Kortenhoeven, Dmitry Chapyshev */ #include #include #include #include #include #include #include #include "resources.h" #include "structures.h" HWND hwnd, hCategories, hApps, hDownloadButton, hUninstallButton, hUpdateButton, hHelpButton, hProfButton; HBITMAP hLogo, hUnderline; WCHAR* DescriptionHeadline = L""; WCHAR* DescriptionText = L""; WCHAR ApplicationText[700]; struct Category Root; struct Application* SelectedApplication; INT_PTR CALLBACK DownloadProc (HWND, UINT, WPARAM, LPARAM); BOOL ProcessXML (const char* filename, struct Category* Root); VOID FreeTree (struct Category* Node); WCHAR Strings [STRING_COUNT][MAX_STRING_LENGHT]; BOOL getUninstaller(WCHAR* RegName, WCHAR* Uninstaller) { const DWORD ArraySize = 200; HKEY hKey1; HKEY hKey2; DWORD Type = 0; DWORD Size = ArraySize; WCHAR Value[ArraySize]; WCHAR KeyName[ArraySize]; LONG i = 0; if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall",0,KEY_READ,&hKey1) == ERROR_SUCCESS) { while (RegEnumKeyExW(hKey1,i,KeyName,&Size,NULL,NULL,NULL,NULL) == ERROR_SUCCESS) { ++i; RegOpenKeyExW(hKey1,KeyName,0,KEY_READ,&hKey2); Size = ArraySize; if (RegQueryValueExW(hKey2,L"DisplayName",0,&Type,(LPBYTE)Value,&Size) == ERROR_SUCCESS) { Size = ArraySize; if (StrCmpW(Value,RegName) == 0) { if (RegQueryValueExW(hKey2,L"UninstallString",0,&Type,(LPBYTE)Uninstaller,&Size) == ERROR_SUCCESS) { RegCloseKey(hKey2); RegCloseKey(hKey1); return TRUE; } else { RegCloseKey(hKey2); RegCloseKey(hKey1); return FALSE; } } } RegCloseKey(hKey2); Size = ArraySize; } RegCloseKey(hKey1); } return FALSE; } void ShowMessage (WCHAR* title, WCHAR* message) { DescriptionHeadline = title; DescriptionText = message; InvalidateRect(hwnd,NULL,TRUE); UpdateWindow(hwnd); } void AddItems(HWND hwnd, struct Category* Category, struct Category* Parent) { TV_INSERTSTRUCTW Insert; Insert.item.lParam = (UINT)Category; Insert.item.mask = TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE;; Insert.item.pszText = Category->Name; Insert.item.cchTextMax = lstrlenW(Category->Name); Insert.item.iImage = Category->Icon; Insert.item.iSelectedImage = Category->Icon; Insert.hInsertAfter = TVI_LAST; Insert.hParent = Category->Parent ? Category->Parent->TreeviewItem : TVI_ROOT; Category->TreeviewItem = (HTREEITEM)SendMessage(hwnd, TVM_INSERTITEM, 0, (LPARAM)&Insert); if(Category->Next) AddItems (hwnd,Category->Next,Parent); if(Category->Children) AddItems (hwnd,Category->Children,Category); } void CategoryChoosen(HWND hwnd, struct Category* Category) { struct Application* CurrentApplication; TV_INSERTSTRUCTW Insert; SelectedApplication = NULL; if(Category->Children && !Category->Apps) ShowMessage(Category->Name, Strings[IDS_CHOOSE_SUB]); else if(!Category->Children && Category->Apps) ShowMessage(Category->Name, Strings[IDS_CHOOSE_APP]); else if(Category->Children && Category->Apps) ShowMessage(Category->Name, Strings[IDS_CHOOSE_BOTH]); else ShowMessage(Category->Name, Strings[IDS_NO_APPS]); (void)TreeView_DeleteItem(hwnd, TVI_ROOT); (void)TreeView_DeleteItem(hwnd, TVI_ROOT); // Delete twice to bypass bug in windows Insert.item.mask = TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE; Insert.hInsertAfter = TVI_LAST; Insert.hParent = TVI_ROOT; CurrentApplication = Category->Apps; WCHAR Uninstaller[200]; while(CurrentApplication) { Insert.item.lParam = (UINT)CurrentApplication; Insert.item.pszText = CurrentApplication->Name; Insert.item.cchTextMax = lstrlenW(CurrentApplication->Name); Insert.item.iImage = 10; if(StrCmpW(CurrentApplication->RegName,L"")) { if(getUninstaller(CurrentApplication->RegName, Uninstaller)) Insert.item.iImage = 9; } SendMessage(hwnd, TVM_INSERTITEM, 0, (LPARAM)&Insert); CurrentApplication = CurrentApplication->Next; } } BOOL CreateToolTip(HWND hwndTool, HWND hDlg, WCHAR* pText) { if (!hwndTool || !hDlg || !pText) return FALSE; HWND hwndTip = CreateWindowExW(0, TOOLTIPS_CLASS, NULL, WS_POPUP |TTS_ALWAYSTIP | TTS_BALLOON, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hDlg, NULL, GetModuleHandle(NULL), NULL); if (!hwndTip) return FALSE; TOOLINFO toolInfo = {0}; toolInfo.cbSize = sizeof(toolInfo); toolInfo.hwnd = hDlg; toolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS; toolInfo.uId = (UINT_PTR)hwndTool; toolInfo.lpszText = pText; SendMessage(hwndTip, TTM_ADDTOOL, 0, (LPARAM)&toolInfo); return TRUE; } BOOL SetupControls (HWND hwnd) { TV_INSERTSTRUCTW Insert = {0}; HIMAGELIST hImageList; HINSTANCE hInstance = GetModuleHandle(NULL); WCHAR Cats[MAX_STRING_LENGHT], Apps[MAX_STRING_LENGHT]; WCHAR Tooltip1[MAX_STRING_LENGHT], Tooltip2[MAX_STRING_LENGHT], Tooltip3[MAX_STRING_LENGHT]; TCHAR Buf[MAX_PATH]; char Tmp[MAX_PATH]; int i; // Getting downloader.xml path if(!GetSystemDirectory(Buf,sizeof(Buf)/sizeof(char))) return FALSE; lstrcat((LPTSTR)Buf, L"\\downloader.xml"); for (i = 0; i < _tcslen(Buf) + 1; i++) Tmp[i] = Buf[i]; // Parse the XML file if (!ProcessXML(Tmp, &Root)) return FALSE; LoadStringW(hInstance, IDS_CATS_TITLE, Cats, MAX_STRING_LENGHT); LoadStringW(hInstance, IDS_APPS_TITLE, Apps, MAX_STRING_LENGHT); // Set up the controls hCategories = CreateWindowExW(0, WC_TREEVIEWW, Cats, WS_CHILD|WS_VISIBLE|WS_BORDER|TVS_HASLINES|TVS_LINESATROOT|TVS_HASBUTTONS|TVS_SHOWSELALWAYS, 0, 0, 0, 0, hwnd, NULL, hInstance, NULL); hApps = CreateWindowExW(0, WC_TREEVIEWW, Apps, WS_CHILD|WS_VISIBLE|WS_BORDER|TVS_HASLINES|TVS_LINESATROOT|TVS_HASBUTTONS|TVS_SHOWSELALWAYS, 0, 0, 0, 0, hwnd, NULL, hInstance, NULL); hLogo = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_LOGO)); hUnderline = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_UNDERLINE)); hHelpButton = CreateWindowW(L"Button", L"", WS_CHILD | WS_VISIBLE | BS_ICON, 550, 10, 40, 40, hwnd, 0, hInstance, NULL); LoadString(hInstance, TTT_HELPBUTTON, Tooltip1, MAX_STRING_LENGHT); CreateToolTip(hHelpButton, hwnd, Tooltip1); hUpdateButton = CreateWindowW(L"Button", L"", WS_CHILD | WS_VISIBLE | BS_ICON, 450, 10, 40, 40, hwnd, 0, hInstance, NULL); LoadString(hInstance, TTT_UPDATEBUTTON, Tooltip2, MAX_STRING_LENGHT); CreateToolTip(hUpdateButton, hwnd, Tooltip2); hProfButton = CreateWindowW(L"Button", L"", WS_CHILD | WS_VISIBLE | BS_ICON, 500, 10, 40, 40, hwnd, 0, hInstance, NULL); LoadString(hInstance, TTT_PROFBUTTON, Tooltip3, MAX_STRING_LENGHT); CreateToolTip(hProfButton, hwnd, Tooltip3); hDownloadButton = CreateWindowW(L"Button", L"", WS_CHILD | WS_VISIBLE | BS_BITMAP, 330, 505, 140, 33, hwnd, 0, hInstance, NULL); hUninstallButton = CreateWindowW(L"Button", L"", WS_CHILD | WS_VISIBLE | BS_BITMAP, 260, 505, 140, 33, hwnd, 0, hInstance, NULL); SendMessageW(hProfButton, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)(HANDLE)LoadIcon(hInstance,MAKEINTRESOURCE(IDI_PROF))); SendMessageW(hHelpButton, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)(HANDLE)LoadIcon(hInstance, MAKEINTRESOURCE(IDI_HELP))); SendMessageW(hUpdateButton, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)(HANDLE)LoadIcon(hInstance, MAKEINTRESOURCE(IDI_UPDATE))); SendMessageW(hDownloadButton, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)(HANDLE)LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_DOWNLOAD))); SendMessageW(hUninstallButton, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)(HANDLE)LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_UNINSTALL))); ShowWindow(hUninstallButton, SW_HIDE); // Set deflaut entry for hApps Insert.item.mask = TVIF_TEXT|TVIF_IMAGE; Insert.item.pszText = Strings[IDS_CHOOSE_CATEGORY]; Insert.item.cchTextMax = lstrlenW(Strings[IDS_CHOOSE_CATEGORY]); Insert.item.iImage = 0; SendMessage(hApps, TVM_INSERTITEM, 0, (LPARAM)&Insert); // Create Tree Icons hImageList = ImageList_Create(16, 16, ILC_COLORDDB, 1, 1); SendMessageW(hCategories, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)(HIMAGELIST)hImageList); SendMessageW(hApps, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)(HIMAGELIST)hImageList); ImageList_Add(hImageList, LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_0)), NULL); ImageList_Add(hImageList, LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_1)), NULL); ImageList_Add(hImageList, LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_2)), NULL); ImageList_Add(hImageList, LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_3)), NULL); ImageList_Add(hImageList, LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_4)), NULL); ImageList_Add(hImageList, LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_5)), NULL); ImageList_Add(hImageList, LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_6)), NULL); ImageList_Add(hImageList, LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_7)), NULL); ImageList_Add(hImageList, LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_8)), NULL); ImageList_Add(hImageList, LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_9)), NULL); ImageList_Add(hImageList, LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_10)), NULL); ImageList_Add(hImageList, LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_11)), NULL); ImageList_Add(hImageList, LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_12)), NULL); ImageList_Add(hImageList, LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_13)), NULL); // Fill the TreeViews AddItems (hCategories, Root.Children, NULL); return TRUE; } static void ResizeControl (HWND hwnd, int x1, int y1, int x2, int y2) { // Make resizing a little easier MoveWindow(hwnd, x1, y1, x2-x1, y2-y1, TRUE); } static void DrawBitmap (HDC hdc, int x, int y, HBITMAP hBmp) { BITMAP bm; HDC hdcMem = CreateCompatibleDC(hdc); SelectObject(hdcMem, hBmp); GetObject(hBmp, sizeof(bm), &bm); TransparentBlt(hdc, x, y, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, 0xFFFFFF); DeleteDC(hdcMem); } static void DrawDescription (HDC hdc, RECT DescriptionRect) { int i; HFONT Font; RECT Rect = {DescriptionRect.left+5, DescriptionRect.top+3, DescriptionRect.right-2, DescriptionRect.top+22}; // Backgroud Rectangle(hdc, DescriptionRect.left, DescriptionRect.top, DescriptionRect.right, DescriptionRect.bottom); // Underline for (i=DescriptionRect.left+1;iRegName, L"")) { if(getUninstaller(App->RegName, Uninstaller)) { return TRUE; } } return FALSE; } struct Application* GetDependency(const WCHAR* Dependency) { struct Category* Category = Root.Children; while (Category->Next) { while (Category->Apps) { if(StrCmpW(Category->Apps->RegName, Dependency) == 0) return Category->Apps; Category->Apps = Category->Apps->Next; } Category = Category->Next; } return NULL; } LRESULT CALLBACK WndProc (HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) { static RECT DescriptionRect; struct Application* AppToInstall; WCHAR InstallDep[260]; WCHAR InstallDepBuffer[260]; WCHAR Title[260]; switch (Message) { case WM_CREATE: { if(!SetupControls(hwnd)) return -1; ShowMessage(Strings[IDS_WELCOME_TITLE], Strings[IDS_WELCOME]); } break; case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); HDC BackbufferHdc = CreateCompatibleDC(hdc); HBITMAP BackbufferBmp = CreateCompatibleBitmap(hdc, ps.rcPaint.right, ps.rcPaint.bottom); SelectObject(BackbufferHdc, BackbufferBmp); FillRect(BackbufferHdc, &ps.rcPaint, CreateSolidBrush(RGB(235,235,235))); DrawBitmap(BackbufferHdc, 10, 12, hLogo); DrawDescription(BackbufferHdc, DescriptionRect); BitBlt(hdc, 0, 0, ps.rcPaint.right, ps.rcPaint.bottom, BackbufferHdc, 0, 0, SRCCOPY); DeleteObject(BackbufferBmp); DeleteDC(BackbufferHdc); EndPaint(hwnd, &ps); } break; case WM_COMMAND: { if(HIWORD(wParam) == BN_CLICKED) { if (lParam == (LPARAM)hProfButton) { DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_PROF), hwnd, ProfDlgProc); } if (lParam == (LPARAM)hDownloadButton) { if(SelectedApplication) { /* install dependencies */ if(StrCmpW(SelectedApplication->Depends, L"")) { AppToInstall = SelectedApplication; SelectedApplication = GetDependency(SelectedApplication->Depends); if (SelectedApplication) if (!IsApplicationInstalled(SelectedApplication)) { LoadString(GetModuleHandle(NULL), IDS_INSTALL_DEP, InstallDep, sizeof(InstallDep) / sizeof(WCHAR)); LoadString(GetModuleHandle(NULL), IDS_WINDOW_TITLE, Title, sizeof(Title) / sizeof(WCHAR)); _snwprintf(InstallDepBuffer, sizeof(InstallDepBuffer) / sizeof(WCHAR), InstallDep, SelectedApplication->Name, AppToInstall->Name, SelectedApplication->Name); if (MessageBox(hwnd, InstallDepBuffer, Title, MB_YESNO | MB_ICONINFORMATION) == IDYES) { DialogBoxW(GetModuleHandle(NULL), MAKEINTRESOURCEW(IDD_DOWNLOAD), 0, DownloadProc); } } SelectedApplication = AppToInstall; } /* download and install the app */ DialogBoxW(GetModuleHandle(NULL), MAKEINTRESOURCEW(IDD_DOWNLOAD), 0, DownloadProc); /* install req. hacks to get it working */ if(StrCmpW(SelectedApplication->PostInstallAction, L"")) { AppToInstall = SelectedApplication; CopyMemory(SelectedApplication->Location, SelectedApplication->PostInstallAction, sizeof(SelectedApplication->Location)); DialogBoxW(GetModuleHandle(NULL), MAKEINTRESOURCEW(IDD_DOWNLOAD), 0, DownloadProc); SelectedApplication = AppToInstall; } } else ShowMessage(Strings[IDS_NO_APP_TITLE], Strings[IDS_NO_APP]); } else if (lParam == (LPARAM)hUninstallButton) { if(SelectedApplication) { WCHAR Uninstaller[200]; if(StrCmpW(SelectedApplication->RegName, L"")) { if(getUninstaller(SelectedApplication->RegName, Uninstaller)) startUninstaller(Uninstaller); } } } else if (lParam == (LPARAM)hUpdateButton) { ShowMessage(Strings[IDS_UPDATE_TITLE], Strings[IDS_UPDATE]); } else if (lParam == (LPARAM)hHelpButton) { ShowMessage(Strings[IDS_HELP_TITLE], Strings[IDS_HELP]); } } } break; case WM_NOTIFY: { LPNMHDR data = (LPNMHDR)lParam; if(data->code == TVN_SELCHANGED) { BOOL bShowUninstaller = FALSE; if(data->hwndFrom == hCategories) { struct Category* Category = (struct Category*) ((LPNMTREEVIEW)lParam)->itemNew.lParam; CategoryChoosen (hApps, Category); } else if(data->hwndFrom == hApps) { SelectedApplication = (struct Application*) ((LPNMTREEVIEW)lParam)->itemNew.lParam; if(SelectedApplication) { ApplicationText[0]=L'\0'; if(StrCmpW(SelectedApplication->Version, L"")) { StrCatW(ApplicationText, Strings[IDS_VERSION]); StrCatW(ApplicationText, SelectedApplication->Version); StrCatW(ApplicationText, L"\n"); } if(StrCmpW(SelectedApplication->Licence, L"")) { StrCatW(ApplicationText, Strings[IDS_LICENCE]); StrCatW(ApplicationText, SelectedApplication->Licence); StrCatW(ApplicationText, L"\n"); } if(StrCmpW(SelectedApplication->Maintainer, L"")) { StrCatW(ApplicationText, Strings[IDS_MAINTAINER]); StrCatW(ApplicationText, SelectedApplication->Maintainer); StrCatW(ApplicationText, L"\n"); } if(StrCmpW(SelectedApplication->Licence, L"") || StrCmpW(SelectedApplication->Version, L"") || StrCmpW(SelectedApplication->Maintainer, L"")) StrCatW(ApplicationText, L"\n"); StrCatW(ApplicationText, SelectedApplication->Description); ShowMessage(SelectedApplication->Name, ApplicationText); WCHAR Uninstaller[200]; if(StrCmpW(SelectedApplication->RegName, L"")) { if(getUninstaller(SelectedApplication->RegName, Uninstaller)) { bShowUninstaller = TRUE; } } } } if (bShowUninstaller) showUninstaller(); else hideUninstaller(); } } break; case WM_SIZING: { LPRECT pRect = (LPRECT)lParam; if (pRect->right-pRect->left < 520) pRect->right = pRect->left + 520; if (pRect->bottom-pRect->top < 300) pRect->bottom = pRect->top + 300; } break; case WM_SIZE: { int Split_Hozizontal = (HIWORD(lParam)-(45+60))/2 + 60; int Split_Vertical = 200; ResizeControl(hCategories, 10, 60, Split_Vertical, HIWORD(lParam)-10); ResizeControl(hApps, Split_Vertical+5, 60, LOWORD(lParam)-10, Split_Hozizontal); RECT Rect = {Split_Vertical+5, Split_Hozizontal+5, LOWORD(lParam)-10, HIWORD(lParam)-50}; DescriptionRect = Rect; MoveWindow(hHelpButton, LOWORD(lParam)-50, 10, 40, 40, TRUE); MoveWindow(hUpdateButton, LOWORD(lParam)-150, 10, 40, 40, TRUE); MoveWindow(hProfButton, LOWORD(lParam)-100, 10, 40, 40, TRUE); if(IsWindowVisible(hUninstallButton)) MoveWindow(hDownloadButton, (Split_Vertical+LOWORD(lParam))/2, HIWORD(lParam)-45, 140, 35, TRUE); else MoveWindow(hDownloadButton, (Split_Vertical+LOWORD(lParam))/2-70, HIWORD(lParam)-45, 140, 35, TRUE); MoveWindow(hUninstallButton, (Split_Vertical+LOWORD(lParam))/2-140, HIWORD(lParam)-45, 140, 35, TRUE); } break; case WM_DESTROY: { DeleteObject(hLogo); if(Root.Children) FreeTree(Root.Children); PostQuitMessage(0); return 0; } break; } return DefWindowProc (hwnd, Message, wParam, lParam); } INT WINAPI wWinMain (HINSTANCE hInstance, HINSTANCE hPrevInst, LPTSTR lpCmdLine, INT nCmdShow) { int i; WNDCLASSEXW WndClass = {0}; MSG msg; InitCommonControls(); // Load strings for(i=0; i