DLL version 2.4 (1/4/2004)

* Initial focus is set in "initDialog" making it possible to override it from NSIS prior to calling "show"
- When initial focus is to a Text field InstallOptions now follows standard Windows behaviour by having the text selected
- Label and other static fields no longer have State= written to the INI file when leaving the dialog
- NOTIFY flag can now be used with Link fields (State should be omitted in this case)
- Likewise, State can now be used with Button fields (behaves the same as with Link fields)
- NOTIFY flag can also now be used with ListBox and DropList fields to have NSIS notified when the selection changes
- Meaning of RIGHT flag is now reversed in right-to-left language mode
- HSCROLL and VSCROLL flags are no longer restricted to Text fields
- Various Link field fixes
- Text box colour bug fix


git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@3350 212acab6-be3b-0410-9dea-997c60f758d6
This commit is contained in:
eccles 2004-01-04 14:06:39 +00:00
parent 1b2abf06de
commit e1c4b80991
7 changed files with 372 additions and 273 deletions

View file

@ -1,8 +1,20 @@
DLL version 2.4 (1/4/2004)
* Initial focus is set in "initDialog" making it possible to override it from NSIS prior to calling "show"
* When initial focus is to a Text field InstallOptions now follows standard Windows behaviour by having the text selected
* Label and other static fields no longer have State= written to the INI file when leaving the dialog
* NOTIFY flag can now be used with Link fields (State should be omitted in this case)
* Likewise, State can now be used with Button fields (behaves the same as with Link fields)
* NOTIFY flag can also now be used with ListBox and DropList fields to have NSIS notified when the selection changes
* Meaning of RIGHT flag is now reversed in right-to-left language mode
* HSCROLL and VSCROLL flags are no longer restricted to Text fields
* Various Link field fixes
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
* Better RTL support
DLL version 2.2 (6/10/2003)
* Added New control type LINK

View file

@ -18,6 +18,15 @@
#include "../exdll/exdll.h"
#undef popstring
// Use for functions only called from one place to possibly reduce some code
// size. Allows the source code to remain readable by leaving the function
// intact.
#ifdef _MSC_VER
#define INLINE __forceinline
#else
#define INLINE inline
#endif
void *WINAPI MALLOC(int len) { return (void*)GlobalAlloc(GPTR,len); }
void WINAPI FREE(void *d) { if (d) GlobalFree((HGLOBAL)d); }
@ -62,57 +71,37 @@ char *WINAPI STRDUP(const char *c)
//---------------------------------------------------------------------
// settings
// crashes on windows 98 - #define IO_ENABLE_LINK
#define IO_ENABLE_LINK
//#define IO_LINK_UNDERLINED // Uncomment to show links text underlined
//---------------------------------------------------------------------
// general flags
#define FLAG_RIGHT 0x00000001
// Flags
// OFN_OVERWRITEPROMPT 0x00000002
// OFN_HIDEREADONLY 0x00000004
#define FLAG_DISABLED 0x00000008
#define FLAG_GROUP 0x00000010
#define FLAG_NOTABSTOP 0x00000020
// text box flags
#define FLAG_PASSWORD 0x00000040
#define FLAG_ONLYNUMBERS 0x00000080
#define FLAG_MULTILINE 0x00000100
// listbox flags
#define FLAG_MULTISELECT 0x00000200
#define FLAG_EXTENDEDSEL 0x00000400
// OFN_PATHMUSTEXIST 0x00000800
// OFN_FILEMUSTEXIST 0x00001000
// OFN_CREATEPROMPT 0x00002000
// combobox flags
#define FLAG_DROPLIST 0x00004000
// 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
#define FLAG_WANTRETURN 0x00100000
#define FLAG_VSCROLL 0x00200000
#define FLAG_HSCROLL 0x00400000
#define FLAG_READONLY 0x00800000
// LBS_NOTIFY 0x00000001 // LISTBOX/CHECKBOX/RADIOBUTTON/BUTTON/LINK - Notify NSIS script when control is "activated" (exact meaning depends on the type of control)
// OFN_OVERWRITEPROMPT 0x00000002 // FILEREQUEST
// OFN_HIDEREADONLY 0x00000004 // FILEREQUEST
// LBS_MULTIPLESEL 0x00000008 // LISTBOX
#define FLAG_READONLY 0x00000010 // TEXT/FILEREQUEST/DIRREQUEST
// BS_LEFTTEXT 0x00000020 // CHECKBOX/RADIOBUTTON
#define FLAG_PASSWORD 0x00000040 // TEXT/FILEREQUEST/DIRREQUEST
#define FLAG_ONLYNUMBERS 0x00000080 // TEXT/FILEREQUEST/DIRREQUEST
#define FLAG_MULTILINE 0x00000100 // TEXT/FILEREQUEST/DIRREQUEST
#define FLAG_NOWORDWRAP 0x00000200 // TEXT/FILEREQUEST/DIRREQUEST - Disable word-wrap in multi-line text boxes
#define FLAG_WANTRETURN 0x00000400 // TEXT/FILEREQUEST/DIRREQUEST
// LBS_EXTENDEDSEL 0x00000800 // LISTBOX
// OFN_PATHMUSTEXIST 0x00000800 // FILEREQUEST
// OFN_FILEMUSTEXIST 0x00001000 // FILEREQUEST
// OFN_CREATEPROMPT 0x00002000 // FILEREQUEST
#define FLAG_DROPLIST 0x00004000 // COMBOBOX
#define FLAG_RESIZETOFIT 0x00008000 // BITMAP
// WS_TABSTOP 0x00010000 // *ALL*
// WS_GROUP 0x00020000 // *ALL*
#define FLAG_SAVEAS 0x00040000 // FILEREQUEST - Show "Save As" instead of "Open" for FileRequest field
// OFN_EXPLORER 0x00080000 // FILEREQUEST
// WS_HSCROLL 0x00100000 // *ALL*
// WS_VSCROLL 0x00200000 // *ALL*
// WS_DISABLED 0x08000000 // *ALL*
struct TableEntry {
char *pszName;
@ -150,7 +139,7 @@ struct FieldType {
// initial buffer size. buffers will grow as required.
// use a value larger than MAX_PATH to prevent need for excessive growing.
#define MAX_BUFFER_LENGTH (300)
#define BUFFER_SIZE 8192 // 8kb of mem is max char count in multiedit
char szBrowseButtonCaption[] = "...";
@ -159,7 +148,6 @@ HWND hMainWindow = NULL;
HWND hCancelButton = NULL;
HWND hNextButton = NULL;
HWND hBackButton = NULL;
HWND hInitialFocus = NULL;
HINSTANCE m_hInstance = NULL;
@ -197,20 +185,28 @@ LRESULT WINAPI mySendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
return SendMessage(hWnd, Msg, wParam, lParam);
}
void WINAPI mySetFocus(HWND hWnd)
{
mySendMessage(hMainWindow, WM_NEXTDLGCTL, (WPARAM)hWnd, TRUE);
}
void WINAPI mySetWindowText(HWND hWnd, LPCTSTR pszText)
{
if (pszText)
SetWindowText(hWnd, pszText);
}
int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData) {
static TCHAR szDir[MAX_PATH];
static TCHAR szDir[MAX_PATH];
if (uMsg == BFFM_INITIALIZED) {
if (GetWindowText(pFields[(int)pData].hwnd, szDir, MAX_PATH) > 0) {
mySendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)szDir);
}
}
return 0;
if (uMsg == BFFM_INITIALIZED &&
GetWindowText(pFields[(int)pData].hwnd, szDir, MAX_PATH) > 0)
mySendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)szDir);
return 0;
}
bool WINAPI ValidateFields() {
bool INLINE ValidateFields() {
int nIdx;
int nLength;
@ -228,7 +224,7 @@ bool WINAPI ValidateFields() {
if (pField->pszValidateText) {
MessageBox(hConfigWindow, pField->pszValidateText, NULL, MB_OK|MB_ICONWARNING);
}
SetFocus(pField->hwnd);
mySetFocus(pField->hwnd);
return false;
}
@ -239,110 +235,111 @@ bool WINAPI ValidateFields() {
bool WINAPI SaveSettings(void) {
static char szField[25];
int nIdx;
int nBufLen = MAX_BUFFER_LENGTH;
int nBufLen = BUFFER_SIZE;
char *pszBuffer = (char*)MALLOC(nBufLen);
if (!pszBuffer) return false;
int CurrField = 1;
for (nIdx = 0; nIdx < nNumFields; nIdx++) {
int nIdx;
int CurrField;
for (nIdx = 0, CurrField = 1; nIdx < nNumFields; nIdx++, CurrField++) {
FieldType *pField = pFields + nIdx;
HWND hwnd = pField->hwnd;
switch (pField->nType) {
case FIELD_BROWSEBUTTON:
if (g_NotifyField > CurrField)
--g_NotifyField;
--CurrField;
default:
continue;
case FIELD_INVALID:
case FIELD_LABEL:
case FIELD_BUTTON:
*pszBuffer=0;
break;
case FIELD_CHECKBOX:
case FIELD_RADIOBUTTON:
wsprintf(pszBuffer, "%d", !!mySendMessage(hwnd, BM_GETCHECK, 0, 0));
break;
case FIELD_LISTBOX:
{
// Ok, this one requires a bit of work.
// First, we allocate a buffer long enough to hold every item.
// 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(pField->pszListItems) + 10;
if (nLength > nBufLen) {
FREE(pszBuffer);
nBufLen = nLength;
pszBuffer = (char*)MALLOC(nBufLen);
if (!pszBuffer) return false;
}
char *pszItem = (char*)MALLOC(nBufLen);
if (!pszItem) return false;
{
// Ok, this one requires a bit of work.
// First, we allocate a buffer long enough to hold every item.
// 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(pField->pszListItems) + 10;
if (nLength > nBufLen) {
FREE(pszBuffer);
nBufLen = nLength;
pszBuffer = (char*)MALLOC(nBufLen);
if (!pszBuffer) return false;
}
char *pszItem = (char*)MALLOC(nBufLen);
if (!pszItem) return false;
*pszBuffer = '\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, "|");
mySendMessage(hwnd, LB_GETTEXT, (WPARAM)nIdx2, (LPARAM)pszItem);
lstrcat(pszBuffer, pszItem);
*pszBuffer = '\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, "|");
mySendMessage(hwnd, LB_GETTEXT, (WPARAM)nIdx2, (LPARAM)pszItem);
lstrcat(pszBuffer, pszItem);
}
}
FREE(pszItem);
break;
}
case FIELD_TEXT:
case FIELD_FILEREQUEST:
case FIELD_DIRREQUEST:
case FIELD_COMBOBOX:
{
int nLength = mySendMessage(pField->hwnd, WM_GETTEXTLENGTH, 0, 0);
if (nLength > nBufLen) {
FREE(pszBuffer);
// add a bit extra so we do this less often
nBufLen = nLength + 20;
pszBuffer = (char*)MALLOC(nBufLen);
if (!pszBuffer) return false;
}
*pszBuffer='"';
GetWindowText(hwnd, pszBuffer+1, nBufLen-1);
pszBuffer[nLength+1]='"';
pszBuffer[nLength+2]='\0';
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;
for (p1=pszBuffer,p2=pszBuf2; *p1; p1++, p2++) {
switch (*p1) {
case '\t':
*p2++ = '\\';
*p2 = 't';
break;
case '\n':
*p2++ = '\\';
*p2 = 'n';
break;
case '\r':
*p2++ = '\\';
*p2 = 'r';
break;
case '\\':
*p2++ = '\\';
default:
*p2=*p1;
}
}
FREE(pszItem);
break;
}
default:
{
int nLength = mySendMessage(pField->hwnd, WM_GETTEXTLENGTH, 0, 0);
if (nLength > nBufLen) {
FREE(pszBuffer);
// add a bit extra so we do this less often
nBufLen = nLength + 20;
pszBuffer = (char*)MALLOC(nBufLen);
if (!pszBuffer) return false;
}
*pszBuffer='"';
GetWindowText(hwnd, pszBuffer+1, nBufLen-1);
pszBuffer[nLength+1]='"';
pszBuffer[nLength+2]='\0';
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;
for (p1=pszBuffer,p2=pszBuf2; *p1; p1++, p2++) {
switch (*p1) {
case '\r':
*p2++ = '\\';
*p2 = 'r';
break;
case '\n':
*p2++ = '\\';
*p2 = 'n';
break;
case '\t':
*p2++ = '\\';
*p2 = 't';
break;
case '\\':
*p2++ = '\\';
default:
*p2=*p1;
}
}
*p2 = 0;
nBufLen = nBufLen*2;
FREE(pszBuffer);
pszBuffer=pszBuf2;
}
break;
*p2 = 0;
nBufLen = nBufLen*2;
FREE(pszBuffer);
pszBuffer=pszBuf2;
}
break;
}
}
wsprintf(szField, "Field %d", CurrField);
WritePrivateProfileString(szField, "State", pszBuffer, pszFilename);
CurrField++;
}
// Tell NSIS which control was activated, if any
@ -356,7 +353,6 @@ bool WINAPI SaveSettings(void) {
#define BROWSE_WIDTH 15
#define BUFFER_SIZE 8192 // 8kb of mem is max char count in multiedit
static char szResult[BUFFER_SIZE];
DWORD WINAPI myGetProfileString(LPCTSTR lpAppName, LPCTSTR lpKeyName)
@ -432,59 +428,52 @@ int WINAPI ReadSettings(void) {
};
// Control flags
static TableEntry FlagTable[] = {
{ "RIGHT", FLAG_RIGHT },
{ "NOTIFY", LBS_NOTIFY },
{ "WARN_IF_EXIST", OFN_OVERWRITEPROMPT },
{ "FILE_HIDEREADONLY", OFN_HIDEREADONLY },
{ "DISABLED", FLAG_DISABLED },
{ "GROUP", FLAG_GROUP },
{ "NOTABSTOP", FLAG_NOTABSTOP },
{ "MULTISELECT", LBS_MULTIPLESEL },
{ "READONLY", FLAG_READONLY },
{ "RIGHT", BS_LEFTTEXT },
{ "PASSWORD", FLAG_PASSWORD },
{ "ONLY_NUMBERS", FLAG_ONLYNUMBERS },
{ "MULTILINE", FLAG_MULTILINE },
{ "MULTISELECT", FLAG_MULTISELECT },
{ "EXTENDEDSELCT", FLAG_EXTENDEDSEL },
{ "FILE_MUST_EXIST", OFN_FILEMUSTEXIST },
{ "NOWORDWRAP", FLAG_NOWORDWRAP },
{ "WANTRETURN", FLAG_WANTRETURN },
{ "EXTENDEDSELCT", LBS_EXTENDEDSEL },
{ "PATH_MUST_EXIST", OFN_PATHMUSTEXIST },
{ "FILE_MUST_EXIST", OFN_FILEMUSTEXIST },
{ "PROMPT_CREATE", OFN_CREATEPROMPT },
{ "DROPLIST", FLAG_DROPLIST },
{ "RESIZETOFIT", FLAG_RESIZETOFIT },
{ "NOTIFY", FLAG_NOTIFY },
{ "NOTABSTOP", WS_TABSTOP },
{ "GROUP", WS_GROUP },
{ "REQ_SAVE", FLAG_SAVEAS },
{ "NOWORDWRAP", FLAG_NOWORDWRAP },
{ "FILE_EXPLORER", OFN_EXPLORER },
{ "WANTRETURN", FLAG_WANTRETURN },
{ "VSCROLL", FLAG_VSCROLL },
{ "HSCROLL", FLAG_HSCROLL },
{ "READONLY", FLAG_READONLY },
{ "HSCROLL", WS_HSCROLL },
{ "VSCROLL", WS_VSCROLL },
{ "DISABLED", WS_DISABLED },
{ NULL, 0 }
};
FieldType *pField = pFields + nIdx;
wsprintf(szField, "Field %d", nCtrlIdx + 1);
myGetProfileString(szField, "TYPE");
// Get the control type
myGetProfileString(szField, "TYPE");
pField->nType = LookupToken(TypeTable, szResult);
if (pField->nType == FIELD_INVALID)
continue;
// Lookup flags associated with the control type
pField->nFlags |= LookupToken(FlagTable, szResult);
pField->pszText = myGetProfileStringDup(szField, "TEXT");
// Label Text - convert newline
if (pField->nType == FIELD_LABEL) {
ConvertNewLines(pField->pszText);
}
pField->nFlags = LookupToken(FlagTable, szResult);
myGetProfileString(szField, "Flags");
pField->nFlags |= LookupTokens(FlagTable, szResult);
// pszState must not be NULL!
myGetProfileString(szField, "State");
pField->pszState = strdup(szResult);
pField->pszRoot = myGetProfileStringDup(szField, "ROOT");
// ListBox items list
{
int nResult = myGetProfileString(szField, "ListItems");
if (nResult) {
@ -495,21 +484,24 @@ int WINAPI ReadSettings(void) {
pField->pszListItems[nResult + 1] = '\0';
}
}
pField->nMaxLength = myGetProfileInt(szField, "MaxLen", 0);
pField->nMinLength = myGetProfileInt(szField, "MinLen", 0);
pField->pszValidateText = myGetProfileStringDup(szField, "ValidateText");
// Label Text - convert newline
pField->pszText = myGetProfileStringDup(szField, "TEXT");
if (pField->nType == FIELD_LABEL)
ConvertNewLines(pField->pszText);
// Dir request - root folder
pField->pszRoot = myGetProfileStringDup(szField, "ROOT");
// ValidateText - convert newline
if (pField->pszValidateText) {
ConvertNewLines(pField->pszValidateText);
}
pField->pszValidateText = myGetProfileStringDup(szField, "ValidateText");
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.
// Convert the filter to the format required by Windows: NULL after each
// item followed by a terminating NULL
pField->pszFilter = (char*)MALLOC(nResult + 2);
strcpy(pField->pszFilter, szResult);
char *pszPos = pField->pszFilter;
@ -521,15 +513,13 @@ int WINAPI ReadSettings(void) {
}
pField->rect.left = myGetProfileInt(szField, "LEFT", 0);
pField->rect.right = myGetProfileInt(szField, "RIGHT", 0);
pField->rect.top = myGetProfileInt(szField, "TOP", 0);
pField->rect.right = myGetProfileInt(szField, "RIGHT", 0);
pField->rect.bottom = myGetProfileInt(szField, "BOTTOM", 0);
myGetProfileString(szField, "Flags");
pField->nFlags |= LookupTokens(FlagTable, szResult);
pField->nMinLength = myGetProfileInt(szField, "MinLen", 0);
pField->nMaxLength = myGetProfileInt(szField, "MaxLen", 0);
// Text color for LINK control, default is pure blue
//if (pField->nType == FIELD_LINK)
pField->hImage = (HANDLE)myGetProfileInt(szField, "TxtColor", RGB(0,0,255));
pField->nControlID = 1200 + nIdx;
@ -538,7 +528,7 @@ int WINAPI ReadSettings(void) {
FieldType *pNewField = &pFields[nIdx+1];
pNewField->nControlID = 1200 + nIdx + 1;
pNewField->nType = FIELD_BROWSEBUTTON;
pNewField->nFlags = pField->nFlags & (FLAG_DISABLED | FLAG_NOTABSTOP);
pNewField->nFlags = pField->nFlags & (WS_DISABLED | WS_TABSTOP);
pNewField->pszText = STRDUP(szBrowseButtonCaption); // needed for generic FREE
pNewField->rect.right = pField->rect.right;
pNewField->rect.left = pNewField->rect.right - BROWSE_WIDTH;
@ -556,7 +546,9 @@ int WINAPI ReadSettings(void) {
LRESULT WINAPI WMCommandProc(HWND hWnd, UINT id, HWND hwndCtl, UINT codeNotify) {
switch (codeNotify) {
case BN_CLICKED:
case BN_CLICKED: // The user pressed a button
case LBN_SELCHANGE: // The user changed the selection in a ListBox control
// case CBN_SELCHANGE: // The user changed the selection in a DropList control (same value as LBN_SELCHANGE)
{
char szBrowsePath[MAX_PATH];
int nIdx = FindControlIdx(id);
@ -580,7 +572,7 @@ LRESULT WINAPI WMCommandProc(HWND hWnd, UINT id, HWND hwndCtl, UINT codeNotify)
tryagain:
if ((pField->nFlags & FLAG_SAVEAS) ? GetSaveFileName(&ofn) : GetOpenFileName(&ofn)) {
SetWindowText(pField->hwnd, szBrowsePath);
mySetWindowText(pField->hwnd, szBrowsePath);
break;
}
else if (szBrowsePath[0] && CommDlgExtendedError() == FNERR_INVALIDFILENAME) {
@ -625,7 +617,7 @@ LRESULT WINAPI WMCommandProc(HWND hWnd, UINT id, HWND hwndCtl, UINT codeNotify)
break;
if (SHGetPathFromIDList(pResult, szBrowsePath)) {
SetWindowText(pField->hwnd, szBrowsePath);
mySetWindowText(pField->hwnd, szBrowsePath);
}
LPMALLOC pMalloc;
@ -637,16 +629,20 @@ LRESULT WINAPI WMCommandProc(HWND hWnd, UINT id, HWND hwndCtl, UINT codeNotify)
}
case FIELD_LINK:
ShellExecute(hMainWindow, NULL, pField->pszState, NULL, NULL, SW_SHOWDEFAULT);
case FIELD_BUTTON:
// Allow the state to be empty - this might be useful in conjunction
// with the NOTIFY flag
if (*pField->pszState)
ShellExecute(hMainWindow, NULL, pField->pszState, NULL, NULL, SW_SHOWDEFAULT);
break;
}
if (pField->nFlags & FLAG_NOTIFY) {
if (pField->nFlags & LBS_NOTIFY) {
// Remember which control was activated then pretend the user clicked Next
g_NotifyField = nIdx + 1;
// the next button must be enabled or nsis will ignore WM_COMMAND
BOOL bWasDisabled = EnableWindow(hNextButton, TRUE);
FORWARD_WM_COMMAND(hMainWindow, IDOK, hNextButton, codeNotify, mySendMessage);
FORWARD_WM_COMMAND(hMainWindow, IDOK, hNextButton, BN_CLICKED, mySendMessage);
if (bWasDisabled)
EnableWindow(hNextButton, FALSE);
}
@ -715,13 +711,12 @@ BOOL CALLBACK cfgDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
// We need lpdis->rcItem later
RECT rc = lpdis->rcItem;
// Get TxtColor unless the user has set another using SetCtlColors
if (!GetWindowLong(lpdis->hwndItem, GWL_USERDATA))
SetTextColor(lpdis->hDC, (COLORREF) pField->hImage);
// Calculate needed size of the control
DrawText(lpdis->hDC, pField->pszText, -1, &rc, DT_VCENTER | DT_SINGLELINE | DT_CALCRECT);
// Make some more room so the focus rect won't cut letters off
rc.right = min(rc.right + 2, lpdis->rcItem.right);
// Move rect to right if in RTL mode
if (bRTL)
{
@ -729,19 +724,24 @@ BOOL CALLBACK cfgDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
rc.right += lpdis->rcItem.right - rc.right;
}
// Make some more room so the focus rect won't cut letters off
rc.right = min(rc.right + 2, lpdis->rcItem.right);
if (lpdis->itemAction & ODA_DRAWENTIRE)
{
// Get TxtColor unless the user has set another using SetCtlColors
if (!GetWindowLong(lpdis->hwndItem, GWL_USERDATA))
SetTextColor(lpdis->hDC, (COLORREF) pField->hImage);
// Draw the text
DrawText(lpdis->hDC, pField->pszText, -1, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE | (bRTL ? DT_RTLREADING : 0));
// Draw the text
DrawText(lpdis->hDC, pField->pszText, -1, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE | (bRTL ? DT_RTLREADING : 0));
}
// Draw the focus rect if needed
if (((lpdis->itemState & ODS_FOCUS) && (lpdis->itemAction & ODA_DRAWENTIRE)) || (lpdis->itemAction & ODA_FOCUS) || (lpdis->itemAction & ODA_SELECT))
if (((lpdis->itemState & ODS_FOCUS) && (lpdis->itemAction & ODA_DRAWENTIRE)) || (lpdis->itemAction & ODA_FOCUS))
{
// NB: when not in DRAWENTIRE mode, this will actually toggle the focus
// rectangle since it's drawn in a XOR way
DrawFocusRect(lpdis->hDC, &rc);
}
MapWindowPoints(lpdis->hwndItem, 0, (LPPOINT) &rc, 2);
pField->rect = rc;
#ifdef IO_LINK_UNDERLINED
@ -755,7 +755,7 @@ BOOL CALLBACK cfgDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
case WM_CTLCOLORBTN:
case WM_CTLCOLORLISTBOX:
// let the NSIS window handle colors, it knows best
return mySendMessage(hMainWindow, WM_CTLCOLORSTATIC, wParam, lParam);
return mySendMessage(hMainWindow, uMsg, wParam, lParam);
}
return 0;
}
@ -766,31 +766,44 @@ BOOL CALLBACK cfgDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
#define IDC_HAND MAKEINTRESOURCE(32649)
#endif
#ifndef BS_TYPEMASK
#define BS_TYPEMASK 0x0000000FL
#endif
// pFields[nIdx].nParentIdx is used to store original windowproc
int WINAPI StaticLINKWindowProc(HWND hWin, UINT uMsg, LPARAM wParam, WPARAM lParam)
{
int CtrlId = GetDlgCtrlID(hWin);
int StaticField = FindControlIdx(CtrlId);
int StaticField = FindControlIdx(GetDlgCtrlID(hWin));
if (StaticField < 0)
return 0;
FieldType *pField = pFields + StaticField;
switch(uMsg)
{
case WM_SETFOCUS:
mySendMessage(hConfigWindow, DM_SETDEFID, CtrlId, 0);
// remove the BS_DEFPUSHBUTTON style from IDOK
mySendMessage(GetDlgItem(hMainWindow, IDOK), BM_SETSTYLE, BS_PUSHBUTTON, TRUE);
break;
case WM_NCHITTEST:
case WM_GETDLGCODE:
// Pretend we are a normal button/default button as appropriate
return DLGC_BUTTON | ((pField->nFlags & FLAG_WANTRETURN) ? DLGC_DEFPUSHBUTTON : DLGC_UNDEFPUSHBUTTON);
case BM_SETSTYLE:
// Detect when we are becoming the default button but don't lose the owner-draw style
if ((wParam & BS_TYPEMASK) == BS_DEFPUSHBUTTON)
pField->nFlags |= FLAG_WANTRETURN; // Hijack this flag to indicate default button status
else
pField->nFlags &= ~FLAG_WANTRETURN;
wParam = (wParam & ~BS_TYPEMASK) | BS_OWNERDRAW;
break;
case WM_NCHITTEST:
{
POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
MapWindowPoints(0, hWin, &pt, 1);
if (PtInRect(&pField->rect, pt))
return HTCLIENT;
else
return HTNOWHERE;
}
case WM_SETCURSOR:
case WM_SETCURSOR:
{
if ((HWND)wParam == hWin && LOWORD(lParam) == HTCLIENT)
{
@ -838,12 +851,12 @@ int WINAPI createCfgDlg()
}
hCancelButton = GetDlgItem(mainwnd,IDCANCEL);
hInitialFocus = hNextButton = GetDlgItem(mainwnd,IDOK);
hNextButton = GetDlgItem(mainwnd,IDOK);
hBackButton = GetDlgItem(mainwnd,3);
if (pszCancelButtonText) SetWindowText(hCancelButton,pszCancelButtonText);
if (pszNextButtonText) SetWindowText(hNextButton,pszNextButtonText);
if (pszBackButtonText) SetWindowText(hBackButton,pszBackButtonText);
mySetWindowText(hCancelButton,pszCancelButtonText);
mySetWindowText(hNextButton,pszNextButtonText);
mySetWindowText(hBackButton,pszBackButtonText);
if (bBackEnabled!=-1) EnableWindow(hBackButton,bBackEnabled);
if (bCancelEnabled!=-1) EnableWindow(hCancelButton,bCancelEnabled);
@ -894,6 +907,8 @@ int WINAPI createCfgDlg()
DeleteDC(memDC);
BOOL fFocused = FALSE;
#define DEFAULT_STYLES (WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS)
for (int nIdx = 0; nIdx < nNumFields; nIdx++) {
@ -905,18 +920,18 @@ int WINAPI createCfgDlg()
DWORD dwRTLExStyle;
} ClassTable[] = {
{ "STATIC", // FIELD_LABEL
DEFAULT_STYLES /*| WS_TABSTOP*/,
DEFAULT_STYLES | SS_RIGHT /*| WS_TABSTOP*/,
DEFAULT_STYLES,
DEFAULT_STYLES | SS_RIGHT,
WS_EX_TRANSPARENT,
WS_EX_TRANSPARENT | WS_EX_RTLREADING },
{ "STATIC", // FIELD_ICON
DEFAULT_STYLES /*| WS_TABSTOP*/ | SS_ICON,
DEFAULT_STYLES /*| WS_TABSTOP*/ | SS_ICON,
DEFAULT_STYLES | SS_ICON,
DEFAULT_STYLES | SS_ICON,
0,
WS_EX_RTLREADING },
{ "STATIC", // FIELD_BITMAP
DEFAULT_STYLES /*| WS_TABSTOP*/ | SS_BITMAP | SS_CENTERIMAGE,
DEFAULT_STYLES /*| WS_TABSTOP*/ | SS_BITMAP | SS_CENTERIMAGE,
DEFAULT_STYLES | SS_BITMAP | SS_CENTERIMAGE,
DEFAULT_STYLES | SS_BITMAP | SS_CENTERIMAGE,
0,
WS_EX_RTLREADING },
{ "BUTTON", // FIELD_BROWSEBUTTON
@ -1025,9 +1040,7 @@ int WINAPI createCfgDlg()
break;
case FIELD_CHECKBOX:
case FIELD_RADIOBUTTON:
case FIELD_BUTTON:
if (pField->nFlags & FLAG_RIGHT)
dwStyle |= BS_RIGHTBUTTON;
dwStyle ^= pField->nFlags & BS_LEFTTEXT;
break;
case FIELD_TEXT:
case FIELD_FILEREQUEST:
@ -1036,40 +1049,37 @@ int WINAPI createCfgDlg()
dwStyle |= ES_PASSWORD;
if (pField->nFlags & FLAG_ONLYNUMBERS)
dwStyle |= ES_NUMBER;
if (pField->nFlags & FLAG_WANTRETURN)
dwStyle |= ES_WANTRETURN;
if (pField->nFlags & FLAG_READONLY)
dwStyle |= ES_READONLY;
title = pField->pszState;
if (pField->nFlags & FLAG_MULTILINE)
{
dwStyle |= ES_MULTILINE | ES_AUTOVSCROLL;
// Enable word-wrap unless we have a horizontal scroll bar
// or it has been explicitly disallowed
if (!(pField->nFlags & (FLAG_HSCROLL | FLAG_NOWORDWRAP)))
if (!(pField->nFlags & (WS_HSCROLL | FLAG_NOWORDWRAP)))
dwStyle &= ~ES_AUTOHSCROLL;
ConvertNewLines(pField->pszState);
// If multiline-readonly then hold the text back until after the
// initial focus has been set. This is so the text is not initially
// selected - useful for License Page look-a-likes.
if (pField->nFlags & FLAG_READONLY)
title = NULL;
}
if (pField->nFlags & FLAG_WANTRETURN)
dwStyle |= ES_WANTRETURN;
if (pField->nFlags & FLAG_VSCROLL)
dwStyle |= WS_VSCROLL;
if (pField->nFlags & FLAG_HSCROLL)
dwStyle |= WS_HSCROLL;
if (pField->nFlags & FLAG_READONLY)
dwStyle |= ES_READONLY;
title = pField->pszState;
break;
case FIELD_COMBOBOX:
dwStyle |= (pField->nFlags & FLAG_DROPLIST) ? CBS_DROPDOWNLIST : CBS_DROPDOWN;
title = pField->pszState;
break;
case FIELD_LISTBOX:
if (pField->nFlags & FLAG_EXTENDEDSEL)
dwStyle |= LBS_EXTENDEDSEL;
if (pField->nFlags & FLAG_MULTISELECT)
dwStyle |= LBS_MULTIPLESEL;
dwStyle |= pField->nFlags & (LBS_NOTIFY | LBS_MULTIPLESEL | LBS_EXTENDEDSEL);
break;
}
if (pField->nFlags & FLAG_DISABLED) dwStyle |= WS_DISABLED;
if (pField->nFlags & FLAG_GROUP) dwStyle |= WS_GROUP;
if (pField->nFlags & FLAG_NOTABSTOP) dwStyle &= ~WS_TABSTOP;
dwStyle |= pField->nFlags & (WS_GROUP | WS_HSCROLL | WS_VSCROLL | WS_DISABLED);
if (pField->nFlags & WS_TABSTOP) dwStyle &= ~WS_TABSTOP;
HWND hwCtrl = pField->hwnd = CreateWindowEx(
dwExStyle,
@ -1090,15 +1100,20 @@ int WINAPI createCfgDlg()
// Sets the font of IO window to be the same as the main window
mySendMessage(hwCtrl, WM_SETFONT, (WPARAM)hFont, TRUE);
// Set initial focus to the first appropriate field
if ((hInitialFocus == hNextButton) && (dwStyle & WS_TABSTOP))
hInitialFocus = hwCtrl;
if (!fFocused && (dwStyle & (WS_TABSTOP | WS_DISABLED)) == WS_TABSTOP) {
fFocused = TRUE;
mySetFocus(hwCtrl);
}
// make sure we created the window, then set additional attributes
switch (pField->nType) {
case FIELD_TEXT:
mySendMessage(hwCtrl, WM_SETTEXT, 0, (LPARAM)title);
// no break;
case FIELD_FILEREQUEST:
case FIELD_DIRREQUEST:
// If multiline-readonly then hold the text back until after the
// initial focus has been set. This is so the text is not initially
// selected - useful for License Page look-a-likes.
if ((pField->nFlags & (FLAG_MULTILINE | FLAG_READONLY)) == (FLAG_MULTILINE | FLAG_READONLY))
mySetWindowText(hwCtrl, pField->pszState);
mySendMessage(hwCtrl, EM_LIMITTEXT, (WPARAM)pField->nMaxLength, (LPARAM)0);
break;
@ -1139,7 +1154,7 @@ int WINAPI createCfgDlg()
}
FREE(pszList);
if (pField->pszState) {
if (pField->nFlags & (FLAG_MULTISELECT|FLAG_EXTENDEDSEL) && nFindMsg == LB_FINDSTRINGEXACT) {
if (pField->nFlags & (LBS_MULTIPLESEL|LBS_EXTENDEDSEL) && nFindMsg == LB_FINDSTRINGEXACT) {
mySendMessage(hwCtrl, LB_SETSEL, FALSE, -1);
pszStart = pszEnd = pField->pszState;
while (*pszStart) {
@ -1212,8 +1227,10 @@ int WINAPI createCfgDlg()
}
}
if (pszTitle)
SetWindowText(mainwnd,pszTitle);
if (!fFocused)
mySetFocus(hNextButton);
mySetWindowText(mainwnd,pszTitle);
pFilenameStackEntry = *g_stacktop;
*g_stacktop = (*g_stacktop)->next;
static char tmp[32];
@ -1229,7 +1246,6 @@ void WINAPI showCfgDlg()
// Tell NSIS to remove old inner dialog and pass handle of the new inner dialog
mySendMessage(hMainWindow, WM_NOTIFY_CUSTOM_READY, (WPARAM)hConfigWindow, 0);
ShowWindow(hConfigWindow, SW_SHOWNA);
SetFocus(hInitialFocus);
g_done = g_NotifyField = 0;
@ -1364,15 +1380,15 @@ void WINAPI ConvertNewLines(char *str) {
for (p1=p2=str; *p1; p1++, p2++) {
if (*p1 == '\\') {
switch (p1[1]) {
case 't':
*p2 = '\t';
break;
case 'n':
*p2 = '\n';
break;
case 'r':
*p2 = '\r';
break;
case 't':
*p2 = '\t';
break;
case '\\':
*p2 = '\\';
break;

View file

@ -235,10 +235,12 @@ will display a directory requester where the user can browse for a directory.<br
An "<em>Icon</em>" control displays an icon. Use no Text to use the installer icon.<br />
A "<em>Bitmap</em>" control displays a bitmap.<br />
A "<em>GroupBox</em>" control displays a frame to group controls.<br />
A "<em>Link</em>" control displays a static hot text, when the user click the control the contents
of <strong>State</strong> (e.g. http://...) will be executed using ShellExecute<br />
A "<em>Button</em>" control displays a push button that your NSIS script can act on when pressed.
See the "<em>NOTIFY</em>" flag for more information.</td>
A "<em>Link</em>" control displays a static hot text. When the user clicks the control the contents
of <strong>State</strong> (e.g. http://...) will be executed using ShellExecute. Alternatively
<strong>State</strong> can be omitted and the <em>NOTIFY</em> flag used to have your NSIS script
called. See the "<em>NOTIFY</em>" flag below for more information.<br />
A "<em>Button</em>" control displays a push button that can be used in the same way as the
"<em>Link</em>" control above.</td>
</tr>
<tr>
<td class="lefttable"><strong>Text</strong></td>
@ -257,7 +259,8 @@ are NSIS functions for converting text to/from this format.</td>
window, so you can read from it from NSIS. For edit texts and dir and file request boxes, this is
the string that is specified. For radio button and check boxes, this can be '0' or '1' (for
unchecked or checked). For list boxes, combo boxes and drop lists this is the selected items
separated by pipes ('|').<br />
separated by pipes ('|'). For Links and Buttons this can specify something to be executed or opened
(using ShellExecute).<br />
<br />
<strong>Note:</strong> For Text fields with the MULTILINE flag, \r\n will be converted to a
newline. To use a back-slash in your text you have to escape it using another back-slash - \\.
@ -314,16 +317,19 @@ Bottom</strong></td>
set in dialog units. To get the right dimensions for your controls, design your dialog using a
resource editor and copy the dimensions to the INI file.<br />
<br />
<strong>Note:</strong> For combobox or droplist, the "<em>bottom</em>" value is not used in the
<strong>Note:</strong> You can specify negative coordinates to specify the distance from the right
or bottom edge.<br />
<br />
<strong>Note (2):</strong> For combobox or droplist, the "<em>bottom</em>" value is not used in the
same way.<br />
In this case, the bottom value is the maximum size of the window when the pop-up list is being
displayed. All other times, the combobox is automatically sized to be one element tall. If you have
trouble where you can not see the combobox drop-down, then check the bottom value and ensure it is
large enough.<br />
large enough. A rough guide for the height required is the number of items in the list multiplied
by 8, plus 20.<br />
<br />
<strong>Note (2):</strong> FileRequest and DirRequest controls will allocate 15 dialog units to the
browse button. Make this control wide enough the contents of the textbox can be seen. Note that you
can specify negative coordinates to specify the distance from the right or bottom edge.</td>
<strong>Note (3):</strong> FileRequest and DirRequest controls will allocate 15 dialog units to the
browse button. Make this control wide enough the contents of the textbox can be seen.</td>
</tr>
<tr>
<td class="lefttable"><strong>Filter</strong></td>
@ -461,13 +467,12 @@ HSCROLL flag also has this effect.</td>
</tr>
<tr>
<td class="righttable">HSCROLL</td>
<td class="righttable">Used by "<em>Text</em>" controls with multiple-line. Show a horizontal
scrollbar and disable word-wrap.</td>
<td class="righttable">Show a horizontal scrollbar. When used by "<em>Text</em>" controls with
multiple-lines this also disables word-wrap.</td>
</tr>
<tr>
<td class="righttable">VSCROLL</td>
<td class="righttable">Used by "<em>Text</em>" controls with multiple-line. Show a vertical
scrollbar.</td>
<td class="righttable">Show a vertical scrollbar.</td>
</tr>
<tr>
<td class="righttable">READONLY</td>
@ -476,11 +481,12 @@ text in the edit control, but allow the user to select and copy the text.</td>
</tr>
<tr>
<td class="righttable">NOTIFY</td>
<td class="righttable">Used by "<em>Button</em>", "<em>CheckBox</em>" and "<em>RadioButton</em>"
controls. Causes InstallOptions to call your NSIS custom page validation/leave function whenever
the button is pressed. Your validation/leave function can read the "<em>State</em>" value from the
"<em>Settings</em>" 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
<td class="righttable">Used by "<em>Button</em>", "<em>Link</em>", "<em>CheckBox</em>",
"<em>RadioButton</em>", "<em>ListBox</em>" and "<em>DropList</em>" controls. Causes InstallOptions
to call your NSIS custom page validation/leave function whenever the control's selection changes.
Your validation/leave function can read the "<em>State</em>" value from the "<em>Settings</em>"
section to determine which control caused the notification, 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.</td>
</tr>
</table>
@ -718,12 +724,32 @@ FunctionEnd
</pre>
<h2>Version history</h2>
<ul>
<li>DLL version 2.4 (1/4/2004)
<ul>
<li>Initial focus is set in "initDialog" making it possible to override it from NSIS prior to
calling "show"</li>
<li>When initial focus is to a Text field InstallOptions now follows standard Windows behaviour by
having the text selected</li>
<li>Label and other static fields no longer have State= written to the INI file when leaving the
dialog</li>
<li>NOTIFY flag can now be used with Link fields (State should be omitted in this case)</li>
<li>Likewise, State can now be used with Button fields (behaves the same as with Link fields)</li>
<li>NOTIFY flag can also now be used with ListBox and DropList fields to have NSIS notified when
the selection changes</li>
<li>Meaning of RIGHT flag is now reversed in right-to-left language mode</li>
<li>HSCROLL and VSCROLL flags are no longer restricted to Text fields</li>
<li>Various Link field fixes</li>
</ul>
</li>
</ul>
<ul>
<li>DLL version 2.3 (12/4/2003)
<ul>
<li>Added new control type "Button"</li>
<li>Added new flag "NOTIFY"</li>
<li>Added new flag "NOWORDWRAP" for multi-line text boxes</li>
<li>Reduced size down to 12K</li>
<li>Better RTL support</li>
</ul>
</li>
</ul>

View file

@ -1,5 +1,5 @@
[Settings]
NumFields=4
NumFields=5
[Field 1]
Type=Label
@ -34,3 +34,11 @@ Top=70
Bottom=80
State=http://nsis.sourceforge.net/
Text=* Homepage http://nsis.sourceforge.net/
[Field 5]
Type=Text
Left=20
Right=-40
Top=85
Bottom=98
State=Just to test proper interaction with the other fields

View file

@ -1,5 +1,5 @@
[Settings]
NumFields=9
NumFields=11
[Field 1]
Type=Groupbox
@ -31,6 +31,7 @@ Bottom=38
[Field 4]
Type=Checkbox
Text=Install support for Z
Flags=RIGHT
State=0
Left=10
Right=100
@ -73,12 +74,32 @@ Right=-10
Top=97
Bottom=118
MinLen=1
ValidateText=Please enter some text before proceeding.
[Field 9]
Type=Button
Flags=NOTIFY
Text=Clear
Text=&Clear
Left=-60
Right=-10
Top=27
Bottom=41
Top=19
Bottom=33
[Field 10]
Type=Button
Text=&Email
State=mailto:someone@anywhere.com
Left=-60
Right=-10
Top=35
Bottom=49
[Field 11]
Type=DROPLIST
ListItems=Show|Hide
State=Show
Flags=NOTIFY
Left=120
Right=-80
Top=20
Bottom=56

View file

@ -30,6 +30,8 @@ Page custom ShowCustom LeaveCustom ": Testing InstallOptions"
Function ShowCustom
; Initialise the dialog but don't show it yet
MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "Test the right-to-left version?" IDNO +2
WriteINIStr "$PLUGINSDIR\test.ini" "Settings" "RTL" "1"
InstallOptions::initDialog /NOUNLOAD "$PLUGINSDIR\test.ini"
; In this mode InstallOptions returns the window handle so we can use it
Pop $hwnd
@ -45,9 +47,10 @@ Function LeaveCustom
; At this point the user has either pressed Next or one of our custom buttons
; We find out which by reading from the INI file
ReadINIStr $0 "$PLUGINSDIR\test.ini" "Settings" "State"
StrCmp $0 0 validate ; Next button?
StrCmp $0 2 supportx ; "Install support for X"?
StrCmp $0 9 clearbtn ; "Clear" button?
StrCmp $0 0 validate ; Next button?
StrCmp $0 2 supportx ; "Install support for X"?
StrCmp $0 9 clearbtn ; "Clear" button?
StrCmp $0 11 droplist ; "Show|Hide" drop-list?
Abort ; Return to the page
supportx:
@ -65,10 +68,23 @@ clearbtn:
SendMessage $1 ${WM_SETTEXT} 0 "STR:"
GetDlgItem $1 $hwnd 1206 ; DirRequest control (1200 + field 6 - 1 + 1 browse button)
SendMessage $1 ${WM_SETTEXT} 0 "STR:"
GetDlgItem $1 $hwnd 1209 ; DirRequest control (1200 + field 8 - 1 + 2 browse buttons)
GetDlgItem $1 $hwnd 1209 ; Multiline control (1200 + field 8 - 1 + 2 browse buttons)
SendMessage $1 ${WM_SETTEXT} 0 "STR:"
Abort ; Return to the page
droplist:
; Make the DirRequest field depend on the droplist
ReadINIStr $0 "$PLUGINSDIR\test.ini" "Field 11" "State"
StrCmp $0 "Show" +3
StrCpy $0 0
Goto +2
StrCpy $0 1
GetDlgItem $1 $hwnd 1206 ; DirRequest control (1200 + field 6 - 1 + 1 browse button)
EnableWindow $1 $0
GetDlgItem $1 $hwnd 1207 ; ... button (the following control)
EnableWindow $1 $0
Abort ; Return to the page
validate:
; At this point we know the Next button was pressed, so perform any validation
ReadINIStr $0 "$PLUGINSDIR\test.ini" "Field 2" "State"

Binary file not shown.