I wrote a set of functions for displaying a progress window while CopyFileEx() runs. The only problem is that the cancel button on the window won't work. Well, actually it will work if I display a message box right before I create the window, which I haven't been able to explain yet... Anyway, here is the full code for it, less the headers:
#include "global_definitions.h"
#include <windows.h>
#include <commctrl.h>
#include "debug.h"
#include "memory.h"
#include "stringio.h"
#include "window_classes.h"
void InitProgressWindowClass(void);
int CopyFileProgressEx(LPCTSTR lpExistingFileName, LPCTSTR lpNewFileName, DWORD dwCopyFlags, HWND hWndParent, char * title, char * message, BOOL popup, DWORD parentUpdate);
DWORD WINAPI ProgressWindowThread(LPVOID lParam);
INT_PTR CALLBACK ProgressWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT ProgressWindow_OnCreate(HWND hWnd, WPARAM wParam, LPARAM lParam);
DWORD CALLBACK CopyProgressRoutine(LARGE_INTEGER TotalFileSize, LARGE_INTEGER TotalBytesTransferred, LARGE_INTEGER StreamSize, LARGE_INTEGER StreamBytesTransferred, DWORD dwStreamNumber, DWORD dwCallbackReason, HANDLE hSourceFile, HANDLE hDestinationFile, LPVOID lpData);
void InitProgressWindowClass(void)
{
WNDCLASSEX wc = {0};
wc.cbSize = sizeof(wc);
wc.lpszClassName = "Progress Window";
wc.hInstance = GetModuleHandle(NULL);
wc.lpfnWndProc = ProgressWindowProc;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_BTNFACE);
wc.cbWndExtra = sizeof(PROGRESSINFO *);
RegisterClassEx(&wc);
}
int CopyFileProgressEx(LPCTSTR lpExistingFileName, LPCTSTR lpNewFileName, DWORD dwCopyFlags, HWND hWndParent, char * title, char * message, BOOL popup, DWORD parentUpdate)
{
PROGRESSINFO * pip = ClearMemAlloc(sizeof(PROGRESSINFO));
BOOL error;
BOOL cancel = 0;
DWORD threadId;
if(!title)
title = "";
if(!message)
message = "";
pip->title = title;
pip->message = message;
pip->popup = popup;
pip->cancel = &cancel;
pip->hWndParent = hWndParent;
pip->parentUpdate = parentUpdate;
SetFocus(hWndParent);
CreateThread(NULL, 0, ProgressWindowThread, pip, 0, &threadId);
while(!pip->hWndProgress)
Sleep(0);
error = CopyFileEx(lpExistingFileName, lpNewFileName, CopyProgressRoutine, pip, NULL, dwCopyFlags);
if(!error)
return 1;
else if(cancel)
return 2;
return 0;
}
DWORD WINAPI ProgressWindowThread(LPVOID lParam)
{
MSG msg;
DWORD exitCode = 0;
PROGRESSINFO * pip = (PROGRESSINFO *) lParam;
DWORD dwStyle = (pip->hWndParent != NULL ? WS_CHILD : 0) | WS_VISIBLE;
RECT progressCords;
if(pip->popup)
{
progressCords.left = GetSystemMetrics(SM_CXSCREEN) / 2 - PROGRESSWINDOW_WIDTH / 2;
progressCords.top = GetSystemMetrics(SM_CYSCREEN) / 2 - PROGRESSWINDOW_HEIGHT / 2;
dwStyle |= WS_POPUPWINDOW;
}
else
{
dwStyle |= WS_DLGFRAME;
GetClientRect(pip->hWndParent, &progressCords);
progressCords.left = (progressCords.right - progressCords.left) / 2 - PROGRESSWINDOW_WIDTH / 2;
progressCords.top = (progressCords.bottom - progressCords.top) / 2 - PROGRESSWINDOW_HEIGHT / 2;
}
pip->hWndProgress = CreateWindowEx(
0,
"Progress Window",
pip->title,
dwStyle,
progressCords.left,
progressCords.top,
PROGRESSWINDOW_WIDTH,
PROGRESSWINDOW_HEIGHT,
pip->hWndParent,
NULL,
GetModuleHandle(NULL),
pip);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
GetExitCodeThread(GetCurrentThread(), &exitCode);
ExitThread(exitCode);
ErrorMessage("Abnormal thread termination", NULL, NULL, MB_ICONEXCLAMATION, 1);
return FALSE;
}
INT_PTR CALLBACK ProgressWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_CREATE:
return ProgressWindow_OnCreate(hWnd, wParam, lParam);
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case BN_CLICKED:
*(((PROGRESSINFO *)(GetWindowLongPtr(hWnd, GWL_USERDATA)))->cancel) = 1;
break;
}
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
free((void *) GetWindowLongPtr(hWnd, GWL_USERDATA));
break;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
LRESULT ProgressWindow_OnCreate(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
PROGRESSINFO * pip = *(PROGRESSINFO **) lParam;
RECT rect;
SetWindowLongPtr(hWnd, GWL_USERDATA, (LONG) pip);
GetClientRect(hWnd, &rect);
pip->progressBar = CreateWindowEx(
WS_EX_CLIENTEDGE,
PROGRESS_CLASS,
NULL,
WS_CHILD | WS_VISIBLE | PBS_SMOOTH,
rect.left + 2,
PROGRESSWINDOW_HEIGHT / 2 - GetSystemMetrics(SM_CYVSCROLL),
rect.right - 5,
GetSystemMetrics(SM_CYVSCROLL),
hWnd,
0,
GetModuleHandle(NULL),
NULL);
pip->hWndStatic = CreateWindowEx(
0,
"Static",
NULL,
WS_CHILD | WS_VISIBLE | SS_CENTER,
rect.left + 2,
rect.top + 10,
rect.right - 5,
rect.top + 20,
hWnd,
0,
GetModuleHandle(NULL),
NULL);
SetWindowText(pip->hWndStatic, pip->message);
pip->hWndCancel = CreateWindowEx(
0,
"Button",
NULL,
WS_CHILD | WS_VISIBLE | BS_TEXT | BS_PUSHBUTTON,
((rect.right - rect.left) / 2) + rect.left - 30,
rect.bottom - 30,
60,
24,
hWnd,
0,
GetModuleHandle(NULL),
NULL);
SetWindowText(pip->hWndCancel, "Cancel");
pip->hWndProgress = hWnd;
SetFocus(pip->hWndCancel);
return FALSE;
}
DWORD CALLBACK CopyProgressRoutine(LARGE_INTEGER TotalFileSize, LARGE_INTEGER TotalBytesTransferred, LARGE_INTEGER StreamSize, LARGE_INTEGER StreamBytesTransferred, DWORD dwStreamNumber, DWORD dwCallbackReason, HANDLE hSourceFile, HANDLE hDestinationFile, LPVOID lpData)
{
int i;
unsigned __int64 biasBit = 0x8000000000000000;
int progressRange;
int progressAchieved;
PROGRESSINFO * pip = lpData;
if(!pip->progressBias)
{
if(!(TotalFileSize.QuadPart & 0xFFFFFFFF80000000))
pip->progressBias = 0;
else
{
for(i = 33; i; i--)
{
if(biasBit & TotalFileSize.QuadPart)
break;
biasBit = biasBit>>1;
}
pip->progressBias = 32 - i;
}
}
progressRange = (int) (TotalFileSize.QuadPart>>(pip->progressBias + 1));
progressAchieved = (int) (TotalBytesTransferred.QuadPart>>(pip->progressBias + 1));
SendMessage(pip->progressBar, (UINT) PBM_SETRANGE32, (WPARAM) 0, (LPARAM) progressRange);
SendMessage(pip->progressBar, (UINT) PBM_SETPOS, (WPARAM) progressAchieved, (LPARAM) 0);
if(pip->parentUpdate && pip->lastParentUpdate + pip->parentUpdate >= GetTickCount())
UpdateWindow(pip->hWndParent);
pip->lastParentUpdate = GetTickCount();
if(TotalFileSize.QuadPart == TotalBytesTransferred.QuadPart)
{
PostMessage(pip->hWndProgress, WM_CLOSE, 0, 0);
return PROGRESS_CONTINUE;
}
if(*pip->cancel)
{
PostMessage(pip->hWndProgress, WM_CLOSE, 0, 0);
return PROGRESS_CANCEL;
}
else
return PROGRESS_CONTINUE;
}
|