diff --git a/Contrib/InstallOptions/Changelog.txt b/Contrib/InstallOptions/Changelog.txt index 27da03f5..79c20011 100644 --- a/Contrib/InstallOptions/Changelog.txt +++ b/Contrib/InstallOptions/Changelog.txt @@ -1,3 +1,9 @@ +DLL version 2.3 (12/4/2003) +* Added new control type "Button" +* Added new flag "NOTIFY" +* Added new flag "NOWORDWRAP" for multi-line text boxes +* Reduced size down to 12K + DLL version 2.2 (6/10/2003) * Added New control type LINK * \r\n converts to newline in Multiline edit box @@ -24,45 +30,45 @@ DLL version 2.0 (1/4/2003) * New documentation (by Joost Verburg) * New GROUP/NOTABSTOP/DISABLED flags -DLL version 1.7 beta (11/2/2002) +DLL version 1.7 beta (11/2/2002) * Added initDialog and show DLL functions DLL version 1.6 beta (9/30/2002) * CancelConfirmIcon becomes CancelConfirmFlags and can now take the other common MessageBox flags -DLL version 1.5 beta (9/26/2002) +DLL version 1.5 beta (9/26/2002) * Made close [x] button behave like Cancel (thanks brainsucker) DLL version 1.4 beta (9/4/2002) * Added Icon and Bitmap controls (by Amir Szekely) DLL version 1.3 beta (8/15/2002) -* Added CancelShow (by ORTIM) +* Added CancelShow (by ORTIM) * Added pixel transformation for widgets (by ORTIM) DLL version 1.2 beta (7/31/2002) * Added CancelEnabled (by ORTIM) -* Added CancelConfirmCaption and CancelConfirmIcon (by Amir Szekely) +* Added CancelConfirmCaption and CancelConfirmIcon (by Amir Szekely) DLL version 1.1 beta (7/22/2002) * Font is now taken from the main NSIS window (by Amir Szekely) DLL version 1.0 beta (12/16/2001) -* Moved to DLL, no longer need parentwnd ini writing -* Tons of changes - no longer fully compatible (see source for a big list) -* removed support for silent installers (it seems the old version would bring up it's own dialog) +* Moved to DLL, no longer need parentwnd ini writing +* Tons of changes - no longer fully compatible (see source for a big list) +* removed support for silent installers (it seems the old version would bring up it's own dialog) version 1.4 (11/18/2001) -* Added Listbox controls. -* Added MULTISELECT flag. +* Added Listbox controls. +* Added MULTISELECT flag. * Made the HWND list for the parent window controls dynamically allocated. This prevents a crash if NSIS ever gets more than 150 controls on it's main window. -* The TEXT property of DirRequest control can be used to specify an initial directory. The current directory is automatically selected when clicking the browse button of the DirRequest control. -* Added ROOT property to DirRequest which can be used to set the root directory (mostly due to felfert) -* Edit controls will now auto scroll (thanks felfert) -* Fixed a problem where the window wouldn't draw properly on some systems (thanks felfert) +* The TEXT property of DirRequest control can be used to specify an initial directory. The current directory is automatically selected when clicking the browse button of the DirRequest control. +* Added ROOT property to DirRequest which can be used to set the root directory (mostly due to felfert) +* Edit controls will now auto scroll (thanks felfert) +* Fixed a problem where the window wouldn't draw properly on some systems (thanks felfert) version 1.3 (11/03/2001) -* Got rid of the call to RedrawWindow() because it's no longer needed with the WS_CLIPCHILDREN flag for NSIS. +* Got rid of the call to RedrawWindow() because it's no longer needed with the WS_CLIPCHILDREN flag for NSIS. * Removed a few hardcoded limits of buffer sizes * Added Checkbox and RadioButton controls * Added RIGHT and CHECKED flags @@ -71,10 +77,10 @@ version 1.2.2 (10/30/2001) * Additional size reductions. Further reduced the size down to 8k. * The text parameter to a combobox can now be used to specify the initial value * Changed from InvalidateRect() to RedrawWindow() to force a redraw after a browse dialog -* On startup, set the flags of the NSIS window to include WS_CLIPCHILDREN. Otherwise, our controls don't get drawn right. +* On startup, set the flags of the NSIS window to include WS_CLIPCHILDREN. Otherwise, our controls don't get drawn right. version 1.2.1 (10/28/2001) -* Bug fix. ControlID for the caption and the OK button were reused by the first two controls. (Thanks Schultz) +* Bug fix. ControlID for the caption and the OK button were reused by the first two controls. (Thanks Schultz) version 1.2j (10/28/2001) * 8.5kb from 44kb. heh. (by Justin Frankel) @@ -98,4 +104,4 @@ version 1.01 (10/25/2001) * Added the license to the documentation version 1.0 (10/25/2001) -* Barely qualifies as a distribution \ No newline at end of file +* Barely qualifies as a distribution diff --git a/Contrib/InstallOptions/InstallerOptions.cpp b/Contrib/InstallOptions/InstallerOptions.cpp index f5ac491c..23ab8f17 100644 --- a/Contrib/InstallOptions/InstallerOptions.cpp +++ b/Contrib/InstallOptions/InstallerOptions.cpp @@ -18,6 +18,9 @@ #include "../exdll/exdll.h" #undef popstring +void *WINAPI MALLOC(int len) { return (void*)GlobalAlloc(GPTR,len); } +void WINAPI FREE(void *d) { if (d) GlobalFree((HGLOBAL)d); } + static int WINAPI popstring(char *str) { stack_t *th; @@ -25,7 +28,7 @@ static int WINAPI popstring(char *str) th=(*g_stacktop); if (str) lstrcpy(str,th->text); *g_stacktop = th->next; - GlobalFree((HGLOBAL)th); + FREE(th); return 0; } @@ -41,14 +44,11 @@ typedef struct { } ctlcolors; #define strcpy(x,y) lstrcpy(x,y) -#define strncpy(x,y,z) lstrcpyn(x,y,z) +//#define strncpy(x,y,z) lstrcpyn(x,y,z) #define strdup(x) STRDUP(x) #define stricmp(x,y) lstrcmpi(x,y) //#define abs(x) ((x) < 0 ? -(x) : (x)) -void *WINAPI MALLOC(int len) { return (void*)GlobalAlloc(GPTR,len); } -void WINAPI FREE(void *d) { if (d) GlobalFree((HGLOBAL)d); } - char *WINAPI STRDUP(const char *c) { char *t=(char*)MALLOC(lstrlen(c)+1); @@ -69,6 +69,7 @@ char *WINAPI STRDUP(const char *c) #define FIELD_LISTBOX (11) #define FIELD_GROUPBOX (12) #define FIELD_LINK (13) +#define FIELD_BUTTON (14) //--------------------------------------------------------------------- // settings @@ -107,6 +108,15 @@ char *WINAPI STRDUP(const char *c) // bitmap flags #define FLAG_RESIZETOFIT 0x00008000 +// general flags +#define FLAG_NOTIFY 0x00010000 // Notify NSIS script when control is "activated" (exact meaning depends on the type of control) + +// browse flags +#define FLAG_SAVEAS 0x00020000 // Show "Save As" instead of "Open" for FileRequest field + +// text box flags +#define FLAG_NOWORDWRAP 0x00040000 // Disable word-wrap in multi-line text boxes + // OFN_EXPLORER 0x00080000 // more text box flags @@ -141,12 +151,11 @@ struct FieldType { char *pszValidateText; int nFlags; - bool bSaveDlg; HWND hwnd; UINT nControlID; - int nParentIdx; // this is used by the filerequest and dirrequest controls, used to store original windowproc for LINK + int nParentIdx; // this is used to store original windowproc for LINK HANDLE hImage; // this is used by image/icon field to save the handle to the image }; @@ -184,6 +193,7 @@ FieldType *pFields = NULL; int nRectId = 0; int nNumFields = 0; int g_done; +int g_NotifyField; // Field number of notifying control int WINAPI FindControlIdx(UINT id) { @@ -193,124 +203,24 @@ int WINAPI FindControlIdx(UINT id) return -1; } -// array of HWNDs and window styles used to make the main NSIS controls invisible while this program runs. - -bool WINAPI BrowseForFile(int nControlIdx) { - OPENFILENAME ofn={0,}; - HWND hControl; - BOOL bResult; - FieldType *pThisField = &pFields[nControlIdx]; - - hControl = pThisField->hwnd; - - ofn.Flags = pThisField->nFlags & (OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_CREATEPROMPT | OFN_EXPLORER); - -// ofn.hInstance = m_hInstance; // no templates so we can leave this at NULL; - ofn.hwndOwner = hConfigWindow; -// ofn.lCustData = NULL; -// ofn.lpfnHook = NULL; -// ofn.lpstrCustomFilter = NULL; -// ofn.lpstrDefExt = NULL; - ofn.nMaxFile = MAX_PATH; - ofn.lpstrFile = (char*)MALLOC(MAX_PATH); - -// ofn.nMaxFileTitle = MAX_PATH; // we ignore this for simplicity, leave lpstrFileTitle at NULL -// ofn.lpstrFileTitle = new char [ofn.nMaxFileTitle]; - - ofn.lpstrFilter = pThisField->pszFilter; // TODO: implement this -// ofn.lpstrInitialDir = NULL; // for now, just use the default initial directory. -// ofn.lpstrTitle = NULL; // TODO: implement this -// ofn.lpTemplateName = NULL; - ofn.lStructSize = sizeof(ofn); -// ofn.nFileExtension // this is output variable, leave it to 0 for now. -// ofn.nFileOffset // this is output variable, leave it to 0 for now. -// ofn.nFilterIndex = 1; // since we use no custom filters, leaving it at 0 means use the first. -// ofn.nMaxCustFilter = 0; - - GetWindowText(hControl, ofn.lpstrFile, MAX_PATH); - -tryagain: - if (pThisField->bSaveDlg) { - bResult = GetSaveFileName(&ofn); - } else { - bResult = GetOpenFileName(&ofn); - } - if (bResult) { - SetWindowText(hControl, ofn.lpstrFile); - return true; - } - else if (ofn.lpstrFile[0] && CommDlgExtendedError() == FNERR_INVALIDFILENAME) { - ofn.lpstrFile[0] = '\0'; - goto tryagain; - } - - return false; +LRESULT WINAPI mySendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + return SendMessage(hWnd, Msg, wParam, lParam); } int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData) { - TCHAR szDir[MAX_PATH]; + static TCHAR szDir[MAX_PATH]; if (uMsg == BFFM_INITIALIZED) { if (GetWindowText(pFields[(int)pData].hwnd, szDir, MAX_PATH) > 0) { - SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)szDir); + mySendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)szDir); } } return 0; } -bool WINAPI BrowseForFolder(int nControlIdx) { - BROWSEINFO bi; - - bi.hwndOwner = hConfigWindow; - bi.pidlRoot = NULL; - bi.pszDisplayName = (char*)MALLOC(MAX_PATH); - bi.lpszTitle = pFields[nControlIdx].pszText; -#ifndef BIF_NEWDIALOGSTYLE -#define BIF_NEWDIALOGSTYLE 0x0040 -#endif - bi.ulFlags = BIF_STATUSTEXT | BIF_RETURNONLYFSDIRS| BIF_NEWDIALOGSTYLE; - bi.lpfn = BrowseCallbackProc; - bi.lParam = nControlIdx; - bi.iImage = 0; - - if (pFields[nControlIdx].pszRoot) { - LPSHELLFOLDER sf; - ULONG eaten; - LPITEMIDLIST root; - int ccRoot = (lstrlen(pFields[nControlIdx].pszRoot) * 2) + 2; - LPWSTR pwszRoot = (LPWSTR) MALLOC(ccRoot); - MultiByteToWideChar(CP_ACP, 0, pFields[nControlIdx].pszRoot, -1, pwszRoot, ccRoot); - SHGetDesktopFolder(&sf); - sf->ParseDisplayName(hConfigWindow, NULL, pwszRoot, &eaten, &root, NULL); - bi.pidlRoot = root; - sf->Release(); - FREE(pwszRoot); - } -// CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); - LPITEMIDLIST pResult = SHBrowseForFolder(&bi); - if (!pResult) { - FREE(bi.pszDisplayName); - return false; - } - - char *pszFolder = (char*)MALLOC(MAX_PATH); - if (SHGetPathFromIDList(pResult, pszFolder)) { - SetWindowText(pFields[nControlIdx].hwnd, pszFolder); - } - - LPMALLOC pMalloc; - if (!SHGetMalloc(&pMalloc)) { - pMalloc->Free(pResult); - } - - FREE(bi.pszDisplayName); - FREE(pszFolder); - - return true; -} - bool WINAPI ValidateFields() { int nIdx; int nLength; @@ -318,17 +228,18 @@ bool WINAPI ValidateFields() { // In the unlikely event we can't allocate memory, go ahead and return true so we can get out of here. // May cause problems for the install script, but no memory is problems for us. for (nIdx = 0; nIdx < nNumFields; nIdx++) { + FieldType *pField = pFields + nIdx; // this if statement prevents a stupid bug where a min/max length is assigned to a label control // where the user obviously has no way of changing what is displayed. (can you say, "infinite loop"?) - if (pFields[nIdx].nType >= FIELD_TEXT) { - nLength = SendMessage(pFields[nIdx].hwnd, WM_GETTEXTLENGTH, 0, 0); + if (pField->nType >= FIELD_TEXT) { + nLength = mySendMessage(pField->hwnd, WM_GETTEXTLENGTH, 0, 0); - if (((pFields[nIdx].nMaxLength > 0) && (nLength > pFields[nIdx].nMaxLength)) || - ((pFields[nIdx].nMinLength > 0) && (nLength < pFields[nIdx].nMinLength))) { - if (pFields[nIdx].pszValidateText) { - MessageBox(hConfigWindow, pFields[nIdx].pszValidateText, NULL, MB_OK|MB_ICONWARNING); + if (((pField->nMaxLength > 0) && (nLength > pField->nMaxLength)) || + ((pField->nMinLength > 0) && (nLength < pField->nMinLength))) { + if (pField->pszValidateText) { + MessageBox(hConfigWindow, pField->pszValidateText, NULL, MB_OK|MB_ICONWARNING); } - SetFocus(pFields[nIdx].hwnd); + SetFocus(pField->hwnd); return false; } @@ -340,27 +251,28 @@ bool WINAPI ValidateFields() { bool WINAPI SaveSettings(void) { static char szField[25]; int nIdx; - HWND hwnd; int nBufLen = MAX_BUFFER_LENGTH; char *pszBuffer = (char*)MALLOC(nBufLen); if (!pszBuffer) return false; int CurrField = 1; - for(nIdx = 0; nIdx < nNumFields; nIdx++) { - if (pFields[nIdx].nType == FIELD_BROWSEBUTTON) - continue; - - hwnd = pFields[nIdx].hwnd; - wsprintf(szField, "Field %d", CurrField); - switch(pFields[nIdx].nType) { + for (nIdx = 0; nIdx < nNumFields; nIdx++) { + FieldType *pField = pFields + nIdx; + HWND hwnd = pField->hwnd; + switch (pField->nType) { + case FIELD_BROWSEBUTTON: + if (g_NotifyField > CurrField) + --g_NotifyField; + continue; case FIELD_INVALID: + case FIELD_LABEL: + case FIELD_BUTTON: + *pszBuffer=0; break; case FIELD_CHECKBOX: case FIELD_RADIOBUTTON: - { - wsprintf(pszBuffer, "%d", !!SendMessage(hwnd, BM_GETCHECK, 0, 0)); - break; - } + wsprintf(pszBuffer, "%d", !!mySendMessage(hwnd, BM_GETCHECK, 0, 0)); + break; case FIELD_LISTBOX: { // Ok, this one requires a bit of work. @@ -368,7 +280,7 @@ bool WINAPI SaveSettings(void) { // Then, we loop through every item and if it's selected we add it to our buffer. // If there is already an item in the list, then we prepend a | character before the new item. // We could simplify for single-select boxes, but using one piece of code saves some space. - int nLength = lstrlen(pFields[nIdx].pszListItems) + 10; + int nLength = lstrlen(pField->pszListItems) + 10; if (nLength > nBufLen) { FREE(pszBuffer); nBufLen = nLength; @@ -379,11 +291,11 @@ bool WINAPI SaveSettings(void) { if (!pszItem) return false; *pszBuffer = '\0'; - int nNumItems = SendMessage(hwnd, LB_GETCOUNT, 0, 0); - for(int nIdx2 = 0; nIdx2 < nNumItems; nIdx2++) { - if (SendMessage(hwnd, LB_GETSEL, nIdx2, 0) > 0) { + int nNumItems = mySendMessage(hwnd, LB_GETCOUNT, 0, 0); + for (int nIdx2 = 0; nIdx2 < nNumItems; nIdx2++) { + if (mySendMessage(hwnd, LB_GETSEL, nIdx2, 0) > 0) { if (*pszBuffer) lstrcat(pszBuffer, "|"); - SendMessage(hwnd, LB_GETTEXT, (WPARAM)nIdx2, (LPARAM)pszItem); + mySendMessage(hwnd, LB_GETTEXT, (WPARAM)nIdx2, (LPARAM)pszItem); lstrcat(pszBuffer, pszItem); } } @@ -391,12 +303,9 @@ bool WINAPI SaveSettings(void) { FREE(pszItem); break; } - case FIELD_LABEL: - *pszBuffer=0; - break; default: { - int nLength = SendMessage(pFields[nIdx].hwnd, WM_GETTEXTLENGTH, 0, 0); + int nLength = mySendMessage(pField->hwnd, WM_GETTEXTLENGTH, 0, 0); if (nLength > nBufLen) { FREE(pszBuffer); // add a bit extra so we do this less often @@ -409,7 +318,7 @@ bool WINAPI SaveSettings(void) { pszBuffer[nLength+1]='"'; pszBuffer[nLength+2]='\0'; - if ( pFields[nIdx].nType == FIELD_TEXT && pFields[nIdx].nFlags & FLAG_MULTILINE ) + if ( pField->nType == FIELD_TEXT && pField->nFlags & FLAG_MULTILINE ) { char *pszBuf2 = (char*)MALLOC(nBufLen*2); // double the size, consider the worst case, all chars are \r\n char *p1, *p2; @@ -442,10 +351,15 @@ bool WINAPI SaveSettings(void) { break; } } - WritePrivateProfileString(szField, "STATE", pszBuffer, pszFilename); + wsprintf(szField, "Field %d", CurrField); + WritePrivateProfileString(szField, "State", pszBuffer, pszFilename); CurrField++; } + // Tell NSIS which control was activated, if any + wsprintf(pszBuffer, "%d", g_NotifyField); + WritePrivateProfileString("Settings", "State", pszBuffer, pszFilename); + FREE(pszBuffer); return true; @@ -503,7 +417,7 @@ int WINAPI ReadSettings(void) { pFields = (FieldType *)MALLOC(sizeof(FieldType)*2*nNumFields); } - for(nIdx = 0, nCtrlIdx = 0; nCtrlIdx < nNumFields; nCtrlIdx++, nIdx++) { + for (nIdx = 0, nCtrlIdx = 0; nCtrlIdx < nNumFields; nCtrlIdx++, nIdx++) { // Control types static TableEntry TypeTable[] = { { "LABEL", FIELD_LABEL }, @@ -524,87 +438,92 @@ int WINAPI ReadSettings(void) { #else { "LINK", FIELD_LABEL }, #endif + { "BUTTON", FIELD_BUTTON }, { NULL, 0 } }; // Control flags static TableEntry FlagTable[] = { - { "FILE_MUST_EXIST", OFN_FILEMUSTEXIST }, - { "PATH_MUST_EXIST", OFN_PATHMUSTEXIST }, - { "WARN_IF_EXIST", OFN_OVERWRITEPROMPT }, - { "PROMPT_CREATE", OFN_CREATEPROMPT }, { "RIGHT", FLAG_RIGHT }, - { "PASSWORD", FLAG_PASSWORD }, - { "DROPLIST", FLAG_DROPLIST }, - { "MULTISELECT", FLAG_MULTISELECT }, - { "EXTENDEDSELCT", FLAG_EXTENDEDSEL }, - { "FILE_EXPLORER", OFN_EXPLORER }, + { "WARN_IF_EXIST", OFN_OVERWRITEPROMPT }, { "FILE_HIDEREADONLY", OFN_HIDEREADONLY }, - { "RESIZETOFIT", FLAG_RESIZETOFIT }, - { "GROUP", FLAG_GROUP }, { "DISABLED", FLAG_DISABLED }, + { "GROUP", FLAG_GROUP }, { "NOTABSTOP", FLAG_NOTABSTOP }, + { "PASSWORD", FLAG_PASSWORD }, { "ONLY_NUMBERS", FLAG_ONLYNUMBERS }, { "MULTILINE", FLAG_MULTILINE }, + { "MULTISELECT", FLAG_MULTISELECT }, + { "EXTENDEDSELCT", FLAG_EXTENDEDSEL }, + { "FILE_MUST_EXIST", OFN_FILEMUSTEXIST }, + { "PATH_MUST_EXIST", OFN_PATHMUSTEXIST }, + { "PROMPT_CREATE", OFN_CREATEPROMPT }, + { "DROPLIST", FLAG_DROPLIST }, + { "RESIZETOFIT", FLAG_RESIZETOFIT }, + { "NOTIFY", FLAG_NOTIFY }, + { "REQ_SAVE", FLAG_SAVEAS }, + { "NOWORDWRAP", FLAG_NOWORDWRAP }, + { "FILE_EXPLORER", OFN_EXPLORER }, + { "WANTRETURN", FLAG_WANTRETURN }, { "VSCROLL", FLAG_VSCROLL }, { "HSCROLL", FLAG_HSCROLL }, - { "WANTRETURN", FLAG_WANTRETURN }, { "READONLY", FLAG_READONLY }, { NULL, 0 } }; + FieldType *pField = pFields + nIdx; wsprintf(szField, "Field %d", nCtrlIdx + 1); myGetProfileString(szField, "TYPE"); // Get the control type - pFields[nIdx].nType = LookupToken(TypeTable, szResult); - if (pFields[nIdx].nType == FIELD_INVALID) + pField->nType = LookupToken(TypeTable, szResult); + if (pField->nType == FIELD_INVALID) continue; // Lookup flags associated with the control type - pFields[nIdx].nFlags |= LookupToken(FlagTable, szResult); + pField->nFlags |= LookupToken(FlagTable, szResult); - pFields[nIdx].pszText = myGetProfileStringDup(szField, "TEXT"); + pField->pszText = myGetProfileStringDup(szField, "TEXT"); // Label Text - convert newline - if (pFields[nIdx].nType == FIELD_LABEL) { - ConvertNewLines(pFields[nIdx].pszText); + if (pField->nType == FIELD_LABEL) { + ConvertNewLines(pField->pszText); } // pszState must not be NULL! - myGetProfileString(szField, "STATE"); - pFields[nIdx].pszState = strdup(szResult); + myGetProfileString(szField, "State"); + pField->pszState = strdup(szResult); - pFields[nIdx].pszRoot = myGetProfileStringDup(szField, "ROOT"); + pField->pszRoot = myGetProfileStringDup(szField, "ROOT"); { int nResult = myGetProfileString(szField, "ListItems"); if (nResult) { // add an extra | character to the end to simplify the loop where we add the items. - pFields[nIdx].pszListItems = (char*)MALLOC(nResult + 2); - strcpy(pFields[nIdx].pszListItems, szResult); - pFields[nIdx].pszListItems[nResult] = '|'; - pFields[nIdx].pszListItems[nResult + 1] = '\0'; + pField->pszListItems = (char*)MALLOC(nResult + 2); + strcpy(pField->pszListItems, szResult); + pField->pszListItems[nResult] = '|'; + pField->pszListItems[nResult + 1] = '\0'; } } - pFields[nIdx].nMaxLength = myGetProfileInt(szField, "MaxLen", 0); - pFields[nIdx].nMinLength = myGetProfileInt(szField, "MinLen", 0); + pField->nMaxLength = myGetProfileInt(szField, "MaxLen", 0); + pField->nMinLength = myGetProfileInt(szField, "MinLen", 0); - pFields[nIdx].pszValidateText = myGetProfileStringDup(szField, "ValidateText"); + pField->pszValidateText = myGetProfileStringDup(szField, "ValidateText"); // ValidateText - convert newline - if (pFields[nIdx].pszValidateText) { - ConvertNewLines(pFields[nIdx].pszValidateText); + if (pField->pszValidateText) { + ConvertNewLines(pField->pszValidateText); } { int nResult = GetPrivateProfileString(szField, "Filter", "All Files|*.*", szResult, sizeof(szResult), pszFilename); if (nResult) { // add an extra | character to the end to simplify the loop where we add the items. - pFields[nIdx].pszFilter = (char*)MALLOC(nResult + 2); - strcpy(pFields[nIdx].pszFilter, szResult); - char *pszPos = pFields[nIdx].pszFilter; + pField->pszFilter = (char*)MALLOC(nResult + 2); + strcpy(pField->pszFilter, szResult); + char *pszPos = pField->pszFilter; while (*pszPos) { if (*pszPos == '|') *pszPos = '\0'; pszPos++; @@ -612,56 +531,31 @@ int WINAPI ReadSettings(void) { } } - pFields[nIdx].rect.left = myGetProfileInt(szField, "LEFT", 0); - pFields[nIdx].rect.right = myGetProfileInt(szField, "RIGHT", 0); - pFields[nIdx].rect.top = myGetProfileInt(szField, "TOP", 0); - pFields[nIdx].rect.bottom = myGetProfileInt(szField, "BOTTOM", 0); + pField->rect.left = myGetProfileInt(szField, "LEFT", 0); + pField->rect.right = myGetProfileInt(szField, "RIGHT", 0); + pField->rect.top = myGetProfileInt(szField, "TOP", 0); + pField->rect.bottom = myGetProfileInt(szField, "BOTTOM", 0); - if (myGetProfileString(szField, "Flags")) { - // append the | to make parsing a bit easier - if (lstrlen(szResult) pszStart) { - if (!stricmp("REQ_SAVE", pszStart)) { - pFields[nIdx].bSaveDlg = true; - } else { - // v1.3 converted this to a table lookup. - // I think it's a bit larger now, but we can - // add new flags with very little overhead. - pFields[nIdx].nFlags |= LookupToken(FlagTable, pszStart); - } - } - // jump to the next item, skip any redundant | characters - do { pszEnd++; } while (*pszEnd == '|'); - pszStart = pszEnd; - } - pszEnd++; - } - } + myGetProfileString(szField, "Flags"); + pField->nFlags |= LookupTokens(FlagTable, szResult); // Text color for LINK control, default is pure blue - //if (pFields[nIdx].nType == FIELD_LINK) - pFields[nIdx].hImage = (HANDLE)myGetProfileInt(szField, "TxtColor", RGB(0,0,255)); + //if (pField->nType == FIELD_LINK) + pField->hImage = (HANDLE)myGetProfileInt(szField, "TxtColor", RGB(0,0,255)); - pFields[nIdx].nControlID = 1200 + nIdx; - if (pFields[nIdx].nType == FIELD_FILEREQUEST || pFields[nIdx].nType == FIELD_DIRREQUEST) + pField->nControlID = 1200 + nIdx; + if (pField->nType == FIELD_FILEREQUEST || pField->nType == FIELD_DIRREQUEST) { FieldType *pNewField = &pFields[nIdx+1]; pNewField->nControlID = 1200 + nIdx + 1; - pNewField->nParentIdx = nIdx; pNewField->nType = FIELD_BROWSEBUTTON; - pNewField->nFlags = pFields[nIdx].nFlags & (FLAG_DISABLED | FLAG_NOTABSTOP); + pNewField->nFlags = pField->nFlags & (FLAG_DISABLED | FLAG_NOTABSTOP); pNewField->pszText = STRDUP(szBrowseButtonCaption); // needed for generic FREE - pNewField->rect.right = pFields[nIdx].rect.right; + pNewField->rect.right = pField->rect.right; pNewField->rect.left = pNewField->rect.right - BROWSE_WIDTH; - pNewField->rect.bottom = pFields[nIdx].rect.bottom; - pNewField->rect.top = pFields[nIdx].rect.top; - pFields[nIdx].rect.right = pNewField->rect.left - 3; + pNewField->rect.bottom = pField->rect.bottom; + pNewField->rect.top = pField->rect.top; + pField->rect.right = pNewField->rect.left - 3; nNumFields++; nIdx++; } @@ -674,26 +568,97 @@ int WINAPI ReadSettings(void) { LRESULT WINAPI WMCommandProc(HWND hWnd, UINT id, HWND hwndCtl, UINT codeNotify) { switch (codeNotify) { case BN_CLICKED: - { - int nIdx = FindControlIdx(id); - if (nIdx < 0) - break; - if (pFields[nIdx].nType == FIELD_BROWSEBUTTON) { - int nParentIdx = pFields[nIdx].nParentIdx; - switch(pFields[nParentIdx].nType) { - case FIELD_FILEREQUEST: - BrowseForFile(nParentIdx); - break; - case FIELD_DIRREQUEST: - BrowseForFolder(nParentIdx); + { + char szBrowsePath[MAX_PATH]; + int nIdx = FindControlIdx(id); + if (nIdx < 0) + break; + if (pFields[nIdx].nType == FIELD_BROWSEBUTTON) + --nIdx; + FieldType *pField = pFields + nIdx; + switch (pField->nType) { + case FIELD_FILEREQUEST: { + OPENFILENAME ofn={0,}; + + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hConfigWindow; + ofn.lpstrFilter = pField->pszFilter; + ofn.lpstrFile = szBrowsePath; + ofn.nMaxFile = sizeof(szBrowsePath); + ofn.Flags = pField->nFlags & (OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_CREATEPROMPT | OFN_EXPLORER); + + GetWindowText(pField->hwnd, szBrowsePath, sizeof(szBrowsePath)); + + tryagain: + if ((pField->nFlags & FLAG_SAVEAS) ? GetSaveFileName(&ofn) : GetOpenFileName(&ofn)) { + SetWindowText(pField->hwnd, szBrowsePath); break; } + else if (szBrowsePath[0] && CommDlgExtendedError() == FNERR_INVALIDFILENAME) { + szBrowsePath[0] = '\0'; + goto tryagain; + } + break; - } else if (pFields[nIdx].nType == FIELD_LINK) { - ShellExecute(hMainWindow, NULL, pFields[nIdx].pszState, NULL, NULL, SW_SHOWDEFAULT); } + + case FIELD_DIRREQUEST: { + BROWSEINFO bi; + + bi.hwndOwner = hConfigWindow; + bi.pidlRoot = NULL; + bi.pszDisplayName = szBrowsePath; + bi.lpszTitle = pField->pszText; +#ifndef BIF_NEWDIALOGSTYLE +#define BIF_NEWDIALOGSTYLE 0x0040 +#endif + bi.ulFlags = BIF_STATUSTEXT | BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE; + bi.lpfn = BrowseCallbackProc; + bi.lParam = nIdx; + bi.iImage = 0; + + if (pField->pszRoot) { + LPSHELLFOLDER sf; + ULONG eaten; + LPITEMIDLIST root; + int ccRoot = (lstrlen(pField->pszRoot) * 2) + 2; + LPWSTR pwszRoot = (LPWSTR) MALLOC(ccRoot); + MultiByteToWideChar(CP_ACP, 0, pField->pszRoot, -1, pwszRoot, ccRoot); + SHGetDesktopFolder(&sf); + sf->ParseDisplayName(hConfigWindow, NULL, pwszRoot, &eaten, &root, NULL); + bi.pidlRoot = root; + sf->Release(); + FREE(pwszRoot); + } +// CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + LPITEMIDLIST pResult = SHBrowseForFolder(&bi); + if (!pResult) + break; + + if (SHGetPathFromIDList(pResult, szBrowsePath)) { + SetWindowText(pField->hwnd, szBrowsePath); + } + + LPMALLOC pMalloc; + if (!SHGetMalloc(&pMalloc)) { + pMalloc->Free(pResult); + } + + break; + } + + case FIELD_LINK: + ShellExecute(hMainWindow, NULL, pField->pszState, NULL, NULL, SW_SHOWDEFAULT); + break; } - break; + + if (pField->nFlags & FLAG_NOTIFY) { + // Remember which control was activated then pretend the user clicked Next + g_NotifyField = nIdx + 1; + FORWARD_WM_COMMAND(hMainWindow, IDOK, hNextButton, codeNotify, mySendMessage); + } + } + break; } return 0; } @@ -710,6 +675,7 @@ BOOL CALLBACK ParentWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPara { // Get the settings ready for the leave function verification SaveSettings(); + g_NotifyField = 0; // Reset the record of activated control } bRes = CallWindowProc((long (__stdcall *)(struct HWND__ *,unsigned int,unsigned int,long))lpWndProcOld,hwnd,message,wParam,lParam); if (message == WM_NOTIFY_OUTER_NEXT && !bRes) @@ -744,6 +710,7 @@ BOOL CALLBACK cfgDlgProc(HWND hwndDlg, if (nIdx < 0) break; + FieldType *pField = pFields + nIdx; #ifdef IO_LINK_UNDERLINED GetObject(GetCurrentObject(lpdis->hDC, OBJ_FONT), sizeof(lf), &lf); @@ -757,24 +724,24 @@ BOOL CALLBACK cfgDlgProc(HWND hwndDlg, if ( ( lpdis->itemState & ODS_FOCUS && lpdis->itemAction & ODA_DRAWENTIRE) || (lpdis->itemAction & ODA_FOCUS) || (lpdis->itemAction & ODA_SELECT)) - DrawFocusRect(lpdis->hDC, &pFields[nIdx].rect); + DrawFocusRect(lpdis->hDC, &pField->rect); - SetTextColor(lpdis->hDC, (COLORREF)pFields[nIdx].hImage); + SetTextColor(lpdis->hDC, (COLORREF)pField->hImage); - pFields[nIdx].rect = lpdis->rcItem; + pField->rect = lpdis->rcItem; // Calculate needed size of the control - DrawText(lpdis->hDC, pFields[nIdx].pszText, -1, &pFields[nIdx].rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_CALCRECT); - pFields[nIdx].rect.right += 4; - pFields[nIdx].rect.bottom = lpdis->rcItem.bottom; + DrawText(lpdis->hDC, pField->pszText, -1, &pField->rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_CALCRECT); + pField->rect.right += 4; + pField->rect.bottom = lpdis->rcItem.bottom; // Resize but don't move - SetWindowPos(lpdis->hwndItem, NULL, 0, 0, pFields[nIdx].rect.right - pFields[nIdx].rect.left, - pFields[nIdx].rect.bottom - pFields[nIdx].rect.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); + SetWindowPos(lpdis->hwndItem, NULL, 0, 0, pField->rect.right - pField->rect.left, + pField->rect.bottom - pField->rect.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); // Draw the text - lpdis->rcItem = pFields[nIdx].rect; + lpdis->rcItem = pField->rect; // Add little margin to avoid focus rect over text lpdis->rcItem.right += 2; lpdis->rcItem.left += 2; - DrawText(lpdis->hDC, pFields[nIdx].pszText, -1, &lpdis->rcItem, DT_LEFT | DT_VCENTER | DT_SINGLELINE ); + DrawText(lpdis->hDC, pField->pszText, -1, &lpdis->rcItem, DT_LEFT | DT_VCENTER | DT_SINGLELINE ); #ifdef IO_LINK_UNDERLINED DeleteObject(SelectObject(lpdis->hDC, OldFont)); #endif @@ -809,6 +776,7 @@ int WINAPI StaticLINKWindowProc(HWND hWin, UINT uMsg, LPARAM wParam, WPARAM lPar int StaticField = FindControlIdx(GetDlgCtrlID(hWin)); if (StaticField < 0) return 0; + FieldType *pField = pFields + StaticField; switch(uMsg) { @@ -817,9 +785,9 @@ int WINAPI StaticLINKWindowProc(HWND hWin, UINT uMsg, LPARAM wParam, WPARAM lPar case WM_KEYDOWN: { if ( wParam == VK_RETURN ) - WMCommandProc(hMainWindow, pFields[StaticField].nControlID, pFields[StaticField].hwnd, BN_CLICKED); + WMCommandProc(hMainWindow, pField->nControlID, pField->hwnd, BN_CLICKED); else if ( wParam == VK_TAB ) - SendMessage(hMainWindow, WM_NEXTDLGCTL, GetKeyState(VK_SHIFT) & 0x8000, FALSE); + mySendMessage(hMainWindow, WM_NEXTDLGCTL, GetKeyState(VK_SHIFT) & 0x8000, FALSE); } break; case WM_SETCURSOR: @@ -835,7 +803,7 @@ int WINAPI StaticLINKWindowProc(HWND hWin, UINT uMsg, LPARAM wParam, WPARAM lPar } } } - return CallWindowProc((WNDPROC)pFields[StaticField].nParentIdx, hWin, uMsg, wParam, lParam); + return CallWindowProc((WNDPROC)pField->nParentIdx, hWin, uMsg, wParam, lParam); } #endif @@ -843,12 +811,11 @@ int old_cancel_visible; int WINAPI createCfgDlg() { - UINT nAddMsg, nFindMsg, nSetSelMsg; - g_is_back=0; g_is_cancel=0; - if (!hMainWindow) + HWND mainwnd = hMainWindow; + if (!mainwnd) { popstring(NULL); pushstring("error finding mainwnd"); @@ -862,7 +829,7 @@ int WINAPI createCfgDlg() return 1; } - HWND childwnd=GetDlgItem(hMainWindow,nRectId); + HWND childwnd=GetDlgItem(mainwnd,nRectId); if (!childwnd) { popstring(NULL); @@ -870,9 +837,9 @@ int WINAPI createCfgDlg() return 1; } - hCancelButton = GetDlgItem(hMainWindow,IDCANCEL); - hInitialFocus = hNextButton = GetDlgItem(hMainWindow,IDOK); - hBackButton = GetDlgItem(hMainWindow,3); + hCancelButton = GetDlgItem(mainwnd,IDCANCEL); + hInitialFocus = hNextButton = GetDlgItem(mainwnd,IDOK); + hBackButton = GetDlgItem(mainwnd,3); if (pszCancelButtonText) SetWindowText(hCancelButton,pszCancelButtonText); if (pszNextButtonText) SetWindowText(hNextButton,pszNextButtonText); @@ -882,16 +849,16 @@ int WINAPI createCfgDlg() if (bCancelEnabled!=-1) EnableWindow(hCancelButton,bCancelEnabled); if (bCancelShow!=-1) old_cancel_visible=ShowWindow(hCancelButton,bCancelShow?SW_SHOWNA:SW_HIDE); - HFONT hFont = (HFONT)SendMessage(hMainWindow, WM_GETFONT, 0, 0); + HFONT hFont = (HFONT)mySendMessage(mainwnd, WM_GETFONT, 0, 0); RECT dialog_r; int width; - hConfigWindow=CreateDialog(m_hInstance,MAKEINTRESOURCE(IDD_DIALOG1),hMainWindow,cfgDlgProc); + hConfigWindow=CreateDialog(m_hInstance,MAKEINTRESOURCE(IDD_DIALOG1),mainwnd,cfgDlgProc); if (hConfigWindow) { GetWindowRect(childwnd,&dialog_r); - ScreenToClient(hMainWindow,(LPPOINT)&dialog_r); - ScreenToClient(hMainWindow,((LPPOINT)&dialog_r)+1); + ScreenToClient(mainwnd,(LPPOINT)&dialog_r); + ScreenToClient(mainwnd,((LPPOINT)&dialog_r)+1); width = dialog_r.right-dialog_r.left; SetWindowPos( hConfigWindow, @@ -903,7 +870,7 @@ int WINAPI createCfgDlg() SWP_NOZORDER|SWP_NOACTIVATE ); // Sets the font of IO window to be the same as the main window - SendMessage(hConfigWindow, WM_SETFONT, (WPARAM)hFont, TRUE); + mySendMessage(hConfigWindow, WM_SETFONT, (WPARAM)hFont, TRUE); } else { @@ -1002,41 +969,46 @@ int WINAPI createCfgDlg() DEFAULT_STYLES | WS_TABSTOP | BS_OWNERDRAW | BS_RIGHT, 0, 0 }, + { "BUTTON", // FIELD_BUTTON + DEFAULT_STYLES | WS_TABSTOP, + DEFAULT_STYLES | WS_TABSTOP | BS_RIGHT, + 0, + 0 } }; - int nType = pFields[nIdx].nType; + FieldType *pField = pFields + nIdx; #undef DEFAULT_STYLES - if (nType < 1 || nType > (sizeof(ClassTable) / sizeof(ClassTable[0]))) + if (pField->nType < 1 || pField->nType > (sizeof(ClassTable) / sizeof(ClassTable[0]))) continue; DWORD dwStyle, dwExStyle; if (bRTL) { - dwStyle = ClassTable[pFields[nIdx].nType - 1].dwRTLStyle; - dwExStyle = ClassTable[pFields[nIdx].nType - 1].dwRTLExStyle; + dwStyle = ClassTable[pField->nType - 1].dwRTLStyle; + dwExStyle = ClassTable[pField->nType - 1].dwRTLExStyle; } else { - dwStyle = ClassTable[pFields[nIdx].nType - 1].dwStyle; - dwExStyle = ClassTable[pFields[nIdx].nType - 1].dwExStyle; + dwStyle = ClassTable[pField->nType - 1].dwStyle; + dwExStyle = ClassTable[pField->nType - 1].dwExStyle; } // Convert from dialog units RECT rect; - rect.left = MulDiv(pFields[nIdx].rect.left, baseUnitX, 4); - rect.right = MulDiv(pFields[nIdx].rect.right, baseUnitX, 4); - rect.top = MulDiv(pFields[nIdx].rect.top, baseUnitY, 8); - rect.bottom = MulDiv(pFields[nIdx].rect.bottom, baseUnitY, 8); + rect.left = MulDiv(pField->rect.left, baseUnitX, 4); + rect.right = MulDiv(pField->rect.right, baseUnitX, 4); + rect.top = MulDiv(pField->rect.top, baseUnitY, 8); + rect.bottom = MulDiv(pField->rect.bottom, baseUnitY, 8); - if (pFields[nIdx].rect.left < 0) + if (pField->rect.left < 0) rect.left += dialog_r.right - dialog_r.left; - if (pFields[nIdx].rect.right < 0) + if (pField->rect.right < 0) rect.right += dialog_r.right - dialog_r.left; - if (pFields[nIdx].rect.top < 0) + if (pField->rect.top < 0) rect.top += dialog_r.bottom - dialog_r.top; - if (pFields[nIdx].rect.bottom < 0) + if (pField->rect.bottom < 0) rect.bottom += dialog_r.bottom - dialog_r.top; if (bRTL) { @@ -1045,61 +1017,63 @@ int WINAPI createCfgDlg() rect.left = width - right; } - char *title = pFields[nIdx].pszText; - switch (nType) { + char *title = pField->pszText; + switch (pField->nType) { case FIELD_ICON: case FIELD_BITMAP: title = NULL; // otherwise it is treated as the name of a resource break; case FIELD_CHECKBOX: case FIELD_RADIOBUTTON: - if (pFields[nIdx].nFlags & FLAG_RIGHT) + case FIELD_BUTTON: + if (pField->nFlags & FLAG_RIGHT) dwStyle |= BS_RIGHTBUTTON; break; + case FIELD_TEXT: case FIELD_FILEREQUEST: case FIELD_DIRREQUEST: - case FIELD_TEXT: - if (pFields[nIdx].nFlags & FLAG_PASSWORD) + if (pField->nFlags & FLAG_PASSWORD) dwStyle |= ES_PASSWORD; - if (pFields[nIdx].nFlags & FLAG_ONLYNUMBERS) + if (pField->nFlags & FLAG_ONLYNUMBERS) dwStyle |= ES_NUMBER; - if (pFields[nIdx].nFlags & FLAG_MULTILINE) + if (pField->nFlags & FLAG_MULTILINE) { dwStyle |= ES_MULTILINE | ES_AUTOVSCROLL; // Enable word-wrap unless we have a horizontal scroll bar - if (!(pFields[nIdx].nFlags & FLAG_HSCROLL)) + // or it has been explicitly disallowed + if (!(pField->nFlags & (FLAG_HSCROLL | FLAG_NOWORDWRAP))) dwStyle &= ~ES_AUTOHSCROLL; - ConvertNewLines(pFields[nIdx].pszState); + ConvertNewLines(pField->pszState); } - if (pFields[nIdx].nFlags & FLAG_WANTRETURN) + if (pField->nFlags & FLAG_WANTRETURN) dwStyle |= ES_WANTRETURN; - if (pFields[nIdx].nFlags & FLAG_VSCROLL) + if (pField->nFlags & FLAG_VSCROLL) dwStyle |= WS_VSCROLL; - if (pFields[nIdx].nFlags & FLAG_HSCROLL) + if (pField->nFlags & FLAG_HSCROLL) dwStyle |= WS_HSCROLL; - if (pFields[nIdx].nFlags & FLAG_READONLY) + if (pField->nFlags & FLAG_READONLY) dwStyle |= ES_READONLY; - title = pFields[nIdx].pszState; + title = pField->pszState; break; case FIELD_COMBOBOX: - dwStyle |= (pFields[nIdx].nFlags & FLAG_DROPLIST) ? CBS_DROPDOWNLIST : CBS_DROPDOWN; - title = pFields[nIdx].pszState; + dwStyle |= (pField->nFlags & FLAG_DROPLIST) ? CBS_DROPDOWNLIST : CBS_DROPDOWN; + title = pField->pszState; break; case FIELD_LISTBOX: - if (pFields[nIdx].nFlags & FLAG_EXTENDEDSEL) + if (pField->nFlags & FLAG_EXTENDEDSEL) dwStyle |= LBS_EXTENDEDSEL; - if (pFields[nIdx].nFlags & FLAG_MULTISELECT) + if (pField->nFlags & FLAG_MULTISELECT) dwStyle |= LBS_MULTIPLESEL; break; } - if (pFields[nIdx].nFlags & FLAG_DISABLED) dwStyle |= WS_DISABLED; - if (pFields[nIdx].nFlags & FLAG_GROUP) dwStyle |= WS_GROUP; - if (pFields[nIdx].nFlags & FLAG_NOTABSTOP) dwStyle &= ~WS_TABSTOP; + if (pField->nFlags & FLAG_DISABLED) dwStyle |= WS_DISABLED; + if (pField->nFlags & FLAG_GROUP) dwStyle |= WS_GROUP; + if (pField->nFlags & FLAG_NOTABSTOP) dwStyle &= ~WS_TABSTOP; - HWND hwCtrl = pFields[nIdx].hwnd = CreateWindowEx( + HWND hwCtrl = pField->hwnd = CreateWindowEx( dwExStyle, - ClassTable[pFields[nIdx].nType - 1].pszClass, + ClassTable[pField->nType - 1].pszClass, title, dwStyle, rect.left, @@ -1107,126 +1081,142 @@ int WINAPI createCfgDlg() rect.right - rect.left, rect.bottom - rect.top, hConfigWindow, - (HMENU)pFields[nIdx].nControlID, + (HMENU)pField->nControlID, m_hInstance, NULL ); if (hwCtrl) { // Sets the font of IO window to be the same as the main window - SendMessage(hwCtrl, WM_SETFONT, (WPARAM)hFont, TRUE); + mySendMessage(hwCtrl, WM_SETFONT, (WPARAM)hFont, TRUE); // Set initial focus to the first appropriate field if ((hInitialFocus == hNextButton) && (dwStyle & WS_TABSTOP)) hInitialFocus = hwCtrl; // make sure we created the window, then set additional attributes - //if (pFields[nIdx].nMaxLength > 0) { - switch (nType) { - case FIELD_TEXT: - SendMessage(hwCtrl, WM_SETTEXT, 0, (LPARAM)title); - case FIELD_DIRREQUEST: - case FIELD_FILEREQUEST: - SendMessage(hwCtrl, EM_LIMITTEXT, (WPARAM)pFields[nIdx].nMaxLength, (LPARAM)0); - break; - } - //} - if ((nType == FIELD_CHECKBOX) || (nType == FIELD_RADIOBUTTON)) { - if (pFields[nIdx].pszState[0] == '1') - { - SendMessage(hwCtrl, BM_SETCHECK, (WPARAM)BST_CHECKED, 0); - } - } else if (pFields[nIdx].pszListItems && ( - ((nType == FIELD_COMBOBOX) && (nAddMsg = CB_ADDSTRING) - && (nFindMsg = CB_FINDSTRINGEXACT) && (nSetSelMsg = CB_SETCURSEL)) || - ((nType == FIELD_LISTBOX ) && (nAddMsg = LB_ADDSTRING) - && (nFindMsg = LB_FINDSTRINGEXACT) && (nSetSelMsg = LB_SETCURSEL)) - )) { - // if this is a listbox or combobox, we need to add the list items. - char *pszStart, *pszEnd, *pszList; - pszStart = pszEnd = pszList = STRDUP(pFields[nIdx].pszListItems); - while ((*pszEnd) && (*pszStart)) { - if (*pszEnd == '|') { - *pszEnd = '\0'; - if (pszEnd > pszStart) { - SendMessage(hwCtrl, nAddMsg, 0, (LPARAM)pszStart); + switch (pField->nType) { + case FIELD_TEXT: + mySendMessage(hwCtrl, WM_SETTEXT, 0, (LPARAM)title); + // no break; + case FIELD_FILEREQUEST: + case FIELD_DIRREQUEST: + mySendMessage(hwCtrl, EM_LIMITTEXT, (WPARAM)pField->nMaxLength, (LPARAM)0); + break; + + case FIELD_CHECKBOX: + case FIELD_RADIOBUTTON: + if (pField->pszState[0] == '1') + mySendMessage(hwCtrl, BM_SETCHECK, (WPARAM)BST_CHECKED, 0); + break; + + case FIELD_COMBOBOX: + case FIELD_LISTBOX: + // if this is a listbox or combobox, we need to add the list items. + if (pField->pszListItems) { + UINT nAddMsg, nFindMsg, nSetSelMsg; + if (pField->nType == FIELD_COMBOBOX) { + nAddMsg = CB_ADDSTRING; + nFindMsg = CB_FINDSTRINGEXACT; + nSetSelMsg = CB_SETCURSEL; } - // jump to the next item, skip any redundant | characters - do { pszEnd++; } while (*pszEnd == '|'); - pszStart = pszEnd; - } - pszEnd++; - } - FREE(pszList); - if (pFields[nIdx].pszState) { - if (pFields[nIdx].nFlags & (FLAG_MULTISELECT|FLAG_EXTENDEDSEL) && nFindMsg == LB_FINDSTRINGEXACT) { - SendMessage(hwCtrl, LB_SETSEL, FALSE, -1); - pszStart = pszEnd = pFields[nIdx].pszState; - while (*pszStart) { - char cLast = *pszEnd; - if (*pszEnd == '|') *pszEnd = '\0'; - if (!*pszEnd) { + else { + nAddMsg = LB_ADDSTRING; + nFindMsg = LB_FINDSTRINGEXACT; + nSetSelMsg = LB_SETCURSEL; + } + char *pszStart, *pszEnd, *pszList; + pszStart = pszEnd = pszList = STRDUP(pField->pszListItems); + while ((*pszEnd) && (*pszStart)) { + if (*pszEnd == '|') { + *pszEnd = '\0'; if (pszEnd > pszStart) { - int nItem = SendMessage(hwCtrl, nFindMsg, -1, (LPARAM)pszStart); - if (nItem != CB_ERR) { // CB_ERR == LB_ERR == -1 - SendMessage(hwCtrl, LB_SETSEL, TRUE, nItem); - } - } - if (cLast) { - do { - pszEnd++; - } while (*pszEnd == '|'); + mySendMessage(hwCtrl, nAddMsg, 0, (LPARAM)pszStart); } + // jump to the next item, skip any redundant | characters + do { pszEnd++; } while (*pszEnd == '|'); pszStart = pszEnd; } pszEnd++; } - } - else { - int nItem = SendMessage(hwCtrl, nFindMsg, -1, (LPARAM)pFields[nIdx].pszState); - if (nItem != CB_ERR) { // CB_ERR == LB_ERR == -1 - SendMessage(hwCtrl, nSetSelMsg, nItem, 0); + FREE(pszList); + if (pField->pszState) { + if (pField->nFlags & (FLAG_MULTISELECT|FLAG_EXTENDEDSEL) && nFindMsg == LB_FINDSTRINGEXACT) { + mySendMessage(hwCtrl, LB_SETSEL, FALSE, -1); + pszStart = pszEnd = pField->pszState; + while (*pszStart) { + char cLast = *pszEnd; + if (*pszEnd == '|') *pszEnd = '\0'; + if (!*pszEnd) { + if (pszEnd > pszStart) { + int nItem = mySendMessage(hwCtrl, nFindMsg, -1, (LPARAM)pszStart); + if (nItem != CB_ERR) { // CB_ERR == LB_ERR == -1 + mySendMessage(hwCtrl, LB_SETSEL, TRUE, nItem); + } + } + if (cLast) { + do { + pszEnd++; + } while (*pszEnd == '|'); + } + pszStart = pszEnd; + } + pszEnd++; + } + } + else { + int nItem = mySendMessage(hwCtrl, nFindMsg, -1, (LPARAM)pField->pszState); + if (nItem != CB_ERR) { // CB_ERR == LB_ERR == -1 + mySendMessage(hwCtrl, nSetSelMsg, nItem, 0); + } + } } } - } - } else if (nType == FIELD_BITMAP || nType == FIELD_ICON) { - WPARAM nImageType = nType == FIELD_BITMAP ? IMAGE_BITMAP : IMAGE_ICON; - LPARAM nImage = 0; - if (pFields[nIdx].pszText) { - pFields[nIdx].hImage = LoadImage( - m_hInstance, - pFields[nIdx].pszText, + break; + + case FIELD_ICON: + case FIELD_BITMAP: + { + WPARAM nImageType = pField->nType == FIELD_BITMAP ? IMAGE_BITMAP : IMAGE_ICON; + LPARAM nImage = 0; + if (pField->pszText) { + pField->hImage = LoadImage( + m_hInstance, + pField->pszText, + nImageType, + (pField->nFlags & FLAG_RESIZETOFIT) + ? (rect.right - rect.left) + : 0, + (pField->nFlags & FLAG_RESIZETOFIT) + ? (rect.bottom - rect.top) + : 0, + LR_LOADFROMFILE + ); + nImage = (LPARAM)pField->hImage; + } + else + nImage = (LPARAM)LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(103)); + mySendMessage( + hwCtrl, + STM_SETIMAGE, nImageType, - (pFields[nIdx].nFlags & FLAG_RESIZETOFIT) - ? (rect.right - rect.left) - : 0, - (pFields[nIdx].nFlags & FLAG_RESIZETOFIT) - ? (rect.bottom - rect.top) - : 0, - LR_LOADFROMFILE + nImage ); - nImage = (LPARAM)pFields[nIdx].hImage; + break; } - else - nImage = (LPARAM)LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(103)); - SendMessage( - hwCtrl, - STM_SETIMAGE, - nImageType, - nImage - ); - } + #ifdef IO_ENABLE_LINK - else if (nType == FIELD_LINK) { - pFields[nIdx].nParentIdx = SetWindowLong(hwCtrl, GWL_WNDPROC, (long)StaticLINKWindowProc); - } + case FIELD_LINK: + pField->nParentIdx = SetWindowLong(hwCtrl, GWL_WNDPROC, (long)StaticLINKWindowProc); + break; #endif + } } } if (pszTitle) - SetWindowText(hMainWindow,pszTitle); + SetWindowText(mainwnd,pszTitle); pFilenameStackEntry = *g_stacktop; *g_stacktop = (*g_stacktop)->next; - char tmp[32]; + static char tmp[32]; wsprintf(tmp,"%d",hConfigWindow); pushstring(tmp); return 0; @@ -1237,11 +1227,11 @@ void WINAPI showCfgDlg() lpWndProcOld = (void *) SetWindowLong(hMainWindow,DWL_DLGPROC,(long)ParentWndProc); // Tell NSIS to remove old inner dialog and pass handle of the new inner dialog - SendMessage(hMainWindow, WM_NOTIFY_CUSTOM_READY, (WPARAM)hConfigWindow, 0); + mySendMessage(hMainWindow, WM_NOTIFY_CUSTOM_READY, (WPARAM)hConfigWindow, 0); ShowWindow(hConfigWindow, SW_SHOWNA); SetFocus(hInitialFocus); - g_done=0; + g_done = g_NotifyField = 0; while (!g_done) { MSG msg; @@ -1269,16 +1259,17 @@ void WINAPI showCfgDlg() int i = nNumFields; while (i--) { - FREE(pFields[i].pszText); - FREE(pFields[i].pszState); - FREE(pFields[i].pszListItems); - FREE(pFields[i].pszFilter); - FREE(pFields[i].pszRoot); - if (pFields[i].nType == FIELD_BITMAP) { - DeleteObject(pFields[i].hImage); + FieldType *pField = pFields + i; + FREE(pField->pszText); + FREE(pField->pszState); + FREE(pField->pszListItems); + FREE(pField->pszFilter); + FREE(pField->pszRoot); + if (pField->nType == FIELD_BITMAP) { + DeleteObject(pField->hImage); } - if (pFields[i].nType == FIELD_ICON) { - DestroyIcon((HICON)pFields[i].hImage); + if (pField->nType == FIELD_ICON) { + DestroyIcon((HICON)pField->hImage); } } FREE(pFields); diff --git a/Contrib/InstallOptions/Readme.html b/Contrib/InstallOptions/Readme.html index 070db650..e5149861 100644 --- a/Contrib/InstallOptions/Readme.html +++ b/Contrib/InstallOptions/Readme.html @@ -54,14 +54,14 @@ h1 text-align: center; margin: 20px; } - + h2 { font-size: 165%; color: #7A7272; font-weight: normal; } - + h3 { font-size: 150%; @@ -85,13 +85,13 @@ a:link, a:visited, a:active color: #294F75; text-decoration: none; } - + a:hover { color: #182634; text-decoration: underline; } - + .subtable { border: 0px; @@ -199,6 +199,14 @@ according to a different rect than NSIS's dialogs rect. If 1 is specified the dialog will be mirrored and all texts will be aligned to the right. Use NSIS's $(^RTL) to fill this field, it's the easiest way. + +State +(output) +This is not something you have to supply yourself but is set by +InstallOptions, before calling your custom page validation function, to the field +number of the custom Button control (or other control having the Notify flag) the +user pressed, if any. +

Each field section has the heading "Field #" where # must be sequential numbers from 1 to NumFields. Each Field section can contain the following values:

@@ -209,14 +217,14 @@ NumFields. Each Field section can contain the following values:

Type of control to be created. Valid values are "Label", "Text", "Password", "Combobox", "DropList", "Listbox", "CheckBox", "RadioButton", "FileRequest", "DirRequest" -"Icon", "Bitmap" or "GroupBox".
+"Icon", "Bitmap", "GroupBox", "Link" or "Button".

A "Label" is used to display static text. (i.e. a caption for a textbox)
A "Text" and "Password" accept text input from the user. "Password" masks the input with * characters.
A "Combobox" allows the user to type text not in the popup list, a "Droplist" only allows selection of items in the list.
-A "listbox" shows multiple items and can optionally allow the user to select more than one +A "Listbox" shows multiple items and can optionally allow the user to select more than one item.
A "CheckBox" control displays a check box with label.
A "RadioButton" control displays a radio button with label.
@@ -228,7 +236,9 @@ An "Icon" control displays an icon. Use no Text to use the installer ic A "Bitmap" control displays a bitmap.
A "GroupBox" control displays a frame to group controls.
A "Link" control displays a static hot text, when the user click the control the contents -of State (e.g. http://...) will be executed using ShellExecute
+of State (e.g. http://...) will be executed using ShellExecute
+A "Button" control displays a push button that your NSIS script can act on +when pressed. See the "NOTIFY" flag for more information. Text @@ -271,7 +281,7 @@ You should not use this on a "combobox" since the user can not control selected.
This should be set to a maximum of 260 for "FileRequest" and "DirRequest" controls.
-Ignored on "label" controls. +Ignored on "Label" controls. MinLen @@ -444,9 +454,16 @@ carriage return be inserted when the user presses the ENTER key while entering t box. +NOWORDWRAP +Used by "Text" controls with multiple-line. Disables the +word-wrap that occurs when long lines are entered. Long lines instead scroll off to the +side. Specifying the HSCROLL flag also has this effect. + + + HSCROLL Used by "Text" controls with multiple-line. Show a horizontal -scrollbar. +scrollbar and disable word-wrap. VSCROLL @@ -458,6 +475,16 @@ scrollbar. Used by "Text" controls. Prevents the user from entering or editing text in the edit control, but allow the user to select and copy the text. + +NOTIFY +Used by "Button", "CheckBox" and "RadioButton" +controls. Causes InstallOptions to call your NSIS custom page validation/leave function +whenever the button is pressed. Your validation/leave function can read the "State" +value from the "Settings" section to determine which custom button has been +pressed, if any, and perform some appropriate action followed by an Abort instruction +(to tell NSIS to return to the page). The Contrib\InstallOptions folder contains an +example script showing how this might be used. + @@ -691,6 +718,16 @@ FunctionEnd

Version history

+