From 1ff9789272119494df17df59c71f07203b24c14a Mon Sep 17 00:00:00 2001 From: kichik Date: Sun, 1 Feb 2004 18:52:06 +0000 Subject: [PATCH] All windows are now created in the main thread where the main dialog is created. This should fix any weird user32.dll crashes caused by different types of messages sent to the main dialog during destruction of the NSISdl dialog. This also reduces the size of the DLL by 0.5KB :) git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@3444 212acab6-be3b-0410-9dea-997c60f758d6 --- Contrib/NSISdl/ReadMe.txt | 2 +- Contrib/NSISdl/nsisdl.cpp | 356 ++++++++++++++++---------------------- Contrib/NSISdl/nsisdl.dsp | 8 - Plugins/nsisdl.dll | Bin 13824 -> 12800 bytes 4 files changed, 152 insertions(+), 214 deletions(-) diff --git a/Contrib/NSISdl/ReadMe.txt b/Contrib/NSISdl/ReadMe.txt index ae1094c5..184fec4a 100644 --- a/Contrib/NSISdl/ReadMe.txt +++ b/Contrib/NSISdl/ReadMe.txt @@ -1,4 +1,4 @@ -NSISdl 1.1 - HTTP downloading plugin for NSIS +NSISdl 1.3 - HTTP downloading plugin for NSIS --------------------------------------------- Copyright (C) 2001-2002 Yaroslav Faybishenko & Justin Frankel diff --git a/Contrib/NSISdl/nsisdl.cpp b/Contrib/NSISdl/nsisdl.cpp index 757860a6..5edfaee0 100644 --- a/Contrib/NSISdl/nsisdl.cpp +++ b/Contrib/NSISdl/nsisdl.cpp @@ -1,5 +1,5 @@ /* - NSIS-DL 1.2 - http downloading DLL for NSIS + NSIS-DL 1.3 - http downloading DLL for NSIS Copyright (C) 2001-2002 Yaroslav Faybishenko & Justin Frankel This software is provided 'as-is', without any express or implied @@ -17,22 +17,13 @@ 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. - - - - Note: this source code is pretty hacked together right now, improvements - and cleanups will come later. - - IMPORTANT: The dialog must have the style "No Parent Notify" - - */ +*/ #include #include #include #include "netinc.h" #include "util.h" -#include "resource.h" #include "httpget.h" #include "../exdll/exdll.h" @@ -43,106 +34,165 @@ void *operator new( unsigned int num_bytes ) void operator delete( void *p ) { if (p) GlobalFree(p); } -HANDLE hModule; -HWND g_hwndProgressBar; +HMODULE hModule; +HWND g_hwndProgressBar; +HWND g_hwndStatic; static int g_cancelled; -long lBusy; -ULONG idThreadOwner; -ULONG ulRefCount; static void *lpWndProcOld; -BOOL CALLBACK DownloadDialogProc(HWND hwndDlg, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) -{ - return 0; -} +static UINT uMsgCreate; -BOOL TryEnterCS() -{ - DWORD CurThreadID = ::GetCurrentThreadId(); - BOOL bRet = TRUE; - long *plBusy = &lBusy; - while (::InterlockedExchange(plBusy, 1) != 0) - { - Sleep(0); - } - - if (idThreadOwner == 0) - { - idThreadOwner = CurThreadID; - ulRefCount = 1; - } - else if (idThreadOwner == CurThreadID) - { - ulRefCount++; - } - else - { - bRet = FALSE; - } - - ::InterlockedExchange(plBusy, 0); - - return bRet; -} - -void LeaveCS() -{ - long *plBusy = &lBusy; - while (::InterlockedExchange(plBusy, 1) != 0) - { - Sleep(0); - } - if (idThreadOwner == ::GetCurrentThreadId()) - { - if (--ulRefCount == 0) - { - // No owner from now - idThreadOwner = 0; - } - } - ::InterlockedExchange(plBusy, 0); -} +HWND childwnd; +HWND hwndL; +HWND hwndB; static LRESULT CALLBACK ParentWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - LRESULT Res = 0; - while ( !TryEnterCS() ) Sleep(0); - if (message == WM_COMMAND && LOWORD(wParam) == IDCANCEL) + if (uMsgCreate && message == uMsgCreate) + { + if (wParam) + { + childwnd = FindWindowEx((HWND) lParam, NULL, "#32770", NULL); + hwndL = GetDlgItem(childwnd, 1016); + hwndB = GetDlgItem(childwnd, 1027); + HWND hwndP = GetDlgItem(childwnd, 1004); + HWND hwndS = GetDlgItem(childwnd, 1006); + if (childwnd && hwndP && hwndS) + { + if (IsWindowVisible(hwndL)) + ShowWindow(hwndL, SW_HIDE); + else + hwndL = NULL; + if (IsWindowVisible(hwndB)) + ShowWindow(hwndB, SW_HIDE); + else + hwndB = NULL; + + RECT wndRect, ctlRect; + + GetClientRect(childwnd, &wndRect); + + GetWindowRect(hwndS, &ctlRect); + + HWND s = g_hwndStatic = CreateWindow( + "STATIC", + "", + WS_CHILD | WS_CLIPSIBLINGS | SS_CENTER, + 0, + wndRect.bottom / 2 - (ctlRect.bottom - ctlRect.top) / 2, + wndRect.right, + ctlRect.bottom - ctlRect.top, + childwnd, + NULL, + hModule, + NULL + ); + + DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS; + dwStyle |= GetWindowLong(hwndP, GWL_STYLE) & PBS_SMOOTH; + + GetWindowRect(hwndP, &ctlRect); + + HWND pb = g_hwndProgressBar = CreateWindow( + "msctls_progress32", + "", + dwStyle, + 0, + wndRect.bottom / 2 + (ctlRect.bottom - ctlRect.top) / 2, + wndRect.right, + ctlRect.bottom - ctlRect.top, + childwnd, + NULL, + hModule, + NULL + ); + + long c; + + c = SendMessage(hwndP, PBM_SETBARCOLOR, 0, 0); + SendMessage(hwndP, PBM_SETBARCOLOR, 0, c); + SendMessage(pb, PBM_SETBARCOLOR, 0, c); + + c = SendMessage(hwndP, PBM_SETBKCOLOR, 0, 0); + SendMessage(hwndP, PBM_SETBKCOLOR, 0, c); + SendMessage(pb, PBM_SETBKCOLOR, 0, c); + + // set font + long hFont = SendMessage((HWND) lParam, WM_GETFONT, 0, 0); + SendMessage(pb, WM_SETFONT, hFont, 0); + SendMessage(s, WM_SETFONT, hFont, 0); + + ShowWindow(pb, SW_SHOWNA); + ShowWindow(s, SW_SHOWNA); + } + else + childwnd = NULL; + } + else if (childwnd) + { + if (g_hwndStatic) + { + DestroyWindow(g_hwndStatic); + g_hwndStatic = NULL; + } + if (g_hwndProgressBar) + { + DestroyWindow(g_hwndProgressBar); + g_hwndProgressBar = NULL; + } + if (hwndB) + { + ShowWindow(hwndB, SW_SHOWNA); + hwndB = NULL; + } + if (hwndL) + { + ShowWindow(hwndL, SW_SHOWNA); + hwndL = NULL; + } + + childwnd = NULL; + } + } + else if (message == WM_COMMAND && LOWORD(wParam) == IDCANCEL) + { g_cancelled = 1; + } else - Res = CallWindowProc((long (__stdcall *)(struct HWND__ *,unsigned int,unsigned int,long))lpWndProcOld,hwnd,message,wParam,lParam); - LeaveCS(); - return Res; + { + return CallWindowProc( + (WNDPROC) lpWndProcOld, + hwnd, + message, + wParam, + lParam + ); + } + return 0; } -BOOL APIENTRY DllMain( HANDLE _hModule, - DWORD ul_reason_for_call, - LPVOID lpReserved - ) +BOOL APIENTRY DllMain(HINSTANCE _hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { hModule = _hModule; return TRUE; } - static int g_file_size; static DWORD g_dwLastTick = 0; -void progress_callback(HWND dlg, char *msg, int read_bytes) +void progress_callback(char *msg, int read_bytes) { // flicker reduction by A. Schiffler DWORD dwLastTick = g_dwLastTick; DWORD dwThisTick = GetTickCount(); - if (dlg) + if (childwnd) { if (dwThisTick - dwLastTick > 500) { - SetDlgItemText (dlg, IDC_STATIC2, msg); + SetWindowText(g_hwndStatic, msg); dwLastTick = dwThisTick; } - if (g_file_size) SendMessage(g_hwndProgressBar, PBM_SETPOS, (WPARAM)MulDiv(read_bytes,30000,g_file_size), 0); + if (g_file_size) + SendMessage(g_hwndProgressBar, PBM_SETPOS, (WPARAM) MulDiv(read_bytes, 30000, g_file_size), 0); g_dwLastTick = dwLastTick; } } @@ -161,13 +211,7 @@ __declspec(dllexport) void download (HWND parent, char buf[1024]; char url[1024]; char filename[1024]; - HWND hwndAux; - HWND hwndL=0; - HWND hwndB=0; - HWND dlg=0; - HWND childwnd=0; BOOL bSuccess=FALSE; - RECT r, cr, orig_childRc; int timeout_ms=30000; char *error=NULL; @@ -226,88 +270,19 @@ __declspec(dllexport) void download (HWND parent, if (parent) { - childwnd=FindWindowEx(parent,NULL,"#32770",NULL); - hwndL=GetDlgItem(childwnd,1016); - hwndB=GetDlgItem(childwnd,1027); - if ( IsWindowVisible(hwndL) ) ShowWindow(hwndL,SW_HIDE); - else hwndL=NULL; - if (IsWindowVisible(hwndB)) ShowWindow(hwndB,SW_HIDE); - else hwndB=NULL; + uMsgCreate = RegisterWindowMessage("nsisdl create"); lpWndProcOld = (void *)SetWindowLong(parent,GWL_WNDPROC,(long)ParentWndProc); - dlg = CreateDialog((HINSTANCE)hModule, - MAKEINTRESOURCE(IDD_DIALOG1), - parent, - DownloadDialogProc); - if (dlg) - { - int pbid = IDC_PROGRESS1; - HWND hwPb = GetDlgItem(childwnd, 1004); + SendMessage(parent, uMsgCreate, TRUE, (LPARAM) parent); - // Set progress bar style - if (GetWindowLong(hwPb, GWL_STYLE) & PBS_SMOOTH) - pbid = IDC_PROGRESS2; - - HWND pb = g_hwndProgressBar = GetDlgItem(dlg, pbid); - - if (hwPb) - { - long c; - - c = SendMessage(hwPb, PBM_SETBARCOLOR, 0, 0); - SendMessage(hwPb, PBM_SETBARCOLOR, 0, c); - SendMessage(pb, PBM_SETBARCOLOR, 0, c); - - c = SendMessage(hwPb, PBM_SETBKCOLOR, 0, 0); - SendMessage(hwPb, PBM_SETBKCOLOR, 0, c); - SendMessage(pb, PBM_SETBKCOLOR, 0, c); - } - - ShowWindow(pb, SW_SHOWNA); - - GetWindowRect(childwnd,&orig_childRc); - GetWindowRect(dlg,&cr); - ScreenToClient(dlg,(LPPOINT)&cr); - ScreenToClient(dlg,((LPPOINT)&cr)+1); - - hwndAux = GetDlgItem(childwnd,1016); - GetWindowRect(hwndAux,&r); - ScreenToClient(childwnd,(LPPOINT)&r); - ScreenToClient(childwnd,((LPPOINT)&r)+1); - SetWindowPos(childwnd,0,0,0,r.right-r.left,r.top,SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOMOVE); - - GetWindowRect(hwndAux,&r); - ScreenToClient(parent,(LPPOINT)&r); - ScreenToClient(parent,((LPPOINT)&r)+1); - SetWindowPos(dlg,0,r.left,r.top,r.right-r.left,cr.bottom-cr.top,SWP_NOACTIVATE|SWP_NOZORDER); - - hwndAux = GetDlgItem(dlg,IDC_STATIC2); - GetWindowRect(hwndAux,&cr); - ScreenToClient(dlg,(LPPOINT)&cr); - ScreenToClient(dlg,((LPPOINT)&cr)+1); - SetWindowPos(hwndAux,0,0,0,r.right-r.left,cr.bottom-cr.top,SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER); - - hwndAux = GetDlgItem(dlg,pbid); - GetWindowRect(hwndAux,&cr); - ScreenToClient(dlg,(LPPOINT)&cr); - ScreenToClient(dlg,((LPPOINT)&cr)+1); - SetWindowPos(hwndAux,0,0,0,r.right-r.left,cr.bottom-cr.top,SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER); - - char *p=filename; - while (*p) p++; - while (*p != '\\' && p != filename) p=CharPrev(filename,p); - wsprintf(buf,szDownloading, p!=filename?p+1:p); - SetDlgItemText(childwnd,1006,buf); - SetDlgItemText(dlg, IDC_STATIC2, szConnecting); - - // set font - long hFont = SendMessage(parent, WM_GETFONT, 0, 0); - SendDlgItemMessage(dlg, pbid, WM_SETFONT, hFont, 0); - SendDlgItemMessage(dlg, IDC_STATIC2, WM_SETFONT, hFont, 0); - - ShowWindow(dlg, SW_SHOWNA); - } + // set initial text + char *p = filename; + while (*p) p++; + while (*p != '\\' && p != filename) p = CharPrev(filename, p); + wsprintf(buf, szDownloading, p != filename ? p + 1 : p); + SetDlgItemText(childwnd, 1006, buf); + SetWindowText(g_hwndStatic, szConnecting); // enable the cancel button hwndPrevFocus = GetFocus(); @@ -365,44 +340,15 @@ __declspec(dllexport) void download (HWND parent, get->connect (url); while (1) { - do - { - if ( dlg ) - { - MSG msg; - while (PeekMessage(&msg,dlg,0,0,PM_REMOVE)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - } - while (!TryEnterCS()); // Process messages - if (g_cancelled || error) - { - if (dlg) - DestroyWindow(dlg); - dlg = NULL; - if (!error) + if (g_cancelled) error = "cancel"; - } - LeaveCS(); if (error) { if (parent) { - SetWindowLong(parent,GWL_WNDPROC,(long)lpWndProcOld); - - if (hwndB) ShowWindow(hwndB,SW_SHOWNA); - if (hwndL) ShowWindow(hwndL,SW_SHOWNA); - - SetWindowPos( - childwnd,0,0,0, - orig_childRc.right-orig_childRc.left, - orig_childRc.bottom-orig_childRc.top, - SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOMOVE - ); + SendMessage(parent, uMsgCreate, FALSE, (LPARAM) parent); + SetWindowLong(parent, GWL_WNDPROC, (long)lpWndProcOld); // Prevent wierd stuff happening if the cancel button happens to be // pressed at the moment we are finishing @@ -439,7 +385,7 @@ __declspec(dllexport) void download (HWND parent, } else if (get->get_status () == 1) { - progress_callback(dlg, "Reading headers", 0); + progress_callback("Reading headers", 0); if (last_recv_time+timeout_ms < GetTickCount()) error = "Timed out on getting headers."; @@ -452,9 +398,9 @@ __declspec(dllexport) void download (HWND parent, cl = get->content_length (); if (cl == 0) error = "Server did not specify content length."; - else if (dlg) { - SendMessage(g_hwndProgressBar, PBM_SETRANGE, 0, MAKELPARAM(0,30000)); - g_file_size=cl; + else if (g_hwndProgressBar) { + SendMessage(g_hwndProgressBar, PBM_SETRANGE, 0, MAKELPARAM(0, 30000)); + g_file_size = cl; } } @@ -493,7 +439,7 @@ __declspec(dllexport) void download (HWND parent, rtext, remain==1?"":szPlural ); - progress_callback(dlg, buf, sofar); + progress_callback(buf, sofar); } else { if (sofar < cl) error = "Server aborted."; diff --git a/Contrib/NSISdl/nsisdl.dsp b/Contrib/NSISdl/nsisdl.dsp index 870909a0..200b3bfe 100644 --- a/Contrib/NSISdl/nsisdl.dsp +++ b/Contrib/NSISdl/nsisdl.dsp @@ -137,20 +137,12 @@ SOURCE=.\netinc.h # End Source File # Begin Source File -SOURCE=.\resource.h -# End Source File -# Begin Source File - SOURCE=.\util.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# Begin Source File - -SOURCE=.\Script1.rc -# End Source File # End Group # End Target # End Project diff --git a/Plugins/nsisdl.dll b/Plugins/nsisdl.dll index 360fd8f07eb7037ccc2cadd3bbca4d4fc8d604d4..bc3fb17d08b799c5ad734785c383e255dfd180d2 100644 GIT binary patch delta 5823 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 C`cg^& delta 6724 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 Z66-8_OQOYOnQ6(Cm&}{-s>kvs_kX