home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 March / CMCD0304.ISO / Software / Freeware / Programare / nullsoft / nsis20.exe / Source / exehead / Ui.c < prev    next >
C/C++ Source or Header  |  2004-02-06  |  47KB  |  1,663 lines

  1. /*
  2. *  Copyright (C) 1999-2004 Nullsoft, Inc.
  3. *  Portions Copyright (C) 2002 Jeff Doozan
  4. *
  5. *  This software is provided 'as-is', without any express or implied warranty.
  6. *  In no event will the authors be held liable for any damages arising from the
  7. *  use of this software.
  8. *
  9. *  Permission is granted to anyone to use this software for any purpose, including
  10. *  commercial applications, and to alter it and redistribute it freely, subject to
  11. *  the following restrictions:
  12. *
  13. *  1. The origin of this software must not be misrepresented; you must not claim that
  14. *  you wrote the original software. If you use this software in a product, an
  15. *  acknowledgment in the product documentation would be appreciated but is not required.
  16. *
  17. *  2. Altered source versions must be plainly marked as such, and must not be
  18. *  misrepresented as being the original software.
  19. *
  20. *  3. This notice may not be removed or altered from any source distribution.
  21. */
  22.  
  23. #include "../Platform.h"
  24. #include <windowsx.h>
  25. #include <shlobj.h>
  26. #include <shellapi.h>
  27.  
  28. #include "resource.h"
  29.  
  30. #include "fileform.h"
  31. #include "state.h"
  32. #include "util.h"
  33. #include "ui.h"
  34. #include "exec.h"
  35. #include "lang.h"
  36.  
  37. #ifdef NSIS_CONFIG_VISIBLE_SUPPORT
  38. HICON g_hIcon;
  39. #endif
  40.  
  41. int dlg_offset;
  42. int ui_dlg_visible=0; // At start main window is not visible
  43. int g_quit_flag; // set when Quit has been called (meaning bail out ASAP)
  44.  
  45. #if NSIS_MAX_INST_TYPES > 32 || NSIS_MAX_INST_TYPES < 1
  46. #error invalid value for NSIS_MAX_INST_TYPES
  47. #endif
  48.  
  49. int progress_bar_pos, progress_bar_len;
  50.  
  51. static char g_tmp[4096];
  52.  
  53. static int m_page=-1,m_retcode,m_delta=1;
  54. static page *g_this_page;
  55.  
  56. #define NOTIFY_BYE_BYE 'x'
  57.  
  58. static void NSISCALL outernotify(char num) {
  59.   if (num==NOTIFY_BYE_BYE)
  60.     g_quit_flag++;
  61.   m_delta=num;
  62.   SendMessage(g_hwnd,WM_NOTIFY_OUTER_NEXT,(WPARAM)num,0); // it sends num again for plugins - DON'T REMOVE!
  63. }
  64.  
  65. #ifdef NSIS_CONFIG_VISIBLE_SUPPORT
  66. BOOL CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  67. static int CALLBACK WINAPI BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData);
  68. #ifdef NSIS_CONFIG_LICENSEPAGE
  69. static BOOL CALLBACK LicenseProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  70. #endif
  71. static BOOL CALLBACK DirProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  72. static BOOL CALLBACK SelProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  73. static BOOL CALLBACK InstProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  74. static BOOL CALLBACK UninstProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  75. #endif//NSIS_CONFIG_VISIBLE_SUPPORT
  76.  
  77. static DWORD WINAPI install_thread(LPVOID p);
  78.  
  79. void NSISCALL CleanUp();
  80.  
  81. HWND insthwnd, insthwnd2, insthwndbutton;
  82.  
  83. HWND m_curwnd;
  84. static HWND m_bgwnd, m_hwndOK, m_hwndCancel;
  85.  
  86. static BOOL NSISCALL SetDlgItemTextFromLang_(HWND dlg, int id, int lid) {
  87.   return my_SetDialogItemText(dlg,id+1000,GetNSISStringTT(lid));
  88. }
  89.  
  90. static void NSISCALL SetNextDef()
  91. {
  92.   SendMessage(g_exec_flags.abort ? m_hwndCancel : m_hwndOK, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE);
  93. }
  94.  
  95. static void NSISCALL EnableNext(BOOL e)
  96. {
  97.   EnableWindow(m_hwndOK, e);
  98. }
  99.  
  100. static void NSISCALL SetActiveCtl(HWND hDlg, HWND hCtl)
  101. {
  102.   SendMessage(hDlg, WM_NEXTDLGCTL, (WPARAM) hCtl, TRUE);
  103. }
  104.  
  105. static void NSISCALL NotifyCurWnd(UINT uNotifyCode)
  106. {
  107.   if (m_curwnd)
  108.     SendMessage(m_curwnd, uNotifyCode, 0, 0);
  109. }
  110.  
  111. #define SetDlgItemTextFromLang(dlg,id,lid) SetDlgItemTextFromLang_(dlg,(id)-1000,lid)
  112.  
  113. #define SetUITextFromLang(it,la) SetDlgItemTextFromLang_(hwndDlg,(it)-1000,la)
  114. #define SetUITextNT(it,text) my_SetDialogItemText(hwndDlg,it,text)
  115. #define GetUIText(it,s) my_GetDialogItemText(it,s)
  116. #define GetUIItem(it) GetDlgItem(hwndDlg,it)
  117.  
  118. #ifdef NSIS_CONFIG_ENHANCEDUI_SUPPORT
  119. #define HandleStaticBkColor() _HandleStaticBkColor(uMsg, wParam, lParam)
  120. static BOOL NSISCALL _HandleStaticBkColor(UINT uMsg, WPARAM wParam, LPARAM lParam)
  121. {
  122.   if ((uMsg - WM_CTLCOLOREDIT) <= (WM_CTLCOLORSTATIC - WM_CTLCOLOREDIT))
  123.   {
  124.     ctlcolors *c = (ctlcolors *)GetWindowLong((HWND)lParam, GWL_USERDATA);
  125.  
  126.     if (c) {
  127.       COLORREF text;
  128.       LOGBRUSH lh;
  129.  
  130.       text = c->text;
  131.       if (c->flags & CC_TEXT_SYS)
  132.         text = GetSysColor(text);
  133.       if (c->flags & CC_TEXT)
  134.         SetTextColor((HDC)wParam, text);
  135.  
  136.       SetBkMode((HDC)wParam, c->bkmode);
  137.  
  138.       lh.lbColor = c->bkc;
  139.       if (c->flags & CC_BK_SYS)
  140.         lh.lbColor = GetSysColor(lh.lbColor);
  141.       if (c->flags & CC_BK)
  142.         SetBkColor((HDC)wParam, lh.lbColor);
  143.  
  144.       if (c->flags & CC_BKB)
  145.       {
  146.         lh.lbStyle = c->lbStyle;
  147.         if (c->bkb)
  148.           DeleteObject(c->bkb);
  149.         c->bkb = CreateBrushIndirect(&lh);
  150.       }
  151.  
  152.       return (BOOL)c->bkb;
  153.     }
  154.   }
  155.   return 0;
  156. }
  157. #else
  158. #define HandleStaticBkColor() 0
  159. #endif//!NSIS_CONFIG_ENHANCEDUI_SUPPORT
  160.  
  161. #ifdef NSIS_CONFIG_LOG
  162. #ifndef NSIS_CONFIG_LOG_ODS
  163. void NSISCALL build_g_logfile()
  164. {
  165.   lstrcat(addtrailingslash(mystrcpy(g_log_file,state_install_directory)),"install.log");
  166. }
  167. #endif
  168. #endif
  169.  
  170. int *cur_langtable;
  171.  
  172. static void NSISCALL set_language()
  173. {
  174.   LANGID lang_mask=(LANGID)~0;
  175.   LANGID lang=state_language[0]?myatoi(state_language):GetUserDefaultLangID();
  176.   char *language_table=0;
  177.   int lang_num;
  178.  
  179. lang_again:
  180.   lang_num=g_blocks[NB_LANGTABLES].num;
  181.   while (lang_num--) {
  182.     language_table=((char*)g_blocks[NB_LANGTABLES].offset)+lang_num*g_header->langtable_size;
  183.     if (!((lang ^ *(LANGID*)language_table) & lang_mask)) {
  184.       dlg_offset=*(int*)(language_table+sizeof(LANGID));
  185.       g_exec_flags.rtl=*(int*)(language_table+sizeof(LANGID)+sizeof(int));
  186.       cur_langtable=(int*)(language_table+sizeof(LANGID)+2*sizeof(int));
  187.       break;
  188.     }
  189.   }
  190.   if (!cur_langtable) {
  191.     if (lang_mask == (LANGID)~0)
  192.       lang_mask=0x3ff; // primary lang
  193.     else // we already tried once and we still don't have a language table
  194.       lang_mask=0; // first lang
  195.     goto lang_again;
  196.   }
  197.  
  198.   myitoa(state_language, *(LANGID*)language_table);
  199.   {
  200.     char *caption = GetNSISString(g_caption,LANG_CAPTION);
  201. #ifdef NSIS_SUPPORT_BGBG
  202.     my_SetWindowText(m_bgwnd, caption);
  203. #endif
  204.   }
  205. }
  206.  
  207. __forceinline int NSISCALL ui_doinstall(void)
  208. {
  209.   header *header = g_header;
  210.   static WNDCLASS wc; // richedit subclassing and bgbg creation
  211.   g_exec_flags.autoclose=g_flags&CH_FLAGS_AUTO_CLOSE;
  212.  
  213.   set_language();
  214.  
  215.   if (!is_valid_instpath(state_install_directory))
  216.   {
  217.     if (header->install_reg_key_ptr)
  218.     {
  219.       myRegGetStr(
  220.         (HKEY)header->install_reg_rootkey,
  221.         GetNSISStringNP(header->install_reg_key_ptr),
  222.         GetNSISStringNP(header->install_reg_value_ptr),
  223.         ps_tmpbuf
  224.       );
  225.       if (ps_tmpbuf[0])
  226.       {
  227.         char *p=ps_tmpbuf;
  228.         char *e;
  229.         if (p[0]=='\"')
  230.         {
  231.           char *p2=CharNext(p);
  232.           p=p2;
  233.           p2 = findchar(p2, '"');
  234.           *p2=0;
  235.         }
  236.         // p is the path now, check for .exe extension
  237.  
  238.         e=p+mystrlen(p)-4;
  239.         if (e > p)
  240.         {
  241.           // if filename ends in .exe, and is not a directory, remove the filename
  242.           if (!lstrcmpi(e, ".exe")) // check extension
  243.           {
  244.             DWORD d;
  245.             d=GetFileAttributes(p);
  246.             if (d == INVALID_FILE_ATTRIBUTES || !(d&FILE_ATTRIBUTE_DIRECTORY))
  247.             {
  248.               // if there is no back-slash, the string will become empty, but that's ok because
  249.               // it would make an invalid instdir anyway
  250.               trimslashtoend(p);
  251.             }
  252.           }
  253.         }
  254.  
  255.         mystrcpy(state_install_directory,p);
  256.       }
  257.     }
  258.   }
  259.   if (!is_valid_instpath(state_install_directory))
  260.   {
  261.     GetNSISString(state_install_directory,header->install_directory_ptr);
  262.   }
  263.  
  264. #ifdef NSIS_CONFIG_LOG
  265.   if (g_flags & CH_FLAGS_SILENT_LOG && !g_is_uninstaller)
  266.   {
  267. #ifndef NSIS_CONFIG_LOG_ODS
  268.     build_g_logfile();
  269. #endif
  270.     log_dolog=1;
  271.   }
  272. #endif
  273.  
  274. #ifdef NSIS_CONFIG_VISIBLE_SUPPORT
  275.   g_hIcon=LoadImage(g_hInstance,MAKEINTRESOURCE(IDI_ICON2),IMAGE_ICON,0,0,LR_DEFAULTSIZE|LR_SHARED);
  276. #ifdef NSIS_SUPPORT_BGBG
  277.   if (header->bg_color1 != -1)
  278.   {
  279.     RECT vp;
  280.     extern LRESULT CALLBACK BG_WndProc(HWND, UINT, WPARAM, LPARAM);
  281.     wc.lpfnWndProc = BG_WndProc;
  282.     wc.hInstance = g_hInstance;
  283.     wc.hIcon = g_hIcon;
  284.     //wc.hCursor = LoadCursor(NULL,IDC_ARROW);
  285.     wc.lpszClassName = "_Nb";
  286.  
  287.     if (!RegisterClass(&wc)) return 0;
  288.  
  289.     SystemParametersInfo(SPI_GETWORKAREA, 0, &vp, 0);
  290.  
  291.     m_bgwnd = CreateWindowEx(WS_EX_TOOLWINDOW,"_Nb",0,WS_POPUP,
  292.       vp.left,vp.top,vp.right-vp.left,vp.bottom-vp.top,0,NULL,g_hInstance,NULL);
  293.   }
  294.  
  295. #ifdef NSIS_SUPPORT_CODECALLBACKS
  296.   g_hwnd=m_bgwnd;
  297. #endif//NSIS_SUPPORT_CODECALLBACKS
  298.  
  299. #endif//NSIS_SUPPORT_BGBG
  300.  
  301. #endif//NSIS_CONFIG_VISIBLE_SUPPORT
  302.  
  303. #ifdef NSIS_SUPPORT_CODECALLBACKS
  304.   // Select language
  305.   if (ExecuteCodeSegment(header->code_onInit,NULL)) return 1;
  306.   set_language();
  307. #endif
  308.  
  309. #ifdef NSIS_CONFIG_VISIBLE_SUPPORT
  310.  
  311. #ifdef NSIS_SUPPORT_CODECALLBACKS
  312. #ifdef NSIS_SUPPORT_BGBG
  313.   g_hwnd=NULL;
  314. #endif//NSIS_SUPPORT_BGBG
  315. #endif//NSIS_SUPPORT_CODECALLBACKS
  316.  
  317. #ifdef NSIS_CONFIG_SILENT_SUPPORT
  318.   if (!g_exec_flags.silent)
  319. #endif//NSIS_CONFIG_SILENT_SUPPORT
  320.   {
  321. #ifdef NSIS_SUPPORT_BGBG
  322.     ShowWindow(m_bgwnd, SW_SHOW);
  323. #endif//NSIS_SUPPORT_BGBG
  324.  
  325. #ifdef NSIS_CONFIG_LICENSEPAGE
  326.     { // load richedit DLL
  327.       static char str1[]="RichEd20.dll";
  328.       static char str2[]="RichEdit20A";
  329.       if (!LoadLibrary(str1))
  330.       {
  331.         *(WORD*)(str1+6) = CHAR2_TO_WORD('3','2');
  332.         LoadLibrary(str1);
  333.       }
  334.  
  335.       // make richedit20a point to RICHEDIT
  336.       if (!GetClassInfo(NULL,str2,&wc))
  337.       {
  338.         str2[8]=0;
  339.         GetClassInfo(NULL,str2,&wc);
  340.         wc.lpszClassName = str2;
  341.         str2[8]='2';
  342.         RegisterClass(&wc);
  343.       }
  344.     }
  345. #endif
  346.  
  347.     {
  348.       int ret=DialogBox(g_hInstance,MAKEINTRESOURCE(IDD_INST+dlg_offset),0,DialogProc);
  349. #if defined(NSIS_SUPPORT_CODECALLBACKS) && defined(NSIS_CONFIG_ENHANCEDUI_SUPPORT)
  350.       ExecuteCodeSegment(header->code_onGUIEnd,NULL);
  351. #endif
  352.       return ret;
  353.     }
  354.   }
  355. #endif//NSIS_CONFIG_VISIBLE_SUPPORT
  356. #ifdef NSIS_CONFIG_SILENT_SUPPORT
  357. #ifdef NSIS_CONFIG_VISIBLE_SUPPORT
  358.   else
  359. #endif//NSIS_CONFIG_VISIBLE_SUPPORT
  360.   {
  361.     if (install_thread(NULL))
  362.     {
  363. #ifdef NSIS_SUPPORT_CODECALLBACKS
  364.       if (!g_quit_flag) ExecuteCodeSegment(header->code_onInstFailed,NULL);
  365. #endif//NSIS_SUPPORT_CODECALLBACKS
  366.       return 1;
  367.     }
  368. #ifdef NSIS_SUPPORT_CODECALLBACKS
  369.     ExecuteCodeSegment(header->code_onInstSuccess,NULL);
  370. #endif//NSIS_SUPPORT_CODECALLBACKS
  371.  
  372.     return 0;
  373.   }
  374. #endif//NSIS_CONFIG_SILENT_SUPPORT
  375. }
  376.  
  377.  
  378. #ifdef NSIS_CONFIG_VISIBLE_SUPPORT
  379. static int CALLBACK WINAPI BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
  380. {
  381.   if (uMsg==BFFM_INITIALIZED)
  382.   {
  383.     my_GetDialogItemText(IDC_DIR,(char*)lpData);
  384.     SendMessage(hwnd,BFFM_SETSELECTION,(WPARAM)1,lpData);
  385.   }
  386.   if (uMsg==BFFM_SELCHANGED)
  387.   {
  388.     SendMessage(
  389.       hwnd,
  390.       BFFM_ENABLEOK,
  391.       0,
  392.       SHGetPathFromIDList((LPITEMIDLIST)lParam,(char*)lpData)
  393. #ifdef NSIS_SUPPORT_CODECALLBACKS
  394.       && !ExecuteCodeSegment(g_header->code_onVerifyInstDir,NULL)
  395. #endif
  396.     );
  397.   }
  398.   return 0;
  399. }
  400.  
  401. BOOL CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  402. {
  403.   if (uMsg == WM_INITDIALOG || uMsg == WM_NOTIFY_OUTER_NEXT)
  404.   {
  405.     page *this_page;
  406.     static DLGPROC winprocs[]=
  407.     {
  408. #ifdef NSIS_CONFIG_LICENSEPAGE
  409.       LicenseProc,
  410. #endif
  411. #ifdef NSIS_CONFIG_COMPONENTPAGE
  412.       SelProc,
  413. #endif
  414.       DirProc,
  415.       InstProc,
  416. #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
  417.       UninstProc
  418. #endif
  419.     };
  420.  
  421.     if (uMsg == WM_INITDIALOG)
  422.     {
  423.       g_hwnd=hwndDlg;
  424.       m_hwndOK=GetDlgItem(hwndDlg,IDOK);
  425.       m_hwndCancel=GetDlgItem(hwndDlg,IDCANCEL);
  426.       SetDlgItemTextFromLang(hwndDlg,IDC_VERSTR,LANG_BRANDING);
  427.       SetClassLong(hwndDlg,GCL_HICON,(long)g_hIcon);
  428. #if defined(NSIS_SUPPORT_CODECALLBACKS) && defined(NSIS_CONFIG_ENHANCEDUI_SUPPORT)
  429.       g_quit_flag = ExecuteCodeSegment(g_header->code_onGUIInit,NULL);
  430. #endif
  431.         //ShowWindow(hwndDlg, SW_SHOW);
  432.     }
  433.  
  434.     this_page=g_pages+m_page;
  435.  
  436.     if (m_page>=0) {
  437. #ifdef NSIS_SUPPORT_CODECALLBACKS
  438.       // Call leave function. If Abort used don't move to the next page.
  439.       // But if quit called we must exit now
  440.       if (m_delta==1) if (ExecuteCodeSegment(this_page->leavefunc,NULL)) return !g_quit_flag;
  441. #endif
  442.  
  443.       // if the last page was a custom page, wait for it to finish by itself.
  444.       // if it doesn't, it's a BAD plugin.
  445.       // plugins should react to WM_NOTIFY_OUTER_NEXT.
  446.       if (!this_page->dlg_id) return 0;
  447.     }
  448.  
  449.     NotifyCurWnd(WM_NOTIFY_INIGO_MONTOYA);
  450.  
  451. nextPage:
  452.     m_page+=m_delta;
  453.     this_page+=m_delta;
  454.  
  455. #ifdef NSIS_SUPPORT_CODECALLBACKS
  456.     if (m_page==g_blocks[NB_PAGES].num) ExecuteCodeSegment(g_header->code_onInstSuccess,NULL);
  457. #endif//NSIS_SUPPORT_CODECALLBACKS
  458.  
  459.     if (g_quit_flag || (unsigned int)m_page >= (unsigned int)g_blocks[NB_PAGES].num)
  460.     {
  461.       DestroyWindow(m_curwnd);
  462.       g_hwnd = 0;
  463.       EndDialog(hwndDlg,m_retcode);
  464.     }
  465.     else
  466.     {
  467.       HWND hwndtmp;
  468.  
  469.       int pflags = this_page->flags;
  470.  
  471.       GetNSISString(state_click_next, this_page->clicknext);
  472.       SetDlgItemTextFromLang(hwndDlg, IDOK, this_page->next);
  473.       SetDlgItemTextFromLang(hwndDlg, IDC_BACK, this_page->back);
  474.       SetDlgItemTextFromLang(hwndDlg, IDCANCEL, this_page->cancel);
  475.  
  476.       hwndtmp = GetDlgItem(hwndDlg, IDC_BACK);
  477.  
  478.       if (g_exec_flags.abort)
  479.       {
  480.         pflags &= ~(PF_BACK_ENABLE | PF_NEXT_ENABLE);
  481.         pflags |= PF_CANCEL_ENABLE;
  482.       }
  483.  
  484.       ShowWindow(hwndtmp, pflags & PF_BACK_SHOW);// SW_HIDE = 0, PF_BACK_SHOW = SW_SHOWNA = 8
  485.       EnableWindow(hwndtmp, pflags & PF_BACK_ENABLE);
  486.       EnableNext(pflags & PF_NEXT_ENABLE);
  487.       EnableWindow(m_hwndCancel, pflags & PF_CANCEL_ENABLE);
  488.  
  489.       SendMessage(hwndtmp, BM_SETSTYLE, BS_PUSHBUTTON, TRUE);
  490.  
  491.       if (g_exec_flags.abort)
  492.       {
  493.         SendMessage(hwndDlg, DM_SETDEFID, IDCANCEL, 0);
  494.         SetActiveCtl(hwndDlg, m_hwndCancel);
  495.       }
  496.       else
  497.       {
  498.         SetActiveCtl(hwndDlg, m_hwndOK);
  499.       }
  500.  
  501.       mystrcpy(g_tmp,g_caption);
  502.       GetNSISString(g_tmp+mystrlen(g_tmp),this_page->caption);
  503.       my_SetWindowText(hwndDlg,g_tmp);
  504.  
  505. #ifdef NSIS_SUPPORT_CODECALLBACKS
  506.       // custom page or user used abort in prefunc
  507.       if (ExecuteCodeSegment(this_page->prefunc, NULL) || !this_page->dlg_id) {
  508.         goto nextPage;
  509.       }
  510. #endif //NSIS_SUPPORT_CODECALLBACKS
  511.  
  512.       if (this_page->wndproc_id != PWP_COMPLETED)
  513.       {
  514.         DestroyWindow(m_curwnd);
  515.       }
  516.       else {
  517.         if (!g_exec_flags.abort && g_exec_flags.autoclose)
  518.           goto nextPage;
  519.         // no need to go to skipPage because PWP_COMPLETED always follows PWP_INSTFILES
  520.         return FALSE;
  521.       }
  522.  
  523.       // update g_this_page for the dialog proc
  524.       g_this_page=this_page;
  525.  
  526.       if (this_page->dlg_id > 0) // NSIS page
  527.       {
  528.         m_curwnd=CreateDialogParam(
  529.           g_hInstance,
  530.           MAKEINTRESOURCE(this_page->dlg_id+dlg_offset),
  531.           hwndDlg,winprocs[this_page->wndproc_id],(LPARAM)this_page
  532.         );
  533.         if (m_curwnd)
  534.         {
  535.           RECT r;
  536.  
  537.           SetDlgItemTextFromLang(m_curwnd,IDC_INTROTEXT,this_page->parms[0]);
  538.  
  539.           GetWindowRect(GetDlgItem(hwndDlg,IDC_CHILDRECT),&r);
  540.           ScreenToClient(hwndDlg,(LPPOINT)&r);
  541.           SetWindowPos(m_curwnd,0,r.left,r.top,0,0,SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOZORDER);
  542. #ifdef NSIS_SUPPORT_CODECALLBACKS
  543.           ExecuteCodeSegment(this_page->showfunc,NULL);
  544. #endif //NSIS_SUPPORT_CODECALLBACKS
  545.           ShowWindow(m_curwnd,SW_SHOWNA);
  546.           NotifyCurWnd(WM_NOTIFY_START);
  547.         }
  548.       }
  549.     }
  550.  
  551. skipPage:
  552.  
  553.     if (!ui_dlg_visible && m_curwnd)
  554.     {
  555.       ShowWindow(hwndDlg, SW_SHOWDEFAULT);
  556.       ui_dlg_visible = 1;
  557.     }
  558.  
  559.     return FALSE;
  560.   }
  561.  
  562. #ifdef NSIS_SUPPORT_BGBG
  563.   if (uMsg == WM_WINDOWPOSCHANGED)
  564.   {
  565.     SetWindowPos(m_bgwnd, hwndDlg, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
  566.   }
  567.   if (uMsg == WM_SIZE) {
  568.     ShowWindow(m_bgwnd, wParam == SIZE_MINIMIZED ? SW_HIDE : SW_SHOW);
  569.   }
  570. #endif //NSIS_SUPPORT_BGBG
  571.  
  572.   if (uMsg == WM_NOTIFY_CUSTOM_READY) {
  573.     DestroyWindow(m_curwnd);
  574.     m_curwnd = (HWND)wParam;
  575.     goto skipPage;
  576.   }
  577.   if (uMsg == WM_CLOSE && m_page == g_blocks[NB_PAGES].num - 1)
  578.   {
  579.     if (!IsWindowEnabled(m_hwndCancel))
  580.     {
  581.       uMsg = WM_COMMAND;
  582.       wParam = IDOK;
  583.     }
  584.   }
  585.   if (uMsg == WM_COMMAND)
  586.   {
  587.     int id = LOWORD(wParam);
  588.     HWND hCtl = GetDlgItem(hwndDlg, id);
  589.     if (hCtl)
  590.     {
  591.       SendMessage(hCtl, BM_SETSTATE, FALSE, 0);
  592.       if (!IsWindowEnabled(hCtl))
  593.         return 0;
  594.     }
  595.  
  596.     if (id == IDOK)
  597.     {
  598.       outernotify(1);
  599.     }
  600.     if (id == IDC_BACK && m_page>0)
  601.     {
  602.       outernotify(-1);
  603.     }
  604.     if (id == IDCANCEL)
  605.     {
  606.       if (g_exec_flags.abort)
  607.       {
  608. #ifdef NSIS_SUPPORT_CODECALLBACKS
  609.         ExecuteCodeSegment(g_header->code_onInstFailed,NULL);
  610. #endif//NSIS_SUPPORT_CODECALLBACKS
  611.         m_retcode=2;
  612.         outernotify(NOTIFY_BYE_BYE);
  613.       }
  614.       else
  615.       {
  616. #ifdef NSIS_SUPPORT_CODECALLBACKS
  617.         if (!ExecuteCodeSegment(g_header->code_onUserAbort,NULL))
  618. #endif//NSIS_SUPPORT_CODECALLBACKS
  619.         {
  620.           m_retcode=1;
  621.           outernotify(NOTIFY_BYE_BYE);
  622.         }
  623.       }
  624.     }
  625.     else
  626.     {
  627.       // Forward WM_COMMANDs to inner dialogs, can be custom ones.
  628.       // Without this, enter on buttons in inner dialogs won't work.
  629.       SendMessage(m_curwnd, WM_COMMAND, wParam, lParam);
  630.     }
  631.   }
  632.   if (uMsg == WM_ENDSESSION && wParam)
  633.   {
  634.     // the session can end any time after we process this message so we better clean up now
  635.     CleanUp();
  636.   }
  637.   return HandleStaticBkColor();
  638. }
  639.  
  640. #define this_page ((page*)lParam)
  641.  
  642. #ifdef NSIS_CONFIG_LICENSEPAGE
  643.  
  644. #define _RICHEDIT_VER 0x0200
  645. #include <RichEdit.h>
  646. #undef _RICHEDIT_VER
  647. static DWORD dwRead;
  648. DWORD CALLBACK StreamLicense(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
  649. {
  650.   lstrcpyn(pbBuff,(char*)dwCookie+dwRead,cb);
  651.   *pcb=mystrlen(pbBuff);
  652.   dwRead+=*pcb;
  653.   return 0;
  654. }
  655.  
  656. static BOOL CALLBACK LicenseProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  657. {
  658.   page *m_this_page=g_this_page;
  659.   HWND hwLicense;
  660.   static int ignoreWMCommand;
  661.  
  662.   if (uMsg == WM_INITDIALOG)
  663.   {
  664.     char *l = (char *)GetNSISStringNP(GetNSISTab(this_page->parms[1]));
  665.     int lt = *l;
  666.     EDITSTREAM es = {
  667.       (DWORD)(++l),
  668.       0,
  669.       StreamLicense
  670.     };
  671.  
  672.     int selected = (this_page->flags & PF_LICENSE_SELECTED) | !(this_page->flags & PF_LICENSE_FORCE_SELECTION);
  673.  
  674.     SetUITextFromLang(IDC_LICENSEAGREE,this_page->parms[2]);
  675.     SetUITextFromLang(IDC_LICENSEDISAGREE,this_page->parms[3]);
  676.     CheckDlgButton(hwndDlg,IDC_LICENSEAGREE+!selected,BST_CHECKED);
  677.     EnableNext(selected);
  678.  
  679.     hwLicense=GetUIItem(IDC_EDIT1);
  680.     SetActiveCtl(hwndDlg, hwLicense);
  681.     SendMessage(hwLicense,EM_AUTOURLDETECT,TRUE,0);
  682. #define lbg g_header->license_bg
  683.     SendMessage(hwLicense,EM_SETBKGNDCOLOR,0,lbg>=0?lbg:GetSysColor(-lbg));
  684. #undef lbg
  685.     SendMessage(hwLicense,EM_SETEVENTMASK,0,ENM_LINK|ENM_KEYEVENTS); //XGE 8th September 2002 Or'd in ENM_KEYEVENTS
  686.     dwRead=0;
  687.     SendMessage(hwLicense,EM_EXLIMITTEXT,0,mystrlen(l));
  688.     SendMessage(hwLicense,EM_STREAMIN,lt,(LPARAM)&es);
  689.     ignoreWMCommand = 0;
  690.     return FALSE;
  691.   }
  692.   if (uMsg == WM_COMMAND && HIWORD(wParam) == BN_CLICKED && !ignoreWMCommand) {
  693.     if (m_this_page->flags & PF_LICENSE_FORCE_SELECTION) {
  694.       int is = SendMessage(GetUIItem(IDC_LICENSEAGREE), BM_GETCHECK, 0, 0) & BST_CHECKED;
  695.       m_this_page->flags &= ~PF_LICENSE_SELECTED;
  696.       m_this_page->flags |= is;
  697.       EnableNext(is);
  698.       SetNextDef();
  699.     }
  700.   }
  701.   if (uMsg == WM_NOTIFY) {
  702.     hwLicense=GetUIItem(IDC_EDIT1);
  703.     #define nmhdr ((NMHDR *)lParam)
  704.     #define enlink ((ENLINK *)lParam)
  705.     #define msgfilter ((MSGFILTER *)lParam)
  706.     if (nmhdr->code==EN_LINK) {
  707.       if (enlink->msg==WM_LBUTTONDOWN) {
  708.         TEXTRANGE tr = {
  709.           enlink->chrg.cpMin,
  710.           enlink->chrg.cpMax,
  711.           ps_tmpbuf
  712.         };
  713.         if (tr.chrg.cpMax-tr.chrg.cpMin < sizeof(ps_tmpbuf)) {
  714.           SendMessage(hwLicense,EM_GETTEXTRANGE,0,(LPARAM)&tr);
  715.           SetCursor(LoadCursor(0,IDC_WAIT));
  716.           ShellExecute(hwndDlg,"open",tr.lpstrText,NULL,NULL,SW_SHOWNORMAL);
  717.           SetCursor(LoadCursor(0,IDC_ARROW));
  718.         }
  719.       }
  720.       if (enlink->msg==WM_SETCURSOR) {
  721.         SetCursor(LoadCursor(0,IDC_HAND));
  722.       }
  723.     }
  724.     //Ximon Eighteen 8th September 2002 Capture return key presses in the rich
  725.     //edit control now that the control gets the focus rather than the default
  726.     //push button. When the user presses return ask the outer dialog to move
  727.     //the installer onto the next page. MSDN docs say return non-zero if the
  728.     //rich edit control should NOT process this message, hence the return 1.
  729.     if (nmhdr->code==EN_MSGFILTER)
  730.     {
  731.       if (msgfilter->msg==WM_KEYDOWN)
  732.       {
  733.         if (msgfilter->wParam==VK_RETURN) {
  734.           SendMessage(g_hwnd, WM_COMMAND, IDOK, 0);
  735.         }
  736.         if (msgfilter->wParam==VK_ESCAPE) {
  737.           SendMessage(g_hwnd, WM_CLOSE, 0, 0);
  738.         }
  739.         return 1;
  740.       }
  741.     }
  742.     #undef nmhdr
  743.     #undef enlink
  744.     #undef msgfilter
  745.   }
  746.   if (uMsg == WM_NOTIFY_INIGO_MONTOYA)
  747.   {
  748.     ignoreWMCommand++;
  749.   }
  750.   return HandleStaticBkColor();
  751. }
  752. #endif
  753.  
  754. #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
  755. static BOOL CALLBACK UninstProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  756. {
  757.   if (uMsg == WM_INITDIALOG)
  758.   {
  759.     SetUITextFromLang(IDC_UNINSTFROM,this_page->parms[1]);
  760.     SetUITextNT(IDC_EDIT1,g_usrvars[this_page->parms[4]]);
  761.   }
  762.   return HandleStaticBkColor();
  763. }
  764. #endif
  765.  
  766.  
  767. static char * NSISCALL inttosizestr(int kb, char *str)
  768. {
  769.   char scalestr[32], byte[32];
  770.   char sh=20;
  771.   char s=0;
  772.   int scale=LANG_GIGA;
  773.   if (kb < 1024) { sh=0; scale=LANG_KILO; }
  774.   else if (kb < 1024*1024) { sh=10; scale=LANG_MEGA; }
  775.   else if (GetVersion()&0x80000000) s='+';//only display the + on GB shown on win9x.
  776.   wsprintf(
  777.     str+mystrlen(str),
  778.     "%d.%d%s%s%c",
  779.     kb>>sh,
  780.     ((kb*10)>>sh)%10,
  781.     GetNSISString(scalestr,scale),
  782.     GetNSISString(byte,LANG_BYTE),
  783.     s
  784.   );
  785.   return str;
  786. }
  787.  
  788. static int NSISCALL _sumsecsfield(int idx)
  789. {
  790.   int x,total;
  791.   section *sections = g_sections;
  792.   for (total = x = 0; x < num_sections; x++)
  793.   {
  794. #ifdef NSIS_CONFIG_COMPONENTPAGE
  795.     if (sections[x].flags & SF_SELECTED)
  796. #endif
  797.       total += sections[x].fields[idx];
  798.   }
  799.   return total;
  800. }
  801.  
  802. #define sumsecsfield(x) _sumsecsfield(SECTION_OFFSET(x))
  803.  
  804. static BOOL CALLBACK DirProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  805. {
  806.   static int dontsetdefstyle;
  807.   page *thispage = g_this_page;
  808.   char *dir = g_usrvars[thispage->parms[4]];
  809.   int browse_text = thispage->parms[3];
  810.   if (uMsg == WM_NOTIFY_INIGO_MONTOYA)
  811.   {
  812.     GetUIText(IDC_DIR,dir);
  813.     validate_filename(dir);
  814. #ifdef NSIS_CONFIG_LOG
  815. #ifndef NSIS_CONFIG_LOG_ODS
  816.     build_g_logfile();
  817. #endif
  818.     log_dolog = IsDlgButtonChecked(hwndDlg,IDC_CHECK1);
  819. #endif
  820.   }
  821.   if (uMsg == WM_INITDIALOG)
  822.   {
  823. #ifdef NSIS_CONFIG_LOG
  824.     if (GetAsyncKeyState(VK_SHIFT)&0x8000)
  825.     {
  826.       HWND h=GetUIItem(IDC_CHECK1);
  827.       SetUITextFromLang(IDC_CHECK1,LANG_LOG_INSTALL_PROCESS);
  828.       ShowWindow(h,SW_SHOWNA);
  829.     }
  830. #endif
  831.     if (validpathspec(dir) && !skip_root(dir))
  832.       addtrailingslash(dir);
  833.     SetUITextNT(IDC_DIR,dir);
  834.     SetUITextFromLang(IDC_BROWSE,this_page->parms[2]);
  835.     SetUITextFromLang(IDC_SELDIRTEXT,this_page->parms[1]);
  836.     SetActiveCtl(hwndDlg, GetUIItem(IDC_DIR));
  837.   }
  838.   if (uMsg == WM_COMMAND)
  839.   {
  840.     int id=LOWORD(wParam);
  841.     if (id == IDC_DIR && HIWORD(wParam) == EN_CHANGE)
  842.     {
  843.       uMsg = WM_IN_UPDATEMSG;
  844.     }
  845.     if (id == IDC_BROWSE)
  846.     {
  847.       BROWSEINFO bi = {0,};
  848.       ITEMIDLIST *idlist;
  849.       bi.hwndOwner = hwndDlg;
  850.       bi.pszDisplayName = g_tmp;
  851.       bi.lpfn = BrowseCallbackProc;
  852.       bi.lParam = (LPARAM)dir;
  853.       bi.lpszTitle = GetNSISStringTT(browse_text);
  854.       bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
  855.       idlist = SHBrowseForFolder(&bi);
  856.       if (idlist)
  857.       {
  858.         // free idlist
  859.         FreePIDL(idlist);
  860.  
  861.         if (g_header->install_directory_auto_append)
  862.         {
  863.           const char *post_str = ps_tmpbuf;
  864.           GetNSISStringTT(g_header->install_directory_auto_append);
  865.           // display name gives just the folder name
  866.           if (lstrcmpi(post_str, g_tmp))
  867.           {
  868.             lstrcat(addtrailingslash(dir), post_str);
  869.           }
  870.         }
  871.  
  872.         dontsetdefstyle++;
  873.         SetUITextNT(IDC_DIR,dir);
  874.       }
  875.     }
  876.   }
  877.   if (uMsg == WM_IN_UPDATEMSG || uMsg == WM_NOTIFY_START)
  878.   {
  879.     static char s[NSIS_MAX_STRLEN];
  880.     char *p;
  881.     int error = 0;
  882.     int total, available=-1;
  883.     DWORD spc,bps,fc,tc;
  884.  
  885.     GetUIText(IDC_DIR,dir);
  886.     if (!is_valid_instpath(dir))
  887.       error = NSIS_INSTDIR_INVALID;
  888.  
  889.     mystrcpy(s,dir);
  890.     p=skip_root(s);
  891.     if (p)
  892.       *p=0;
  893.  
  894.     if (GetDiskFreeSpace(s,&spc,&bps,&fc,&tc))
  895.     {
  896.       DWORD r=MulDiv(bps*spc,fc,1<<10);
  897.       if (r > 0x7fffffff) r=0x7fffffff;
  898.       available=(int)r;
  899.     }
  900.  
  901.     total = sumsecsfield(size_kb);
  902.  
  903.     if ((unsigned int)available < (unsigned int)total)
  904.       error = NSIS_INSTDIR_NOT_ENOUGH_SPACE;
  905.  
  906.     if (LANG_STR_TAB(LANG_SPACE_REQ)) {
  907.       SetUITextNT(IDC_SPACEREQUIRED,inttosizestr(total,GetNSISString(s,LANG_SPACE_REQ)));
  908.       if (available != -1)
  909.         SetUITextNT(IDC_SPACEAVAILABLE,inttosizestr(available,GetNSISString(s,LANG_SPACE_AVAIL)));
  910.       else
  911.         SetUITextNT(IDC_SPACEAVAILABLE,"");
  912.     }
  913.  
  914.     g_exec_flags.instdir_error = error;
  915.  
  916. #ifdef NSIS_SUPPORT_CODECALLBACKS
  917.     if (!error)
  918.       error = ExecuteCodeSegment(g_header->code_onVerifyInstDir,NULL);
  919. #endif
  920.  
  921.     if (thispage->flags & PF_DIR_NO_BTN_DISABLE)
  922.       error = 0;
  923.  
  924.     EnableNext(!error);
  925.     if (!error && !dontsetdefstyle)
  926.       SetNextDef();
  927.     dontsetdefstyle = 0;
  928.   }
  929.   return HandleStaticBkColor();
  930. }
  931.  
  932. #ifdef NSIS_CONFIG_COMPONENTPAGE
  933.  
  934. static int NSISCALL SetChildrenStates(HWND hwTree, HTREEITEM hItem, int iChecked)
  935. {
  936.   int iCheckedChildren = 0, iChildren = 0, *pFlags, iState = 1;
  937.   HTREEITEM hItrItem;
  938.   TVITEM tvItem;
  939.  
  940.   hItrItem = TreeView_GetChild(hwTree, hItem);
  941.   while (hItrItem)
  942.   {
  943.     iCheckedChildren += SetChildrenStates(hwTree, hItrItem, iChecked);
  944.     iChildren++;
  945.     hItrItem = TreeView_GetNextSibling(hwTree, hItrItem);
  946.   }
  947.  
  948.   tvItem.hItem = hItem;
  949.   tvItem.mask = TVIF_PARAM | TVIF_STATE;
  950.   tvItem.stateMask = TVIS_STATEIMAGEMASK;
  951.   TreeView_GetItem(hwTree, &tvItem);
  952.  
  953.   pFlags = &(g_sections[tvItem.lParam].flags);
  954.  
  955.   if (*pFlags & SF_RO)
  956.   {
  957.     iState = 4;
  958.     iChecked = *pFlags & SF_SELECTED;
  959.   }
  960.  
  961.   *pFlags &= ~(SF_SELECTED|SF_PSELECTED);
  962.  
  963.   if (iCheckedChildren || iChecked)
  964.   {
  965.     iState++;
  966.     if (iChildren == iCheckedChildren)
  967.     {
  968.       *pFlags |= SF_SELECTED;
  969.     }
  970.     else
  971.     {
  972.       iState++;
  973.       *pFlags |= SF_PSELECTED;
  974.     }
  975.     iChecked = 1;
  976.   }
  977.  
  978.   tvItem.state = INDEXTOSTATEIMAGEMASK(iState);
  979.  
  980.   TreeView_SetItem(hwTree, &tvItem);
  981.  
  982.   return iChecked;
  983. }
  984.  
  985. static void NSISCALL SetParentState(HWND hwTree, HTREEITEM hItem)
  986. {
  987.   TVITEM tvItem;
  988.   int iState = 0, iItrState, *iFlags;
  989.  
  990.   HTREEITEM hParent = TreeView_GetParent(hwTree, hItem);
  991.   if (!hParent)
  992.     return;
  993.  
  994.   hItem = TreeView_GetChild(hwTree, hParent);
  995.  
  996.   tvItem.mask = TVIF_STATE | TVIF_PARAM;
  997.   tvItem.stateMask = TVIS_STATEIMAGEMASK;
  998.  
  999.   while (hItem) {
  1000.     tvItem.hItem = hItem;
  1001.     TreeView_GetItem(hwTree, &tvItem);
  1002.     iItrState = tvItem.state >> 12;
  1003.     iState |= iItrState % 3 ? iItrState % 3 : 3;
  1004.     hItem = TreeView_GetNextSibling(hwTree, hItem);
  1005.   }
  1006.  
  1007.   tvItem.hItem = hParent;
  1008.   TreeView_GetItem(hwTree, &tvItem);
  1009.  
  1010.   iFlags = &(g_sections[tvItem.lParam].flags);
  1011.   *iFlags &= ~(SF_SELECTED|SF_PSELECTED);
  1012.  
  1013.   if (iState == 2)
  1014.     *iFlags |= SF_SELECTED;
  1015.   if (iState == 3)
  1016.     *iFlags |= SF_PSELECTED;
  1017.  
  1018.   tvItem.state = INDEXTOSTATEIMAGEMASK(iState);
  1019.   TreeView_SetItem(hwTree, &tvItem);
  1020.  
  1021.   SetParentState(hwTree, hParent);
  1022. }
  1023.  
  1024. #define CheckTreeItem(h, i, c) { SetChildrenStates(h, i, c); SetParentState(h, i); }
  1025.  
  1026. HTREEITEM NSISCALL TreeHitTest(HWND tree)
  1027. {
  1028.   TVHITTESTINFO ht;
  1029.   DWORD dwpos = GetMessagePos();
  1030.  
  1031.   ht.pt.x = GET_X_LPARAM(dwpos);
  1032.   ht.pt.y = GET_Y_LPARAM(dwpos);
  1033.   ScreenToClient(tree, &ht.pt);
  1034.  
  1035.   TreeView_HitTest(tree, &ht);
  1036.  
  1037.   if (ht.flags & (TVHT_ONITEMSTATEICON|TVHT_ONITEMLABEL|TVHT_ONITEMRIGHT|TVHT_ONITEM))
  1038.     return ht.hItem;
  1039.  
  1040.   return 0;
  1041. }
  1042.  
  1043. static LONG oldTreeWndProc;
  1044. static DWORD WINAPI newTreeWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1045. {
  1046.   static LPARAM last_item=-1;
  1047.   if (uMsg == WM_CHAR && wParam == (WPARAM)' ')
  1048.   {
  1049.     NotifyCurWnd(WM_TREEVIEW_KEYHACK);
  1050.     return 0;
  1051.   }
  1052. #if defined(NSIS_SUPPORT_CODECALLBACKS) && defined(NSIS_CONFIG_ENHANCEDUI_SUPPORT)
  1053.   if (uMsg == WM_DESTROY) {
  1054.     last_item=-1;
  1055.   }
  1056.   if (uMsg == WM_MOUSEMOVE) {
  1057.     TVITEM tvItem;
  1058.  
  1059.     if (IsWindowVisible(hwnd)) {
  1060.       tvItem.hItem = TreeHitTest(hwnd);
  1061.  
  1062.       lParam = -1;
  1063.  
  1064.       if (tvItem.hItem)
  1065.       {
  1066.         tvItem.mask = TVIF_PARAM;
  1067.  
  1068.         TreeView_GetItem(hwnd, &tvItem);
  1069.  
  1070.         lParam = tvItem.lParam;
  1071.       }
  1072.       uMsg = WM_NOTIFY_SELCHANGE;
  1073.     }
  1074.   }
  1075.   if (uMsg == WM_NOTIFY_SELCHANGE) {
  1076.     if (last_item != lParam)
  1077.     {
  1078.       last_item = lParam;
  1079.  
  1080.       mystrcpy(g_tmp, g_usrvars[0]);
  1081.  
  1082.       myitoa(g_usrvars[0], lParam);
  1083.  
  1084.       ExecuteCodeSegment(g_header->code_onMouseOverSection,NULL);
  1085.  
  1086.       mystrcpy(g_usrvars[0], g_tmp);
  1087.     }
  1088.   }
  1089. #endif//NSIS_SUPPORT_CODECALLBACKS && NSIS_CONFIG_ENHANCEDUI_SUPPORT
  1090.   return CallWindowProc((WNDPROC)oldTreeWndProc,hwnd,uMsg,wParam,lParam);
  1091. }
  1092.  
  1093. static BOOL CALLBACK SelProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1094. {
  1095.   static HTREEITEM *hTreeItems;
  1096.   static HIMAGELIST hImageList;
  1097.   HWND hwndCombo1 = GetUIItem(IDC_COMBO1);
  1098.   HWND hwndTree1 = GetUIItem(IDC_TREE1);
  1099.   extern HWND g_SectionHack;
  1100.   section *sections=g_sections;
  1101.   int *install_types=g_header->install_types;
  1102.   if (uMsg == WM_INITDIALOG)
  1103.   {
  1104.     int doLines=0;
  1105.     HTREEITEM Par;
  1106.     HBITMAP hBMcheck1;
  1107.     int x, lastGoodX, i, noCombo=2;
  1108.  
  1109.     g_SectionHack=hwndDlg;
  1110.  
  1111.     hTreeItems=(HTREEITEM*)my_GlobalAlloc(sizeof(HTREEITEM)*num_sections);
  1112.  
  1113.     hBMcheck1=LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_BITMAP1));
  1114.  
  1115.     oldTreeWndProc=SetWindowLong(hwndTree1,GWL_WNDPROC,(long)newTreeWndProc);
  1116.  
  1117.     hImageList = ImageList_Create(16,16, ILC_COLOR32|ILC_MASK, 6, 0);
  1118.     ImageList_AddMasked(hImageList,hBMcheck1,RGB(255,0,255));
  1119.  
  1120.     TreeView_SetImageList(hwndTree1, hImageList, TVSIL_STATE);
  1121.  
  1122.     if (SendMessage(hwndTree1, TVM_GETITEMHEIGHT, 0, 0) < 16)
  1123.       SendMessage(hwndTree1, TVM_SETITEMHEIGHT, 16, 0);
  1124.  
  1125.     DeleteObject(hBMcheck1);
  1126.  
  1127.     for (i = 0; i < NSIS_MAX_INST_TYPES+1; i++)
  1128.     {
  1129.       if (install_types[i])
  1130.       {
  1131.         int j;
  1132.         if (i != NSIS_MAX_INST_TYPES) noCombo = 0;
  1133.         GetNSISString(g_tmp,install_types[i]);
  1134.         j=SendMessage(hwndCombo1,CB_ADDSTRING,0,(LPARAM)g_tmp);
  1135.         SendMessage(hwndCombo1,CB_SETITEMDATA,j,i);
  1136.         if (i == g_exec_flags.cur_insttype)
  1137.           SendMessage(hwndCombo1, CB_SETCURSEL, j, 0);
  1138.       }
  1139.     }
  1140.  
  1141.     SetUITextFromLang(IDC_TEXT1,this_page->parms[1+noCombo]);
  1142.     SetUITextFromLang(IDC_TEXT2,this_page->parms[2+noCombo]);
  1143.  
  1144.     Par=NULL;
  1145.  
  1146.     for (lastGoodX = x = 0; x < num_sections; x ++)
  1147.     {
  1148.       section *sec=sections+x;
  1149.  
  1150.       if (sec->name_ptr)
  1151.       {
  1152.         TVINSERTSTRUCT tv;
  1153.         tv.hParent=Par;
  1154.         tv.hInsertAfter=TVI_LAST;
  1155.         tv.item.mask=TVIF_PARAM|TVIF_TEXT|TVIF_STATE;
  1156.         tv.item.lParam=x;
  1157.         tv.item.pszText=GetNSISStringTT(sec->name_ptr);
  1158.         tv.item.stateMask=TVIS_STATEIMAGEMASK|TVIS_EXPANDED|TVIS_BOLD;
  1159.  
  1160.         {
  1161.           int l=1;
  1162.           // Sf_SELECTED == 1
  1163.           l += sec->flags & SF_SELECTED;
  1164.           //if (sec->flags & SF_SELECTED) l++;
  1165.           if (sec->flags & SF_RO) l+=3;
  1166.  
  1167.           tv.item.state=INDEXTOSTATEIMAGEMASK(l);
  1168.         }
  1169.  
  1170.         //if (sec->flags&SF_BOLD)
  1171.         {
  1172.           // SF_BOLD << 1 == 16 == TVIS_BOLD
  1173.           tv.item.state|=(sec->flags&SF_BOLD)<<1;
  1174.         }
  1175.  
  1176.         if (sec->flags&SF_SUBSEC)
  1177.         {
  1178.           tv.item.mask|=TVIF_CHILDREN;
  1179.           tv.item.cChildren=1;
  1180.           //if (sec->flags&SF_EXPAND)
  1181.             // TVIS_EXPANDED == SF_EXPAND
  1182.             tv.item.state|=sec->flags&SF_EXPAND;
  1183.           Par = hTreeItems[x] = TreeView_InsertItem(hwndTree1,&tv);
  1184.           doLines=1;
  1185.         }
  1186.         else if (sec->flags&SF_SUBSECEND)
  1187.         {
  1188.           SetParentState(hwndTree1,hTreeItems[lastGoodX]);
  1189.           Par=TreeView_GetParent(hwndTree1,Par);
  1190.         }
  1191.         else
  1192.         {
  1193.           lastGoodX = x;
  1194.           hTreeItems[x] = TreeView_InsertItem(hwndTree1,&tv);
  1195.         }
  1196.       }
  1197.     }
  1198.     if (!doLines)
  1199.     {
  1200.       SetWindowLong(hwndTree1,GWL_STYLE,GetWindowLong(hwndTree1,GWL_STYLE)&~(TVS_LINESATROOT));
  1201.     }
  1202.     SendMessage(hwndTree1,WM_VSCROLL,SB_TOP,0);
  1203.  
  1204.     if (!noCombo)
  1205.     {
  1206.       ShowWindow(hwndCombo1, SW_SHOW);
  1207.       SetActiveCtl(hwndDlg, hwndCombo1);
  1208.     }
  1209.     else
  1210.       SetActiveCtl(hwndDlg, hwndTree1);
  1211.  
  1212.     uMsg = g_exec_flags.insttype_changed ? WM_NOTIFY_INSTTYPE_CHANGE : WM_IN_UPDATEMSG;
  1213.   }
  1214.   if (uMsg == WM_NOTIFY_SECTEXT) // update text
  1215.   {
  1216.     int x=wParam;
  1217.     int ns=lParam;
  1218.     TVITEM tv;
  1219.  
  1220.     if (tv.hItem=hTreeItems[x])
  1221.     {
  1222.       tv.mask=TVIF_TEXT;
  1223.       tv.pszText=GetNSISStringTT(ns);
  1224.       TreeView_SetItem(hwndTree1,&tv);
  1225.     }
  1226.   }
  1227.   if (uMsg == WM_NOTIFY_SECFLAGS) // change flags
  1228.   {
  1229.     int flags = sections[wParam].flags;
  1230.     TVITEM tvItem;
  1231.  
  1232.     if (!(tvItem.hItem = hTreeItems[wParam])) return 0;
  1233.     tvItem.mask = TVIF_STATE;
  1234.     tvItem.stateMask = TVIS_BOLD;
  1235.     tvItem.state = 0;
  1236.     //if (flags&SF_BOLD) tvItem.state |= TVIS_BOLD;
  1237.     // SF_BOLD << 1 == 16 == TVIS_BOLD
  1238.     tvItem.state|=(flags&SF_BOLD)<<1;
  1239.     TreeView_SetItem(hwndTree1, &tvItem);
  1240.  
  1241.     TreeView_Expand(hwndTree1, tvItem.hItem, flags & SF_EXPAND ? TVE_EXPAND : TVE_COLLAPSE);
  1242.  
  1243.     if ((flags & (SF_PSELECTED | SF_SELECTED)) != SF_PSELECTED)
  1244.     {
  1245.       CheckTreeItem(hwndTree1, tvItem.hItem, flags & SF_SELECTED);
  1246.     }
  1247.   }
  1248.   if (uMsg == WM_NOTIFY || uMsg == WM_TREEVIEW_KEYHACK)
  1249.   {
  1250.     LPNMHDR lpnmh = (LPNMHDR) lParam;
  1251.     if (uMsg == WM_TREEVIEW_KEYHACK || lpnmh->idFrom == IDC_TREE1)
  1252.     {
  1253.       if (!(g_flags&CH_FLAGS_NO_CUSTOM) && (uMsg == WM_TREEVIEW_KEYHACK || lpnmh->code == NM_CLICK))
  1254.       {
  1255.         TVITEM tvItem;
  1256.  
  1257.         if (uMsg != WM_TREEVIEW_KEYHACK)
  1258.           tvItem.hItem=TreeHitTest(hwndTree1);
  1259.         else
  1260.           tvItem.hItem=TreeView_GetSelection(hwndTree1);
  1261.  
  1262.         if (tvItem.hItem)
  1263.         {
  1264.           int iState;
  1265.  
  1266.           tvItem.mask = TVIF_STATE|TVIF_PARAM;
  1267.           TreeView_GetItem(hwndTree1, &tvItem);
  1268.  
  1269.           iState = tvItem.state >> 12;
  1270.  
  1271.           if (iState < 4) // not RO
  1272.           {
  1273.             if (iState == 2) // already checked
  1274.             {
  1275.               sections[tvItem.lParam].flags&=~SF_SELECTED;
  1276.               CheckTreeItem(hwndTree1,tvItem.hItem,0);
  1277.             }
  1278.             else
  1279.             {
  1280.               sections[tvItem.lParam].flags|=SF_SELECTED;
  1281.               CheckTreeItem(hwndTree1,tvItem.hItem,1);
  1282.             }
  1283.             lParam = 0;
  1284.             wParam = 1;
  1285.             uMsg = WM_IN_UPDATEMSG;
  1286.           } // not ro
  1287.         } // was valid click
  1288.       } // was click or hack
  1289. #if defined(NSIS_SUPPORT_CODECALLBACKS) && defined(NSIS_CONFIG_ENHANCEDUI_SUPPORT)
  1290.       if (lpnmh)
  1291.       {
  1292.         if (lpnmh->code == TVN_SELCHANGED)
  1293.         {
  1294.           SendMessage(hwndTree1, WM_NOTIFY_SELCHANGE, 0, ((LPNMTREEVIEW)lpnmh)->itemNew.lParam);
  1295.         }
  1296.         if (lpnmh->code == TVN_ITEMEXPANDED)
  1297.         {
  1298.           LPNMTREEVIEW pnmtv = (LPNMTREEVIEW) lpnmh;
  1299.           if (pnmtv->action == TVE_EXPAND)
  1300.             sections[pnmtv->itemNew.lParam].flags |= SF_EXPAND;
  1301.           else
  1302.             sections[pnmtv->itemNew.lParam].flags &= ~SF_EXPAND;
  1303.         }
  1304.       }
  1305. #endif//NSIS_SUPPORT_CODECALLBACKS && NSIS_CONFIG_ENHANCEDUI_SUPPORT
  1306.     }
  1307.   }
  1308.   if (uMsg == WM_MOUSEMOVE)
  1309.   {
  1310.     SendMessage(hwndTree1, WM_MOUSEMOVE, 0, 0);
  1311.   }
  1312.   if (uMsg == WM_NOTIFY_INSTTYPE_CHANGE ||
  1313.      (uMsg == WM_COMMAND && LOWORD(wParam)==IDC_COMBO1 && HIWORD(wParam)==CBN_SELCHANGE))
  1314.   {
  1315.     int t=SendMessage(hwndCombo1,CB_GETCURSEL,0,0);
  1316.     if (uMsg == WM_NOTIFY_INSTTYPE_CHANGE || t != CB_ERR)
  1317.     {
  1318.       int whichcfg=SendMessage(hwndCombo1,CB_GETITEMDATA,t,0);
  1319.       if (uMsg == WM_NOTIFY_INSTTYPE_CHANGE)
  1320.       {
  1321.         whichcfg = g_exec_flags.cur_insttype;
  1322.         g_exec_flags.insttype_changed = 0;
  1323.       }
  1324.       else lParam = 1;
  1325.  
  1326.       if (whichcfg == CB_ERR || !(install_types[whichcfg]))
  1327.         whichcfg = NSIS_MAX_INST_TYPES;
  1328.  
  1329.       if (whichcfg != NSIS_MAX_INST_TYPES) // not custom
  1330.       {
  1331.         int x=num_sections;
  1332.         section *t=sections;
  1333.         HTREEITEM *ht=hTreeItems;
  1334.         while (x--)
  1335.         {
  1336.           TVITEM tv;
  1337.           int l=1;
  1338.  
  1339.           if (t->install_types & (1<<whichcfg))
  1340.           {
  1341.             l++;
  1342.             t->flags|=SF_SELECTED;
  1343.           }
  1344.           else t->flags&=~SF_SELECTED;
  1345.  
  1346.           if (t->flags&SF_RO) l+=3;
  1347.  
  1348.           if (tv.hItem=*ht) {
  1349.             tv.mask=TVIF_STATE;
  1350.             tv.state=INDEXTOSTATEIMAGEMASK(l);
  1351.             tv.stateMask=TVIS_STATEIMAGEMASK;
  1352.  
  1353.             TreeView_SetItem(hwndTree1,&tv);
  1354.             SetParentState(hwndTree1,tv.hItem);
  1355.           }
  1356.           t++;
  1357.           ht++;
  1358.         }
  1359.         SendMessage(hwndTree1,WM_VSCROLL,SB_TOP,0);
  1360.       }
  1361.  
  1362.       g_exec_flags.cur_insttype=whichcfg;
  1363.  
  1364.       uMsg = WM_IN_UPDATEMSG;
  1365.     }
  1366.   }
  1367.   if (uMsg == WM_NOTIFY_INIGO_MONTOYA)
  1368.   {
  1369.     if (hImageList) ImageList_Destroy(hImageList);
  1370.     if (hTreeItems) GlobalFree(hTreeItems);
  1371.     hImageList=NULL;
  1372.     hTreeItems=NULL;
  1373.     g_SectionHack=NULL;
  1374.   }
  1375.   if (uMsg == WM_IN_UPDATEMSG)
  1376.   {
  1377. #if defined(NSIS_SUPPORT_CODECALLBACKS) && defined(NSIS_CONFIG_COMPONENTPAGE)
  1378.   if ( wParam )
  1379.     ExecuteCodeSegment(g_header->code_onSelChange,NULL);
  1380. #endif//NSIS_SUPPORT_CODECALLBACKS && NSIS_CONFIG_COMPONENTPAGE
  1381.  
  1382.     if (g_flags & CH_FLAGS_COMP_ONLY_ON_CUSTOM)
  1383.     {
  1384.       int c = (g_exec_flags.cur_insttype == NSIS_MAX_INST_TYPES) << 3;// SW_SHOWNA=8, SW_HIDE=0
  1385.       ShowWindow(hwndTree1, c);
  1386.       ShowWindow(GetUIItem(IDC_TEXT2), c);
  1387.     }
  1388.     else if (!lParam)
  1389.     {
  1390.       int r,x,cbi;
  1391.       // check to see which install type we are
  1392.       for (r = 0, cbi = 0; r < NSIS_MAX_INST_TYPES; r ++)
  1393.       {
  1394.         HTREEITEM *ht=hTreeItems;
  1395.         section *t=sections;
  1396.         x=num_sections;
  1397.  
  1398.         if (!install_types[r]) continue;
  1399.  
  1400.         while (x--)
  1401.         {
  1402.           if (*ht && !(t->flags&(SF_SUBSEC|SF_SUBSECEND)))
  1403.           {
  1404.             TVITEM tvItem;
  1405.             tvItem.hItem=*ht;
  1406.             tvItem.mask=TVIF_STATE;
  1407.             TreeView_GetItem(hwndTree1,&tvItem);
  1408.             if (!(t->install_types&(1<<r)) != !((tvItem.state>>12 != 1 && (tvItem.state>>12 != 4)))) break;
  1409.           }
  1410.           t++;
  1411.           ht++;
  1412.         }
  1413.         if (x < 0) break;
  1414.  
  1415.         cbi++;
  1416.       }
  1417.  
  1418.       g_exec_flags.cur_insttype=r;
  1419.       SendMessage(hwndCombo1,CB_SETCURSEL,cbi,0);
  1420.     } // end of typecheckshit
  1421.  
  1422.     if (LANG_STR_TAB(LANG_SPACE_REQ)) {
  1423.       SetUITextNT(IDC_SPACEREQUIRED,inttosizestr(sumsecsfield(size_kb),GetNSISString(g_tmp,LANG_SPACE_REQ)));
  1424.  
  1425.     }
  1426.   }
  1427.  
  1428.   return HandleStaticBkColor();
  1429. }
  1430. #endif//NSIS_CONFIG_COMPONENTPAGE
  1431.  
  1432. #endif//NSIS_CONFIG_VISIBLE_SUPPORT
  1433.  
  1434. int ui_st_updateflag=0x6;
  1435.  
  1436. void NSISCALL update_status_text(int strtab, const char *text) {
  1437.   static char tmp[NSIS_MAX_STRLEN*2];
  1438.   LVITEM new_item;
  1439.   HWND linsthwnd = insthwnd;
  1440.   if (linsthwnd)
  1441.   {
  1442.     int updateflag = ui_st_updateflag;
  1443.     int tmplen;
  1444.  
  1445.     if (!(updateflag & 1))
  1446.       GetNSISString(tmp, strtab);
  1447.  
  1448.     tmplen = mystrlen(tmp);
  1449.  
  1450.     if (text)
  1451.     {
  1452.       if (tmplen + mystrlen(text) >= sizeof(tmp)) return;
  1453.       lstrcat(tmp, text);
  1454.     }
  1455.  
  1456.     if ((updateflag & 4)) my_SetWindowText(insthwnd2, tmp);
  1457.     if ((updateflag & 2))
  1458.     {
  1459.       new_item.mask = LVIF_TEXT;
  1460.       new_item.pszText = tmp;
  1461.       new_item.iItem = ListView_GetItemCount(linsthwnd) - (updateflag & 1);
  1462.       new_item.iSubItem = 0;
  1463.       SendMessage(linsthwnd, (updateflag & 1) ? LVM_SETITEM : LVM_INSERTITEM, 0, (LPARAM) &new_item);
  1464.       ListView_EnsureVisible(linsthwnd, new_item.iItem, 0);
  1465.     }
  1466.  
  1467.     if (updateflag & 1)
  1468.       tmp[tmplen] = 0;
  1469.   }
  1470. }
  1471.  
  1472. static DWORD WINAPI install_thread(LPVOID p)
  1473. {
  1474.   int m_inst_sec=0;
  1475.   HWND progresswnd = (HWND)p;
  1476.  
  1477. #if defined(NSIS_SUPPORT_ACTIVEXREG) || defined(NSIS_SUPPORT_CREATESHORTCUT)
  1478.   {
  1479.     extern HRESULT g_hres;
  1480.     g_hres|=OleInitialize(NULL);
  1481.   }
  1482. #endif
  1483.  
  1484.   while (m_inst_sec<num_sections)
  1485.   {
  1486. #ifdef NSIS_CONFIG_COMPONENTPAGE
  1487.     if (g_sections[m_inst_sec].flags&SF_SELECTED)
  1488. #endif
  1489.     {
  1490.       log_printf2("Section: \"%s\"",GetNSISStringTT(g_sections[m_inst_sec].name_ptr));
  1491.       if (ExecuteCodeSegment(g_sections[m_inst_sec].code,progresswnd))
  1492.       {
  1493.         g_exec_flags.abort++;
  1494.         break;
  1495.       }
  1496.     }
  1497. #ifdef NSIS_CONFIG_COMPONENTPAGE
  1498.     else
  1499.     {
  1500.       log_printf2("Skipping section: \"%s\"",GetNSISStringTT(g_sections[m_inst_sec].name_ptr));
  1501.     }
  1502. #endif
  1503.     m_inst_sec++;
  1504.   }
  1505.   NotifyCurWnd(WM_NOTIFY_INSTPROC_DONE);
  1506.  
  1507. #if defined(NSIS_SUPPORT_ACTIVEXREG) || defined(NSIS_SUPPORT_CREATESHORTCUT)
  1508.   OleUninitialize();
  1509. #endif
  1510.  
  1511.   return g_exec_flags.abort;
  1512. }
  1513.  
  1514. #ifdef NSIS_CONFIG_VISIBLE_SUPPORT
  1515.  
  1516. static BOOL CALLBACK InstProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1517. {
  1518.   HWND linsthwnd=insthwnd;
  1519.   if (uMsg == WM_INITDIALOG)
  1520.   {
  1521.     RECT r;
  1522.     LVCOLUMN lvc = {LVCF_WIDTH, 0, -1, 0, 0, -1};
  1523.     int lb_bg=g_header->lb_bg,lb_fg=g_header->lb_fg;
  1524.  
  1525.     insthwndbutton=GetUIItem(IDC_SHOWDETAILS);
  1526.     insthwnd2=GetUIItem(IDC_INTROTEXT);
  1527.     linsthwnd=insthwnd=GetUIItem(IDC_LIST1);
  1528.  
  1529.     progress_bar_len=sumsecsfield(code_size);
  1530.     progress_bar_pos=0;
  1531.  
  1532.     log_printf3("New install of \"%s\" to \"%s\"",GetNSISStringTT(LANG_NAME),state_install_directory);
  1533.  
  1534.     GetClientRect(linsthwnd, &r);
  1535.     lvc.cx = r.right - GetSystemMetrics(SM_CXHSCROLL);
  1536.     ListView_InsertColumn(linsthwnd, 0, &lvc);
  1537.  
  1538.     ListView_SetExtendedListViewStyleEx(linsthwnd, LVS_EX_LABELTIP, LVS_EX_LABELTIP);
  1539.     if (lb_bg >= 0) {
  1540.       ListView_SetBkColor(linsthwnd, lb_bg);
  1541.       ListView_SetTextBkColor(linsthwnd, lb_bg);
  1542.     }
  1543.     if (lb_fg >= 0) {
  1544.       ListView_SetTextColor(linsthwnd, lb_fg);
  1545.     }
  1546.     SetUITextFromLang(IDC_SHOWDETAILS,this_page->parms[1]);
  1547.     if (g_flags&(CH_FLAGS_DETAILS_SHOWDETAILS|CH_FLAGS_DETAILS_NEVERSHOW))
  1548.     {
  1549.       ShowWindow(insthwndbutton,SW_HIDE);
  1550.       if (!(g_flags&CH_FLAGS_DETAILS_NEVERSHOW)) ShowWindow(linsthwnd,SW_SHOWNA);
  1551.       else insthwndbutton=NULL;
  1552.     }
  1553.  
  1554.     {
  1555.       HWND progresswnd=GetUIItem(IDC_PROGRESS);
  1556.       SendMessage(progresswnd,PBM_SETRANGE,0,MAKELPARAM(0,30000));
  1557.       if (g_flags&CH_FLAGS_PROGRESS_COLORED)
  1558.       {
  1559.         SendMessage(progresswnd,PBM_SETBARCOLOR,0,lb_fg);
  1560.         SendMessage(progresswnd,PBM_SETBKCOLOR,0,lb_bg);
  1561.       }
  1562.     }
  1563.  
  1564.     return FALSE;
  1565.   }
  1566.   if (uMsg == WM_NOTIFY_START) {
  1567.     DWORD id;
  1568.     CloseHandle(CreateThread(NULL,0,install_thread,GetUIItem(IDC_PROGRESS),0,&id));
  1569.   }
  1570.   if (uMsg == WM_COMMAND && LOWORD(wParam) == IDC_SHOWDETAILS)
  1571.   {
  1572.     ShowWindow(insthwndbutton,SW_HIDE);
  1573.     ShowWindow(linsthwnd,SW_SHOWNA);
  1574.     SetNextDef();
  1575.   }
  1576.   if (uMsg == WM_NOTIFY_INSTPROC_DONE)
  1577.   {
  1578.     if (g_quit_flag)
  1579.     {
  1580.       m_retcode=1;
  1581.       outernotify(NOTIFY_BYE_BYE);
  1582.     }
  1583.     else
  1584.     {
  1585.       ShowWindow(g_hwnd,SW_SHOWNA);
  1586.       if (!g_exec_flags.abort)
  1587.         update_status_text(g_this_page->parms[2],0);
  1588.       outernotify(1);
  1589.     }
  1590.   }
  1591.   //>>>Ximon Eighteen aka Sunjammer 30th August 2002
  1592.   //+++Popup "Copy Details To Clipboard" menu when RMB clicked in DetailView
  1593.   //+++Currently this has no language support for the popup menu tex
  1594.   if (uMsg == WM_CONTEXTMENU && wParam == (WPARAM) linsthwnd)
  1595.   {
  1596.     int count = ListView_GetItemCount(linsthwnd);
  1597.     if (count > 0)
  1598.     {
  1599.       HMENU menu = CreatePopupMenu();
  1600.       POINT pt;
  1601.       AppendMenu(menu,MF_STRING,1,GetNSISStringTT(LANG_COPYDETAILS));
  1602.       if (lParam == ((UINT)-1))
  1603.       {
  1604.         RECT r;
  1605.         GetWindowRect(linsthwnd, &r);
  1606.         pt.x = r.left;
  1607.         pt.y = r.top;
  1608.       }
  1609.       else
  1610.       {
  1611.         pt.x = GET_X_LPARAM(lParam);
  1612.         pt.y = GET_Y_LPARAM(lParam);
  1613.       }
  1614.       if (1==TrackPopupMenu(
  1615.         menu,
  1616.         TPM_NONOTIFY|TPM_RETURNCMD,
  1617.         pt.x,
  1618.         pt.y,
  1619.         0,linsthwnd,0))
  1620.       {
  1621.         int i,total = 1; // 1 for the null char
  1622.         LVITEM item;
  1623.         HGLOBAL memory;
  1624.         LPTSTR ptr;//,endPtr;
  1625.  
  1626.         // 1st pass - determine clipboard memory required.
  1627.         item.iSubItem   = 0;
  1628.         item.pszText    = g_tmp;
  1629.         item.cchTextMax = sizeof(g_tmp) - 1;
  1630.         i = count;
  1631.         while (i--)
  1632.           // Add 2 for the CR/LF combination that must follow every line.
  1633.           total += 2+SendMessage(linsthwnd,LVM_GETITEMTEXT,i,(LPARAM)&item);
  1634.  
  1635.         // 2nd pass - store detail view strings on the clipboard
  1636.         // Clipboard MSDN docs say mem must be GMEM_MOVEABLE
  1637.         OpenClipboard(0);
  1638.         EmptyClipboard();
  1639.         memory = GlobalAlloc(GHND,total);
  1640.         ptr = GlobalLock(memory);
  1641.         //endPtr = ptr+total-2; // -2 to allow for CR/LF
  1642.         i = 0;
  1643.         do {
  1644.           item.pszText = ptr;
  1645.           item.cchTextMax = total;
  1646.           SendMessage(linsthwnd,LVM_GETITEMTEXT,i,(LPARAM)&item);
  1647.           ptr += mystrlen(ptr);
  1648.           *(WORD*)ptr = CHAR2_TO_WORD('\r','\n');
  1649.           ptr+=2;
  1650.         } while (++i < count);
  1651.         // memory is auto zeroed when allocated with GHND - *ptr = 0;
  1652.         GlobalUnlock(memory);
  1653.         SetClipboardData(CF_TEXT,memory);
  1654.         CloseClipboard();
  1655.       }
  1656.     }
  1657.     return FALSE;
  1658.   }
  1659.   //<<<
  1660.   return HandleStaticBkColor();
  1661. }
  1662. #endif//NSIS_CONFIG_VISIBLE_SUPPORT
  1663.