#define WIN32_LEAN_AND_MEAN #include <windows.h> #include <stdlib.h> #include <stdio.h> #include <tchar.h> #include <string> #include "res\resource.h" #include "fs.h" // Ignore stupid deprecation warning #pragma warning(disable : 4996) const char* cTitle = "P4fsV"; const char* cWindowClass = "p4fsv"; const int w_dialog = 350; const int h_dialog = 60; const int h_dialog_extended1 = 100; const int h_dialog_extended2 = 170; const int x_progressbar = 10; const int y_progressbar = 10; const int w_progressbar = 250; const int h_progressbar = 17; const int w_text2 = 325; const int h_text1 = 70; const int h_text2 = 100; const int x_cancel_button = 275; const int y_cancel_button = 7; const int w_cancel_button = 60; const int h_cancel_button = 23; const int x_ok_button = 275; const int y_ok_button1 = 45; const int y_ok_button2 = 95; const int w_bitmap = 12; const int h_bitmap = 15; HINSTANCE sInstance; HWND sMainWindow = NULL; HWND sCancelButton = NULL; HWND sOkButton = NULL; HWND sProgressbar = NULL; HBITMAP sProgressBitmap = NULL; UINT_PTR sTimer = NULL; int sFileCount = 0; long long sSyncSize = 0; long long sReadSize = 0; long long sWrittenSize = 0; int sFilesSeen = 0; EResult sResult = FS_BUSY; int sStartTime = 0; float sMbps = 0.0f; float sProgressbarOffset = 0.0f; void SyncStatCallback(int inFileCount, long long inSyncSize) { sFileCount += inFileCount; sSyncSize += inSyncSize; } void FileStatCallback(const char* inDepotFile, const char* inClientFile, const char* inAction, int inRev, long long inFileSize) { ++sFilesSeen; } void ReadCallback(long long inReadSize) { sReadSize += inReadSize; } void WriteCallback(long long inWriteSize) { sWrittenSize += inWriteSize; } DWORD WINAPI SyncThread(void* inInfo) { sResult = Sync(__argc, __argv, "P4fsV", SyncStatCallback, FileStatCallback, ReadCallback, WriteCallback); return sResult; } DWORD WINAPI AbortThread(void* inInfo) { AbortSync(); sResult = FS_ABORTED; return sResult; } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_SYSCOMMAND : if ((wParam == SC_CLOSE) && (sResult == FS_BUSY)) { SetWindowText(sMainWindow, "Canceling..."); CreateThread(NULL, 0, AbortThread, NULL, 0, NULL); return 0; } return DefWindowProc(hWnd, message, wParam, lParam); break; case WM_COMMAND : { int wmId = LOWORD(wParam); int wmEvent = HIWORD(wParam); switch (wmId) { case BN_CLICKED: if ((HWND) lParam == sCancelButton) { SetWindowText(sMainWindow, "Canceling..."); CreateThread(NULL, 0, AbortThread, NULL, 0, NULL); return 0; } else if ((HWND) lParam == sOkButton) { DestroyWindow(hWnd); } else return DefWindowProc(hWnd, message, wParam, lParam); break; default: break; } return DefWindowProc(hWnd, message, wParam, lParam); break; } case WM_TIMER: if (hWnd == sMainWindow) { InvalidateRect(sProgressbar, NULL, FALSE); if (sFileCount > 0) { sMbps = (sReadSize * 8.0f) / ((GetTickCount() - sStartTime) * 1000.0f); char title[100]; sprintf(title, "P4fsV - syncing %d / %d files @ %3.0f mbit/sec", sFilesSeen, sFileCount, sMbps); char old_title[100]; GetWindowText(sMainWindow, old_title, 100); if (strcmp(title, old_title) != 0 && strcmp(old_title, "Canceling...") != 0) SetWindowText(sMainWindow, title); } if (sResult != FS_BUSY) { // We're done, process result switch (sResult) { case FS_OK : case FS_ABORTED : // Success or aborted by user, clear up the dialog and exit. DestroyWindow(sMainWindow); break; case FS_HELP : case FS_ERROR_ARGUMENT : case FS_ERROR_NO_SYNC : case FS_ERROR_MEMORY : case FS_ERROR_INIT : { // Initialization error, show in a static text box replacing the progress bar. DestroyWindow(sProgressbar); DestroyWindow(sCancelButton); SetWindowPos(sMainWindow, 0, 0, 0, w_dialog, h_dialog_extended1, SWP_NOMOVE | SWP_NOZORDER); HWND error_window = CreateWindow("STATIC", GetErrorMessage(), WS_CHILD | WS_VISIBLE, x_progressbar, y_progressbar, w_progressbar, h_text1, sMainWindow, NULL, sInstance, NULL); HFONT font = (HFONT) GetStockObject(DEFAULT_GUI_FONT); SendMessage(error_window, WM_SETFONT, (WPARAM) font, MAKELPARAM(FALSE, 0)); sOkButton = CreateWindow("BUTTON", "Ok", WS_CHILD | BS_PUSHBUTTON | WS_VISIBLE, x_cancel_button, y_cancel_button, w_cancel_button, h_cancel_button, sMainWindow, NULL, sInstance, NULL); SendMessage(sOkButton, WM_SETFONT, (WPARAM) font, MAKELPARAM(FALSE, 0)); KillTimer(sMainWindow, sTimer); break; } case FS_ERROR_SYNC : case FS_ERROR_IO : { // Error during sync itself, show in a text window with scrollbar underneath progress bar. SetWindowPos(sMainWindow, 0, 0, 0, w_dialog, h_dialog_extended2, SWP_NOMOVE | SWP_NOZORDER); HWND error_window = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", NULL, WS_VISIBLE | WS_CHILD | WS_BORDER | WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | ES_WANTRETURN | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_READONLY, x_progressbar, y_progressbar + h_progressbar + 10, w_text2, h_text2, sMainWindow, 0, sInstance, NULL); HFONT font = (HFONT) GetStockObject(DEFAULT_GUI_FONT); SendMessage(error_window, WM_SETFONT, (WPARAM) font, MAKELPARAM(FALSE, 0)); // Convert the line-endings for the stupid edit control const char* error_message = GetExtendedErrorMessage(); std::string message = "Error(s) reported during sync :\r\n"; while (*error_message) { if (*error_message == '\n') { if (*(error_message + 1)) message += "\r\n"; } else message += *error_message; ++error_message; } SetWindowText(error_window, message.c_str()); DestroyWindow(sCancelButton); sOkButton = CreateWindow("BUTTON", "Ok", WS_CHILD | BS_PUSHBUTTON | WS_VISIBLE, x_cancel_button, y_cancel_button, w_cancel_button, h_cancel_button, sMainWindow, NULL, sInstance, NULL); SendMessage(sOkButton, WM_SETFONT, (WPARAM)font, MAKELPARAM(FALSE, 0)); KillTimer(sMainWindow, sTimer); break; } default : break; } } break; } else return DefWindowProc(hWnd, message, wParam, lParam); case WM_PAINT: if (hWnd == sProgressbar) { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); HDC hdcMem = CreateCompatibleDC(hdc); HBITMAP hbmOld = (HBITMAP) SelectObject(hdcMem, sProgressBitmap); int w_progress = (sSyncSize > 0) ? (int) ((sReadSize * w_progressbar) / sSyncSize) : 0; sProgressbarOffset += sMbps / 50.0f; int offset = w_bitmap - ((int)sProgressbarOffset) % w_bitmap; int x = 0; while (x < w_progress) { int w = w_bitmap; if (x + w > w_progress) w = w_progress - x; BitBlt(hdc, x, 0, w, h_bitmap - 1, hdcMem, offset, 0, SRCCOPY); x += w_bitmap; } RECT rect; rect.left = w_progress + 1; rect.top = 0; rect.right = w_progressbar - 1; rect.bottom = h_bitmap - 1; FillRect(hdc, &rect, (HBRUSH) (COLOR_WINDOW)); SelectObject(hdcMem, hbmOld); DeleteDC(hdcMem); EndPaint(hWnd, &ps); } else return DefWindowProc(hWnd, message, wParam, lParam); break; case WM_DESTROY: RECT window_rect; GetWindowRect(sMainWindow, &window_rect); HKEY reg_key; DWORD disposition; if (RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\P4fsV", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, ®_key, &disposition) == ERROR_SUCCESS) { DWORD len = sizeof(int); RegSetValueEx(reg_key, "WindowPosX", 0, REG_DWORD, (LPBYTE)&window_rect.left, sizeof(window_rect.left)); RegSetValueEx(reg_key, "WindowPosY", 0, REG_DWORD, (LPBYTE)&window_rect.top, sizeof(window_rect.top)); RegCloseKey(reg_key); } if (hWnd == sMainWindow) PostQuitMessage(0); else return DefWindowProc(hWnd, message, wParam, lParam); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } ATOM MyRegisterClass(HINSTANCE inInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = 0; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = inInstance; wcex.hIcon = LoadIcon(inInstance, MAKEINTRESOURCE(IDI_ICON1)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH) (COLOR_WINDOW); wcex.lpszMenuName = NULL; wcex.lpszClassName = cWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_ICON2)); return RegisterClassEx(&wcex); } BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { sInstance = hInstance; int x_window_pos = CW_USEDEFAULT; int y_window_pos = 0; HKEY reg_key; if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\P4fsV", 0, KEY_QUERY_VALUE, ®_key) == ERROR_SUCCESS) { DWORD len = sizeof(int); RegQueryValueEx(reg_key, "WindowPosX", NULL, NULL, (LPBYTE) &x_window_pos, &len); RegQueryValueEx(reg_key, "WindowPosY", NULL, NULL, (LPBYTE) &y_window_pos, &len); RegCloseKey(reg_key); } sMainWindow = CreateWindowEx(WS_EX_DLGMODALFRAME, cWindowClass, cTitle, WS_SYSMENU | WS_CAPTION | WS_DLGFRAME | WS_VISIBLE | WS_CLIPCHILDREN, x_window_pos, y_window_pos, w_dialog, h_dialog, NULL, NULL, hInstance, NULL); if (!sMainWindow) return FALSE; ShowWindow(sMainWindow, nCmdShow); // Create cancel button sCancelButton = CreateWindow("BUTTON", "Cancel", WS_CHILD | BS_PUSHBUTTON | WS_VISIBLE, x_cancel_button, y_cancel_button, w_cancel_button, h_cancel_button, sMainWindow, NULL, hInstance, NULL); HFONT font = (HFONT) GetStockObject(DEFAULT_GUI_FONT); SendMessage(sCancelButton, WM_SETFONT, (WPARAM)font, MAKELPARAM(FALSE, 0)); // Create the progress bar WNDCLASSEX pb_wnd_class; pb_wnd_class.cbSize = sizeof(WNDCLASSEX); pb_wnd_class.style = 0; pb_wnd_class.lpfnWndProc = WndProc; pb_wnd_class.cbClsExtra = 0; pb_wnd_class.cbWndExtra = 0; pb_wnd_class.hInstance = hInstance; pb_wnd_class.hIcon = NULL; pb_wnd_class.hCursor = LoadCursor(NULL, IDC_ARROW); pb_wnd_class.hbrBackground = (HBRUSH) (COLOR_WINDOW); pb_wnd_class.lpszMenuName = NULL; pb_wnd_class.lpszClassName = "P4fsvProgressBar"; pb_wnd_class.hIconSm = NULL; ATOM pb_class = RegisterClassEx(&pb_wnd_class); sProgressbar = CreateWindowEx(WS_EX_STATICEDGE, "P4fsvProgressBar", NULL, WS_CHILD | WS_VISIBLE, x_progressbar, y_progressbar, w_progressbar, h_progressbar, sMainWindow, NULL, hInstance, NULL); sProgressBitmap = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BITMAP1)); sTimer = SetTimer(sMainWindow, 1, 40, NULL); // And now start the sync CreateThread(NULL, 0, SyncThread, NULL, 0, NULL); sStartTime = GetTickCount(); return TRUE; } int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); MyRegisterClass(hInstance); if (!InitInstance (hInstance, nCmdShow)) return FALSE; MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } DeleteObject(sProgressBitmap); // So as not to interfere with normal p4 exit codes (which, as far as I can tell are undocumented) // We add 1000 to our exit code on failure. Success is still signaled by FS_OK (=0) if (sResult != FS_OK && sResult != FS_HELP) return sResult + 1000; return FS_OK; }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#3 | 6451 | Frank Compagner |
- Now fully support unicode & utf-16 files - Improved accuracy of P4fsV progress bar - Added logging to help in remote debugging |
||
#2 | 6420 | Frank Compagner |
A number of improvements: - p4fs now supports the global -s (scripted output) option. - p4fs and P4fsV now support the modtime client option. - P4CHARSET is now correctly handled (though no full Unicode support yet). - Increased the maximum command line length for p4fs to the Windows maximum 32768. - Improved error handling. - Fixed a crash when cancelling a sync using the async or multithreaded writers. - P4fsV progressbar now behaves well when passing more than one filespec - P4fsV will now offer the option to overwrite any locally changed (but not checked out) files when it finds these during a sync (cannot clobber ...). - Made the P4fsV error dialog resizeable. - P4fsV Windows layout fixed so it works properly with all Windows style setings. - Ooh, and prettier icons too. |
||
#1 | 6187 | Frank Compagner | Added p4fs project |