[C++] 纯文本查看 复制代码
#include <windows.h>
#include <gdiplus.h>
#include <urlmon.h>
#include <process.h> // 用于_beginthreadex替代std::thread
#include <tlhelp32.h>
#include <wininet.h> // 添加WinINet支持
#include <string>
#include <vector>
#pragma comment(lib, "gdiplus.lib")
#pragma comment(lib, "urlmon.lib")
#pragma comment(lib, "wininet.lib")
// 因为XP不支持std::thread所以使用_beginthreadex
typedef struct {
std::wstring url;
std::wstring savePath;
} DownloadParams;
using namespace Gdiplus;
// 全局变量
ULONG_PTR gdiplusToken;
HINSTANCE hInst;
POINT ptWindowPos = { 0, 0 };
bool isDragging = false;
POINT ptDragStart = { 0, 0 };
int progressValue = 0; // 进度条当前值
// 下载进度全局变量
int g_downloadProgress = 0; // 实际下载进度
// 更新信息结构
struct UpdateInfo {
std::wstring softwareName;
std::wstring processName;
std::wstring version;
std::wstring downloadUrl;
bool forceReplace;
std::wstring installPath;
};
UpdateInfo g_updateInfo;
bool g_isDownloading = false;
bool g_downloadCompleted = false;
bool g_downloadFailed = false; // 添加下载失败标志
std::wstring g_downloadedFilePath;
// 自定义下载回调类,用于更新下载进度
class DownloadProgress_callback : public IBindStatusCallback {
public:
DownloadProgress_callback() : m_refCount(1) {}
STDMETHOD(OnProgress)(ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR wszStatusText) {
if (ulProgressMax > 0) {
g_downloadProgress = static_cast<int>((static_cast<double>(ulProgress) / static_cast<double>(ulProgressMax)) * 100);
// 确保进度值在0-100范围内
if (g_downloadProgress > 100) g_downloadProgress = 100;
if (g_downloadProgress < 0) g_downloadProgress = 0;
}
return S_OK;
}
// IUnknown接口实现
STDMETHOD_(ULONG, AddRef)() {
return InterlockedIncrement(&m_refCount);
}
STDMETHOD_(ULONG, Release)() {
long count = InterlockedDecrement(&m_refCount);
if (count == 0) {
delete this;
}
return count;
}
STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject) {
if (riid == IID_IUnknown || riid == IID_IBindStatusCallback) {
*ppvObject = this;
AddRef();
return S_OK;
}
*ppvObject = NULL;
return E_NOINTERFACE;
}
// 实现IBindStatusCallback接口方法
STDMETHOD(OnStartBinding)(DWORD dwReserved, IBinding *pib) { return E_NOTIMPL; }
STDMETHOD(GetPriority)(LONG *pnPriority) { return E_NOTIMPL; }
STDMETHOD(OnLowResource)(DWORD reserved) { return S_OK; }
STDMETHOD(OnStopBinding)(HRESULT hresult, LPCWSTR szError) { return S_OK; }
STDMETHOD(GetBindInfo)(DWORD *grfBINDF, BINDINFO *pbindinfo) { return E_NOTIMPL; }
STDMETHOD(OnDataAvailable)(DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed) { return S_OK; }
STDMETHOD(OnObjectAvailable)(REFIID riid, IUnknown *punk) { return E_NOTIMPL; }
private:
long m_refCount;
};
// 函数声明
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void PaintContent(HWND hwnd, PAINTSTRUCT& ps);
void DrawContent(Graphics& graphics, const RECT& rcClient, float dpiScale);
Bitmap* LoadPngFromResource(HINSTANCE hInstance, LPCWSTR resourceName);
void DrawProgressBar(Graphics& graphics, const Rect& bounds, int progress, float dpiScale);
void ParseCommandLine(LPWSTR cmdLine);
void DownloadUpdateFile(const std::wstring& url, const std::wstring& savePath);
unsigned int __stdcall DownloadThreadProc(void* param);
void StartDownload();
bool TerminateProcessByName(const std::wstring& processName);
bool ReplaceTargetFile(const std::wstring& sourceFile, const std::wstring& targetPath);
// 应用程序入口
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
hInst = hInstance;
// 解析命令行参数
if (wcslen(lpCmdLine) > 0) {
ParseCommandLine(lpCmdLine);
}
// 初始化COM和GDI+
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr)) {
return FALSE;
}
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
// 注册窗口类
WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.hInstance = hInstance;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszClassName = L"CustomDrawWindow";
RegisterClassEx(&wcex);
// 在创建窗口前计算屏幕中心位置
int screenWidth = GetSystemMetrics(SM_CXSCREEN);
int screenHeight = GetSystemMetrics(SM_CYSCREEN);
int windowWidth = 420;
int windowHeight = 211;
int posX = (screenWidth - windowWidth) / 2;
int posY = (screenHeight - windowHeight) / 2;
// 创建窗口并显示
HWND hWnd = CreateWindowEx(
0,
L"CustomDrawWindow",
L"GDI+ High DPI Custom Draw Window",
WS_POPUP,
posX, posY, // 居中显示的位置
windowWidth, windowHeight,
NULL,
NULL,
hInstance,
NULL);
if (!hWnd)
return FALSE;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
// 创建一个定时器用于更新进度条
SetTimer(hWnd, 1, 100, NULL); // 每100ms触发一次
// 消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// 清理资源
GdiplusShutdown(gdiplusToken);
CoUninitialize();
return (int)msg.wParam;
}
// 获取当前DPI的辅助函数 (XP兼容版本)
UINT GetWindowDpi(HWND hwnd) {
HDC hdc = GetDC(hwnd);
int dpiX = GetDeviceCaps(hdc, LOGPIXELSX);
ReleaseDC(hwnd, hdc);
return dpiX;
}
// 从资源加载PNG图片
Bitmap* LoadPngFromResource(HINSTANCE hInstance, LPCWSTR resourceName)
{
// 尝试多种方式加载资源
HRSRC hResource = NULL;
// 方式1: 使用PNG类型参数
hResource = FindResourceW(hInstance, resourceName, L"PNG");
// 方式2: 如果失败,使用IMAGE类型参数
if (!hResource) {
hResource = FindResourceW(hInstance, resourceName, L"IMAGE");
}
// 方式3: 如果仍然失败,使用默认资源类型参数
if (!hResource) {
hResource = FindResource(hInstance, resourceName, L"PNG");
}
// 方式4: 如果全都失败,使用固定ID
if (!hResource) {
hResource = FindResource(hInstance, MAKEINTRESOURCE(101), L"PNG");
}
if (!hResource) {
return nullptr;
}
// 加载资源
HGLOBAL hMemory = LoadResource(hInstance, hResource);
if (!hMemory) {
return nullptr;
}
// 获取资源大小
DWORD dwSize = SizeofResource(hInstance, hResource);
if (dwSize == 0) {
return nullptr;
}
VOID* pResourceData = LockResource(hMemory);
if (!pResourceData) {
return nullptr;
}
// 分配全局内存
HGLOBAL hBuffer = GlobalAlloc(GMEM_MOVEABLE, dwSize);
if (!hBuffer) {
return nullptr;
}
VOID* pBuffer = GlobalLock(hBuffer);
if (!pBuffer) {
GlobalFree(hBuffer);
return nullptr;
}
// 复制资源数据到内存
CopyMemory(pBuffer, pResourceData, dwSize);
GlobalUnlock(hBuffer);
// 创建IStream
IStream* pStream = nullptr;
if (CreateStreamOnHGlobal(hBuffer, FALSE, &pStream) != S_OK) {
GlobalFree(hBuffer);
return nullptr;
}
// 创建Bitmap
Bitmap* bitmap = Bitmap::FromStream(pStream);
pStream->Release();
GlobalFree(hBuffer);
if (!bitmap) {
return nullptr;
}
if (bitmap->GetLastStatus() != Ok) {
delete bitmap;
return nullptr;
}
return bitmap;
}
// 绘制进度条
void DrawProgressBar(Graphics& graphics, const Rect& bounds, int progress, float dpiScale) {
// 确保进度值在0-100范围内
if (progress < 0) progress = 0;
if (progress > 100) progress = 100;
// 创建圆角矩形路径
GraphicsPath path;
int cornerRadius = static_cast<int>(5 * dpiScale);
// 构建路径
path.AddArc(bounds.X, bounds.Y, cornerRadius * 2, cornerRadius * 2, 180, 90);
path.AddArc(bounds.X + bounds.Width - cornerRadius * 2, bounds.Y, cornerRadius * 2, cornerRadius * 2, 270, 90);
path.AddArc(bounds.X + bounds.Width - cornerRadius * 2, bounds.Y + bounds.Height - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 0, 90);
path.AddArc(bounds.X, bounds.Y + bounds.Height - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 90, 90);
path.CloseFigure();
// 绘制进度条背景
Color backgroundColor(255, 220, 220, 220); // 浅灰色
SolidBrush backgroundBrush(backgroundColor);
graphics.FillPath(&backgroundBrush, &path);
// 绘制进度条填充部分
if (progress > 0) {
int fillWidth = static_cast<int>((bounds.Width - 4) * progress / 100.0);
if (fillWidth > 0) {
Rect fillRect(bounds.X + 2, bounds.Y + 2, fillWidth, bounds.Height - 4);
// 创建填充部分的圆角矩形路径
GraphicsPath fillPath;
int fillCornerRadius = cornerRadius > 2 ? cornerRadius - 2 : 1;
fillPath.AddArc(fillRect.X, fillRect.Y, fillCornerRadius * 2, fillCornerRadius * 2, 180, 90);
fillPath.AddArc(fillRect.X + fillRect.Width - fillCornerRadius * 2, fillRect.Y, fillCornerRadius * 2, fillCornerRadius * 2, 270, 90);
fillPath.AddArc(fillRect.X + fillRect.Width - fillCornerRadius * 2, fillRect.Y + fillRect.Height - fillCornerRadius * 2, fillCornerRadius * 2, fillCornerRadius * 2, 0, 90);
fillPath.AddArc(fillRect.X, fillRect.Y + fillRect.Height - fillCornerRadius * 2, fillCornerRadius * 2, fillCornerRadius * 2, 90, 90);
fillPath.CloseFigure();
// 创建垂直线性渐变 (浅蓝色到深蓝色)
LinearGradientBrush gradientBrush(
PointF(static_cast<Gdiplus::REAL>(fillRect.X), static_cast<Gdiplus::REAL>(fillRect.Y)),
PointF(static_cast<Gdiplus::REAL>(fillRect.X), static_cast<Gdiplus::REAL>(fillRect.Y + fillRect.Height)),
Color(255, 95, 205, 255), // 浅蓝色
Color(255, 50, 144, 225) // 深蓝色
);
graphics.FillPath(&gradientBrush, &fillPath);
}
}
// 绘制边框
Pen borderPen(Color(255, 180, 180, 180), 1.0f);
graphics.DrawPath(&borderPen, &path);
// 绘制进度文本
WCHAR progressText[32];
swprintf_s(progressText, L"%d%%", progress);
Font font(L"Arial", 14 * dpiScale, FontStyleBold);
SolidBrush textBrush(Color(255, 255, 255, 255));
// 测量文本大小
RectF textBounds;
graphics.MeasureString(progressText, -1, &font, PointF(0, 0), &textBounds);
// 定位文本
PointF textPos(
bounds.X + (bounds.Width - textBounds.Width) / 2,
bounds.Y + (bounds.Height - textBounds.Height) / 2
);
graphics.DrawString(progressText, -1, &font, textPos, &textBrush);
}
// 绘制函数
void PaintContent(HWND hwnd, PAINTSTRUCT& ps) {
// 获取客户区域
RECT rcClient;
GetClientRect(hwnd, &rcClient);
// 创建内存位图用于双缓冲
Bitmap doubleBufferBitmap(rcClient.right - rcClient.left, rcClient.bottom - rcClient.top);
Graphics doubleBufferGraphics(&doubleBufferBitmap);
doubleBufferGraphics.SetSmoothingMode(SmoothingModeAntiAlias);
doubleBufferGraphics.SetInterpolationMode(InterpolationModeHighQualityBicubic);
// 获取当前DPI
UINT dpi = GetWindowDpi(hwnd);
float dpiScale = dpi / 96.0f;
if (dpiScale == 0) dpiScale = 1.0f;
DrawContent(doubleBufferGraphics, rcClient, dpiScale);
// 将双缓冲内容绘制到屏幕
Graphics screenGraphics(ps.hdc);
screenGraphics.DrawImage(&doubleBufferBitmap, 0, 0);
}
// 绘制窗口内容
void DrawContent(Graphics& graphics, const RECT& rcClient, float dpiScale) {
// 从资源文件加载背景图片 - 使用专用的背景资源ID
Bitmap* background = LoadPngFromResource(hInst, L"IDB_PNG1");
// 如果失败,尝试可能的背景资源ID
if (!background) {
background = LoadPngFromResource(hInst, L"PNG1");
}
if (!background) {
background = LoadPngFromResource(hInst, MAKEINTRESOURCE(101)); // 使用资源ID 101作为默认图
}
if (!background) {
background = LoadPngFromResource(hInst, MAKEINTRESOURCE(104)); // 使用背景资源ID
}
// 加载成功则绘制背景图片
if (background && background->GetLastStatus() == Ok) {
// 获取目标窗口尺寸
int targetWidth = rcClient.right - rcClient.left;
int targetHeight = rcClient.bottom - rcClient.top;
// 直接绘制图片到窗口大小,避免使用缩放版本
graphics.DrawImage(background, 0, 0, targetWidth, targetHeight);
delete background;
}
else {
// 如果无法加载背景图片,则绘制纯色背景
SolidBrush brush(Color(70, 130, 180)); // SteelBlue
graphics.FillRectangle(&brush, rcClient.left, rcClient.top,
rcClient.right - rcClient.left,
rcClient.bottom - rcClient.top);
// 显示错误信息给用户
Font errorFont(L"Arial", 16 * dpiScale);
SolidBrush errorBrush(Color(255, 255, 255, 255));
graphics.DrawString(L"加载背景图片资源失败", -1, &errorFont,
PointF(210 * dpiScale, 100 * dpiScale), &errorBrush);
}
// 绘制版本文本 (自动计算位置)
Font titleFont(L"微软雅黑", 10 * dpiScale, FontStyleBold);
SolidBrush textBrush(Color(255, 255, 255, 255));
RectF textBounds;
// 构造显示版本号的文本
std::wstring versionText = L"当前版本: " + g_updateInfo.version;
// 只有当版本号不为空时才显示
if (!g_updateInfo.version.empty()) {
// 测量文本大小
graphics.MeasureString(versionText.c_str(), -1, &titleFont, PointF(0, 0), &textBounds);
// 计算文本位置 (右对齐,直接使用偏移)
float x = 180 * dpiScale;
float y = 100 * dpiScale;
graphics.DrawString(versionText.c_str(), -1, &titleFont, PointF(x, y), &textBrush);
}
// 绘制进度条 (位置根据背景LOGO调整)
Rect progressBarRect(
static_cast<int>(20 * dpiScale), // X轴偏移,靠左LOGO旁边
static_cast<int>(150 * dpiScale),
static_cast<int>(380 * dpiScale), // 宽度根据窗口大小调整
static_cast<int>(30 * dpiScale)
);
DrawProgressBar(graphics, progressBarRect, progressValue, dpiScale);
}
// 解析命令行参数
void ParseCommandLine(LPWSTR cmdLine) {
std::wstring cmd(cmdLine);
// 先尝试按引号分割参数
size_t pos = 0;
std::vector<std::wstring> args;
std::wstring token;
// 解析带引号的参数
while ((pos = cmd.find(L"\"")) != std::wstring::npos) {
cmd.erase(0, pos + 1);
pos = cmd.find(L"\"");
if (pos != std::wstring::npos) {
token = cmd.substr(0, pos);
args.push_back(token);
cmd.erase(0, pos + 1);
}
}
// 解析剩余的无引号参数
if (!cmd.empty()) {
// 按空格分割剩余参数
size_t start = 0;
size_t end = 0;
while ((end = cmd.find(L" ", start)) != std::wstring::npos) {
std::wstring param = cmd.substr(start, end - start);
if (!param.empty()) {
args.push_back(param);
}
start = end + 1;
}
// 添加最后的一个参数
std::wstring lastParam = cmd.substr(start);
if (!lastParam.empty()) {
args.push_back(lastParam);
}
}
if (args.size() >= 6) {
g_updateInfo.softwareName = args[0];
g_updateInfo.processName = args[1];
g_updateInfo.version = args[2];
g_updateInfo.downloadUrl = args[3];
g_updateInfo.forceReplace = (args[4] == L"true" || args[4] == L"1");
g_updateInfo.installPath = args[5];
}
}
// 使用WinINet的下载函数(更好的XP兼容性)
bool DownloadFileWithWinINet(const std::wstring& url, const std::wstring& savePath) {
// 初始化WinINet
HINTERNET hInternet = InternetOpen(L"UpdateClient/1.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (!hInternet) {
return false;
}
// 打开URL连接
HINTERNET hUrl = InternetOpenUrl(hInternet, url.c_str(), NULL, 0, INTERNET_FLAG_RELOAD, 0);
if (!hUrl) {
InternetCloseHandle(hInternet);
return false;
}
// 创建本地文件
HANDLE hFile = CreateFile(savePath.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
InternetCloseHandle(hUrl);
InternetCloseHandle(hInternet);
return false;
}
// 下载并保存数据
char buffer[4096];
DWORD bytesRead, bytesWritten;
bool success = true;
DWORD totalBytes = 0;
DWORD contentLength = 0;
// 获取内容长度
wchar_t szContentLength[32];
DWORD dwLength = sizeof(szContentLength);
if (HttpQueryInfo(hUrl, HTTP_QUERY_CONTENT_LENGTH, szContentLength, &dwLength, NULL)) {
contentLength = _wtoi(szContentLength);
}
while (InternetReadFile(hUrl, buffer, sizeof(buffer), &bytesRead) && bytesRead > 0) {
if (!WriteFile(hFile, buffer, bytesRead, &bytesWritten, NULL)) {
success = false;
break;
}
totalBytes += bytesRead;
// 更新进度
if (contentLength > 0) {
g_downloadProgress = static_cast<int>((static_cast<double>(totalBytes) / static_cast<double>(contentLength)) * 100);
if (g_downloadProgress > 100) g_downloadProgress = 100;
}
}
CloseHandle(hFile);
InternetCloseHandle(hUrl);
InternetCloseHandle(hInternet);
return success;
}
// 文件下载支持进度更新
void DownloadUpdateFile(const std::wstring& url, const std::wstring& savePath) {
g_isDownloading = true;
g_downloadCompleted = false;
g_downloadFailed = false;
g_downloadProgress = 0;
// 尝试使用WinINet下载(更好的XP兼容性)
bool success = DownloadFileWithWinINet(url, savePath);
// 如果WinINet失败,尝试使用URLDownloadToFile
if (!success) {
// 创建下载回调对象
DownloadProgress_callback* callback = new DownloadProgress_callback();
// 使用URLDownloadToFile进行文件下载并设置回调
HRESULT hr = URLDownloadToFile(NULL, url.c_str(), savePath.c_str(), 0, callback);
// 释放回调对象
callback->Release();
success = (hr == S_OK);
}
g_isDownloading = false;
g_downloadCompleted = success;
g_downloadFailed = !success;
g_downloadedFilePath = savePath;
// 下载完成后将进度设为100%
if (g_downloadCompleted) {
g_downloadProgress = 100;
}
}
// 下载线程过程函数 (XP兼容版本)
unsigned int __stdcall DownloadThreadProc(void* param) {
DownloadParams* params = static_cast<DownloadParams*>(param);
DownloadUpdateFile(params->url, params->savePath);
delete params;
return 0;
}
// 开始下载
void StartDownload() {
if (g_updateInfo.downloadUrl.empty()) return;
// 直接使用installPath作为保存路径
std::wstring savePath = g_updateInfo.installPath;
// 确保目录存在
size_t lastSlash = savePath.find_last_of(L"\\/");
if (lastSlash != std::wstring::npos) {
std::wstring directory = savePath.substr(0, lastSlash);
CreateDirectoryW(directory.c_str(), NULL);
}
// 创建参数结构
DownloadParams* params = new DownloadParams();
params->url = g_updateInfo.downloadUrl;
params->savePath = savePath;
// 创建下载线程 (使用XP兼容的方式)
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, DownloadThreadProc, params, 0, NULL);
if (hThread) {
CloseHandle(hThread);
}
}
// 终止指定进程
bool TerminateProcessByName(const std::wstring& processName) {
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE) {
return false;
}
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(hSnapshot, &pe32)) {
CloseHandle(hSnapshot);
return false;
}
bool found = false;
do {
if (_wcsicmp(pe32.szExeFile, processName.c_str()) == 0) {
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pe32.th32ProcessID);
if (hProcess != NULL) {
TerminateProcess(hProcess, 0);
CloseHandle(hProcess);
found = true;
}
}
} while (Process32Next(hSnapshot, &pe32));
CloseHandle(hSnapshot);
return found;
}
// 替换文件
bool ReplaceTargetFile(const std::wstring& sourceFile, const std::wstring& targetPath) {
// 确保目标目录存在
std::wstring directory = targetPath.substr(0, targetPath.find_last_of(L"\\/"));
CreateDirectoryW(directory.c_str(), NULL);
// 复制文件
return CopyFileW(sourceFile.c_str(), targetPath.c_str(), FALSE) == TRUE;
}
// 窗口过程函数
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
PaintContent(hWnd, ps);
EndPaint(hWnd, &ps);
}
break;
case WM_TIMER:
{
// 更新进度条值
if (wParam == 1) {
// 检查是否有更新信息需要处理
if (!g_updateInfo.softwareName.empty() && !g_isDownloading && !g_downloadCompleted) {
// 开始下载
StartDownload();
}
// 检查下载是否完成
if (g_downloadCompleted) {
// 下载完成,根据参数决定是否替换
if (g_updateInfo.forceReplace) {
// 强制替换
TerminateProcessByName(g_updateInfo.processName);
ReplaceTargetFile(g_downloadedFilePath, g_updateInfo.installPath);
// 启动新版本程序
ShellExecuteW(NULL, L"open", g_updateInfo.installPath.c_str(), NULL, NULL, SW_SHOWNORMAL);
// 退出更新程序
PostMessage(hWnd, WM_CLOSE, 0, 0);
}
else {
// 非强制替换,需要提示用户手动确认
// 可以在这里添加UI提示
}
g_downloadCompleted = false; // 重置状态
}
// 只在下载时才更新进度条
if (g_isDownloading) {
// 使用实际下载进度更新进度条
progressValue = g_downloadProgress;
}
else if (g_downloadCompleted) {
// 下载完成,显示100%
progressValue = 100;
}
else if (g_downloadFailed) {
// 下载失败,显示错误
progressValue = -1; // 可用特殊值表示错误
}
InvalidateRect(hWnd, NULL, FALSE); // 请求重绘
}
}
break;
case WM_LBUTTONDOWN:
{
isDragging = true;
POINT ptMouse;
ptMouse.x = (short)LOWORD(lParam);
ptMouse.y = (short)HIWORD(lParam);
ClientToScreen(hWnd, &ptMouse);
ptDragStart = ptMouse;
RECT rcWindow;
GetWindowRect(hWnd, &rcWindow);
ptWindowPos.x = rcWindow.left;
ptWindowPos.y = rcWindow.top;
SetCapture(hWnd);
}
break;
case WM_LBUTTONUP:
{
isDragging = false;
ReleaseCapture();
}
break;
case WM_MOUSEMOVE:
{
if (isDragging && (wParam & MK_LBUTTON)) {
POINT ptMouse;
ptMouse.x = (short)LOWORD(lParam);
ptMouse.y = (short)HIWORD(lParam);
ClientToScreen(hWnd, &ptMouse);
POINT ptNewPos;
ptNewPos.x = ptWindowPos.x + (ptMouse.x - ptDragStart.x);
ptNewPos.y = ptWindowPos.y + (ptMouse.y - ptDragStart.y);
SetWindowPos(hWnd, NULL, ptNewPos.x, ptNewPos.y, 0, 0,
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}
}
break;
case WM_SIZE:
InvalidateRect(hWnd, NULL, TRUE);
break;
case WM_KEYDOWN:
if (wParam == VK_ESCAPE) {
PostMessage(hWnd, WM_CLOSE, 0, 0);
}
break;
case WM_RBUTTONDOWN:
PostMessage(hWnd, WM_CLOSE, 0, 0);
break;
case WM_DESTROY:
KillTimer(hWnd, 1); // 销毁定时器
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}