
Compiler output is identical before & after this step git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/branches/wizou@6036 212acab6-be3b-0410-9dea-997c60f758d6
1653 lines
52 KiB
C++
1653 lines
52 KiB
C++
/*********************************************************
|
|
*
|
|
* InstallOptions version 2.0 - Plugin for custom pages
|
|
*
|
|
* See Readme.html for documentation and license
|
|
*
|
|
* Unicode support by Jim Park -- 08/01/2007
|
|
*
|
|
*********************************************************/
|
|
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include <shlobj.h>
|
|
#include <commdlg.h>
|
|
#include <cderr.h>
|
|
#include "resource.h"
|
|
#include "shellapi.h"
|
|
|
|
#include <nsis/pluginapi.h> // nsis plugin
|
|
|
|
// 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); }
|
|
|
|
#define strcpy(x,y) lstrcpy(x,y)
|
|
//#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))
|
|
|
|
TCHAR *WINAPI STRDUP(const TCHAR *c)
|
|
{
|
|
TCHAR *t=(TCHAR*)MALLOC((lstrlen(c)+1)*sizeof(TCHAR));
|
|
return lstrcpy(t,c);
|
|
}
|
|
|
|
// Turn a pair of chars into a word
|
|
// Turn four chars into a dword
|
|
#ifdef __BIG_ENDIAN__ // Not very likely, but, still...
|
|
#define CHAR2_TO_WORD(a,b) (((WORD)(b))|((a)<<8))
|
|
#define CHAR4_TO_DWORD(a,b,c,d) (((DWORD)CHAR2_TO_WORD(c,d))|(CHAR2_TO_WORD(a,b)<<16))
|
|
#else
|
|
#define CHAR2_TO_WORD(a,b) (((WORD)(a))|((b)<<8))
|
|
#define CHAR4_TO_DWORD(a,b,c,d) (((DWORD)CHAR2_TO_WORD(a,b))|(CHAR2_TO_WORD(c,d)<<16))
|
|
#endif
|
|
|
|
// Field types
|
|
// NB - the order of this list is important - see below
|
|
|
|
#define FIELD_INVALID (0)
|
|
#define FIELD_HLINE (1)
|
|
#define FIELD_VLINE (2)
|
|
#define FIELD_LABEL (3)
|
|
#define FIELD_ICON (4)
|
|
#define FIELD_BITMAP (5)
|
|
#define FIELD_BROWSEBUTTON (6)
|
|
#define FIELD_LINK (7)
|
|
#define FIELD_BUTTON (8)
|
|
#define FIELD_GROUPBOX (9)
|
|
#define FIELD_CHECKBOX (10)
|
|
#define FIELD_RADIOBUTTON (11)
|
|
#define FIELD_TEXT (12)
|
|
#define FIELD_FILEREQUEST (13)
|
|
#define FIELD_DIRREQUEST (14)
|
|
#define FIELD_COMBOBOX (15)
|
|
#define FIELD_LISTBOX (16)
|
|
|
|
#define FIELD_SETFOCUS FIELD_CHECKBOX // First field that qualifies for having the initial keyboard focus
|
|
#define FIELD_CHECKLEN FIELD_TEXT // First field to have length of state value checked against MinLen/MaxLen
|
|
|
|
//---------------------------------------------------------------------
|
|
// settings
|
|
#define IO_ENABLE_LINK
|
|
|
|
//#define IO_LINK_UNDERLINED // Uncomment to show links text underlined
|
|
//---------------------------------------------------------------------
|
|
|
|
// Flags
|
|
|
|
// 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 TRANSPARENT_BMP 0x00000020 // BITMAP
|
|
#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*
|
|
#define FLAG_FOCUS 0x10000000 // Controls that can receive focus
|
|
|
|
struct TableEntry {
|
|
TCHAR *pszName;
|
|
int nValue;
|
|
};
|
|
|
|
int WINAPI LookupToken(TableEntry*, TCHAR*);
|
|
int WINAPI LookupTokens(TableEntry*, TCHAR*);
|
|
|
|
void WINAPI ConvertNewLines(TCHAR *str);
|
|
|
|
// all allocated buffers must be first in the struct
|
|
// when adding more allocated buffers to FieldType, don't forget to change this define
|
|
#define FIELD_BUFFERS 6
|
|
struct FieldType {
|
|
TCHAR *pszText;
|
|
TCHAR *pszState;
|
|
TCHAR *pszRoot;
|
|
|
|
TCHAR *pszListItems;
|
|
TCHAR *pszFilter;
|
|
|
|
TCHAR *pszValidateText;
|
|
int nMinLength;
|
|
int nMaxLength;
|
|
|
|
int nType;
|
|
RECT rect;
|
|
|
|
int nFlags;
|
|
|
|
HWND hwnd;
|
|
UINT nControlID;
|
|
|
|
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
|
|
|
|
int nField; // field number in INI file
|
|
TCHAR *pszHwndEntry; // "HWND" or "HWND2"
|
|
|
|
long wndProc;
|
|
};
|
|
|
|
// initial buffer size. buffers will grow as required.
|
|
// use a value larger than MAX_PATH to prevent need for excessive growing.
|
|
#define BUFFER_SIZE 8192 // 8kb of mem is max char count in multiedit
|
|
|
|
TCHAR szBrowseButtonCaption[] = _T("...");
|
|
|
|
HWND hConfigWindow = NULL;
|
|
HWND hMainWindow = NULL;
|
|
HWND hCancelButton = NULL;
|
|
HWND hNextButton = NULL;
|
|
HWND hBackButton = NULL;
|
|
|
|
HINSTANCE m_hInstance = NULL;
|
|
|
|
struct _stack_t *pFilenameStackEntry = NULL;
|
|
|
|
TCHAR *pszFilename = NULL;
|
|
TCHAR *pszTitle = NULL;
|
|
TCHAR *pszCancelButtonText = NULL;
|
|
TCHAR *pszNextButtonText = NULL;
|
|
TCHAR *pszBackButtonText = NULL;
|
|
|
|
int bBackEnabled = FALSE;
|
|
int bCancelEnabled = FALSE; // by ORTIM: 13-August-2002
|
|
int bCancelShow = FALSE; // by ORTIM: 13-August-2002
|
|
|
|
int bRTL = FALSE;
|
|
|
|
FieldType *pFields = NULL;
|
|
#define DEFAULT_RECT 1018
|
|
int nRectId = 0;
|
|
int nNumFields = 0;
|
|
int g_done;
|
|
int g_NotifyField; // Field number of notifying control
|
|
|
|
int WINAPI FindControlIdx(UINT id)
|
|
{
|
|
for (int nIdx = 0; nIdx < nNumFields; nIdx++)
|
|
if (id == pFields[nIdx].nControlID)
|
|
return nIdx;
|
|
return -1;
|
|
}
|
|
|
|
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];
|
|
|
|
if (uMsg == BFFM_INITIALIZED &&
|
|
GetWindowText(pFields[(int)pData].hwnd, szDir, MAX_PATH) > 0)
|
|
mySendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)szDir);
|
|
return 0;
|
|
}
|
|
|
|
|
|
bool INLINE ValidateFields() {
|
|
int nIdx;
|
|
int nLength;
|
|
|
|
// 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 (pField->nType >= FIELD_CHECKLEN) {
|
|
nLength = mySendMessage(pField->hwnd, WM_GETTEXTLENGTH, 0, 0);
|
|
|
|
if (((pField->nMaxLength > 0) && (nLength > pField->nMaxLength)) ||
|
|
((pField->nMinLength > 0) && (nLength < pField->nMinLength))) {
|
|
if (pField->pszValidateText) {
|
|
TCHAR szTitle[1024];
|
|
GetWindowText(hMainWindow, szTitle, _countof(szTitle));
|
|
MessageBox(hConfigWindow, pField->pszValidateText, szTitle, MB_OK|MB_ICONWARNING);
|
|
}
|
|
mySetFocus(pField->hwnd);
|
|
return false;
|
|
}
|
|
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool WINAPI SaveSettings(void) {
|
|
static TCHAR szField[25];
|
|
int nBufLen = BUFFER_SIZE;
|
|
TCHAR *pszBuffer = (TCHAR*)MALLOC(nBufLen*sizeof(TCHAR));
|
|
if (!pszBuffer) return false;
|
|
|
|
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_CHECKBOX:
|
|
case FIELD_RADIOBUTTON:
|
|
wsprintf(pszBuffer, _T("%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 = (TCHAR*)MALLOC(nBufLen*sizeof(TCHAR));
|
|
if (!pszBuffer) return false;
|
|
}
|
|
TCHAR *pszItem = (TCHAR*)MALLOC(nBufLen*sizeof(TCHAR));
|
|
if (!pszItem) return false;
|
|
|
|
*pszBuffer = _T('\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, _T("|"));
|
|
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 = (TCHAR*)MALLOC(nBufLen*sizeof(TCHAR));
|
|
if (!pszBuffer) return false;
|
|
}
|
|
*pszBuffer=_T('"');
|
|
GetWindowText(hwnd, pszBuffer+1, nBufLen-1);
|
|
pszBuffer[nLength+1]=_T('"');
|
|
pszBuffer[nLength+2]=_T('\0');
|
|
|
|
if (pField->nType == FIELD_TEXT && (pField->nFlags & FLAG_MULTILINE))
|
|
{
|
|
TCHAR *pszBuf2 = (TCHAR*)MALLOC(nBufLen*2*sizeof(TCHAR)); // double the size, consider the worst case, all chars are \r\n
|
|
TCHAR *p1, *p2;
|
|
for (p1 = pszBuffer, p2 = pszBuf2; *p1; p1 = CharNext(p1), p2 = CharNext(p2))
|
|
{
|
|
switch (*p1) {
|
|
case _T('\t'):
|
|
*(LPWORD)p2 = CHAR2_TO_WORD('\\', 't');
|
|
p2++;
|
|
break;
|
|
case _T('\n'):
|
|
*(LPWORD)p2 = CHAR2_TO_WORD('\\', 'n');
|
|
p2++;
|
|
break;
|
|
case _T('\r'):
|
|
*(LPWORD)p2 = CHAR2_TO_WORD('\\', 'r');
|
|
p2++;
|
|
break;
|
|
case _T('\\'):
|
|
*p2++ = '\\';
|
|
// Jim Park: used to be p2++ but that's a bug that works because
|
|
// CharNext()'s behavior at terminating null char. But still
|
|
// definitely, unsafe.
|
|
default:
|
|
lstrcpyn(p2, p1, CharNext(p1) - p1 + 1);
|
|
break;
|
|
}
|
|
}
|
|
*p2 = 0;
|
|
nBufLen = nBufLen*2;
|
|
FREE(pszBuffer);
|
|
pszBuffer=pszBuf2;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
wsprintf(szField, _T("Field %d"), CurrField);
|
|
WritePrivateProfileString(szField, _T("State"), pszBuffer, pszFilename);
|
|
}
|
|
|
|
// Tell NSIS which control was activated, if any
|
|
wsprintf(pszBuffer, _T("%d"), g_NotifyField);
|
|
WritePrivateProfileString(_T("Settings"), _T("State"), pszBuffer, pszFilename);
|
|
|
|
FREE(pszBuffer);
|
|
|
|
return true;
|
|
}
|
|
|
|
#define BROWSE_WIDTH 15
|
|
|
|
static TCHAR szResult[BUFFER_SIZE];
|
|
TCHAR *pszAppName;
|
|
|
|
DWORD WINAPI myGetProfileString(LPCTSTR lpKeyName)
|
|
{
|
|
*szResult = _T('\0');
|
|
return GetPrivateProfileString(pszAppName, lpKeyName, _T(""), szResult, BUFFER_SIZE, pszFilename);
|
|
}
|
|
|
|
TCHAR * WINAPI myGetProfileStringDup(LPCTSTR lpKeyName)
|
|
{
|
|
int nSize = myGetProfileString(lpKeyName);
|
|
if (nSize)
|
|
return strdup(szResult); // uses STRDUP
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
UINT WINAPI myGetProfileInt(LPCTSTR lpKeyName, INT nDefault)
|
|
{
|
|
return GetPrivateProfileInt(pszAppName, lpKeyName, nDefault, pszFilename);
|
|
}
|
|
|
|
int WINAPI ReadSettings(void) {
|
|
static TCHAR szField[25];
|
|
int nIdx, nCtrlIdx;
|
|
|
|
pszAppName = _T("Settings");
|
|
pszTitle = myGetProfileStringDup(_T("Title"));
|
|
pszCancelButtonText = myGetProfileStringDup(_T("CancelButtonText"));
|
|
pszNextButtonText = myGetProfileStringDup(_T("NextButtonText"));
|
|
pszBackButtonText = myGetProfileStringDup(_T("BackButtonText"));
|
|
|
|
nNumFields = myGetProfileInt(_T("NumFields"), 0);
|
|
|
|
nRectId = myGetProfileInt(_T("Rect"), DEFAULT_RECT);
|
|
|
|
bBackEnabled = myGetProfileInt(_T("BackEnabled"), -1);
|
|
// by ORTIM: 13-August-2002
|
|
bCancelEnabled = myGetProfileInt(_T("CancelEnabled"), -1);
|
|
bCancelShow = myGetProfileInt(_T("CancelShow"), -1);
|
|
|
|
bRTL = myGetProfileInt(_T("RTL"), 0);
|
|
|
|
if (nNumFields > 0) {
|
|
// make this twice as large for the worst case that every control is a browse button.
|
|
// the structure is small enough that this won't waste much memory.
|
|
// if the structure gets much larger, we should switch to a linked list.
|
|
pFields = (FieldType *)MALLOC(sizeof(FieldType)*2*nNumFields);
|
|
}
|
|
|
|
for (nIdx = 0, nCtrlIdx = 0; nCtrlIdx < nNumFields; nCtrlIdx++, nIdx++) {
|
|
// Control types
|
|
static TableEntry TypeTable[] = {
|
|
{ _T("LABEL"), FIELD_LABEL },
|
|
{ _T("TEXT"), FIELD_TEXT },
|
|
{ _T("PASSWORD"), FIELD_TEXT },
|
|
{ _T("LISTBOX"), FIELD_LISTBOX },
|
|
{ _T("COMBOBOX"), FIELD_COMBOBOX },
|
|
{ _T("DROPLIST"), FIELD_COMBOBOX },
|
|
{ _T("FILEREQUEST"), FIELD_FILEREQUEST },
|
|
{ _T("DIRREQUEST"), FIELD_DIRREQUEST },
|
|
{ _T("CHECKBOX"), FIELD_CHECKBOX },
|
|
{ _T("RADIOBUTTON"), FIELD_RADIOBUTTON },
|
|
{ _T("ICON"), FIELD_ICON },
|
|
{ _T("BITMAP"), FIELD_BITMAP },
|
|
{ _T("GROUPBOX"), FIELD_GROUPBOX },
|
|
#ifdef IO_ENABLE_LINK
|
|
{ _T("LINK"), FIELD_LINK },
|
|
#else
|
|
{ _T("LINK"), FIELD_LABEL },
|
|
#endif
|
|
{ _T("BUTTON"), FIELD_BUTTON },
|
|
{ _T("HLINE"), FIELD_HLINE },
|
|
{ _T("VLINE"), FIELD_VLINE },
|
|
{ NULL, 0 }
|
|
};
|
|
// Control flags
|
|
static TableEntry FlagTable[] = {
|
|
{ _T("NOTIFY"), LBS_NOTIFY },
|
|
{ _T("WARN_IF_EXIST"), OFN_OVERWRITEPROMPT },
|
|
{ _T("FILE_HIDEREADONLY"), OFN_HIDEREADONLY },
|
|
{ _T("MULTISELECT"), LBS_MULTIPLESEL },
|
|
{ _T("READONLY"), FLAG_READONLY },
|
|
{ _T("RIGHT"), BS_LEFTTEXT },
|
|
{ _T("PASSWORD"), FLAG_PASSWORD },
|
|
{ _T("ONLY_NUMBERS"), FLAG_ONLYNUMBERS },
|
|
{ _T("MULTILINE"), FLAG_MULTILINE },
|
|
{ _T("NOWORDWRAP"), FLAG_NOWORDWRAP },
|
|
{ _T("WANTRETURN"), FLAG_WANTRETURN },
|
|
{ _T("EXTENDEDSELCT"), LBS_EXTENDEDSEL },
|
|
{ _T("PATH_MUST_EXIST"), OFN_PATHMUSTEXIST },
|
|
{ _T("FILE_MUST_EXIST"), OFN_FILEMUSTEXIST },
|
|
{ _T("PROMPT_CREATE"), OFN_CREATEPROMPT },
|
|
{ _T("DROPLIST"), FLAG_DROPLIST },
|
|
{ _T("RESIZETOFIT"), FLAG_RESIZETOFIT },
|
|
{ _T("NOTABSTOP"), WS_TABSTOP },
|
|
{ _T("GROUP"), WS_GROUP },
|
|
{ _T("REQ_SAVE"), FLAG_SAVEAS },
|
|
{ _T("FILE_EXPLORER"), OFN_EXPLORER },
|
|
{ _T("HSCROLL"), WS_HSCROLL },
|
|
{ _T("VSCROLL"), WS_VSCROLL },
|
|
{ _T("DISABLED"), WS_DISABLED },
|
|
{ _T("TRANSPARENT"), TRANSPARENT_BMP },
|
|
{ _T("FOCUS"), FLAG_FOCUS },
|
|
{ NULL, 0 }
|
|
};
|
|
FieldType *pField = pFields + nIdx;
|
|
|
|
pField->nField = nCtrlIdx + 1;
|
|
pField->pszHwndEntry = _T("HWND");
|
|
|
|
wsprintf(szField, _T("Field %d"), nCtrlIdx + 1);
|
|
pszAppName = szField;
|
|
|
|
// Get the control type
|
|
myGetProfileString(_T("TYPE"));
|
|
pField->nType = LookupToken(TypeTable, szResult);
|
|
if (pField->nType == FIELD_INVALID)
|
|
continue;
|
|
|
|
// Lookup flags associated with the control type
|
|
pField->nFlags = LookupToken(FlagTable, szResult);
|
|
myGetProfileString(_T("Flags"));
|
|
pField->nFlags |= LookupTokens(FlagTable, szResult);
|
|
|
|
// pszState must not be NULL!
|
|
myGetProfileString(_T("State"));
|
|
pField->pszState = strdup(szResult); // uses STRDUP
|
|
|
|
// ListBox items list
|
|
{
|
|
int nResult = myGetProfileString(_T("ListItems"));
|
|
if (nResult) {
|
|
// add an extra | character to the end to simplify the loop where we add the items.
|
|
pField->pszListItems = (TCHAR*)MALLOC((nResult + 2)*sizeof(TCHAR));
|
|
lstrcpy(pField->pszListItems, szResult);
|
|
pField->pszListItems[nResult] = _T('|');
|
|
pField->pszListItems[nResult + 1] = _T('\0');
|
|
}
|
|
}
|
|
|
|
// Label Text - convert newline
|
|
pField->pszText = myGetProfileStringDup(_T("TEXT"));
|
|
if (pField->nType == FIELD_LABEL || pField->nType == FIELD_LINK)
|
|
ConvertNewLines(pField->pszText);
|
|
|
|
// Dir request - root folder
|
|
pField->pszRoot = myGetProfileStringDup(_T("ROOT"));
|
|
|
|
// ValidateText - convert newline
|
|
pField->pszValidateText = myGetProfileStringDup(_T("ValidateText"));
|
|
ConvertNewLines(pField->pszValidateText);
|
|
|
|
{
|
|
int nResult = GetPrivateProfileString(szField, _T("Filter"), _T("All Files|*.*"), szResult, _countof(szResult), pszFilename);
|
|
if (nResult) {
|
|
// Convert the filter to the format required by Windows: NULL after each
|
|
// item followed by a terminating NULL
|
|
pField->pszFilter = (TCHAR*)MALLOC((nResult + 2)*sizeof(TCHAR));
|
|
lstrcpy(pField->pszFilter, szResult);
|
|
TCHAR *pszPos = pField->pszFilter;
|
|
while (*pszPos)
|
|
{
|
|
if (*pszPos == _T('|'))
|
|
*pszPos++ = 0;
|
|
else
|
|
pszPos = CharNext(pszPos);
|
|
}
|
|
}
|
|
}
|
|
|
|
pField->rect.left = myGetProfileInt(_T("LEFT"), 0);
|
|
pField->rect.top = myGetProfileInt(_T("TOP"), 0);
|
|
pField->rect.right = myGetProfileInt(_T("RIGHT"), 0);
|
|
pField->rect.bottom = myGetProfileInt(_T("BOTTOM"), 0);
|
|
pField->nMinLength = myGetProfileInt(_T("MinLen"), 0);
|
|
pField->nMaxLength = myGetProfileInt(_T("MaxLen"), 0);
|
|
|
|
// Text color for LINK control, default is pure blue
|
|
pField->hImage = (HANDLE)myGetProfileInt(_T("TxtColor"), RGB(0,0,255));
|
|
|
|
pField->nControlID = 1200 + nIdx;
|
|
if (pField->nType == FIELD_FILEREQUEST || pField->nType == FIELD_DIRREQUEST)
|
|
{
|
|
FieldType *pNewField = &pFields[nIdx+1];
|
|
pNewField->nControlID = 1200 + nIdx + 1;
|
|
pNewField->nType = FIELD_BROWSEBUTTON;
|
|
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;
|
|
pNewField->rect.bottom = pField->rect.bottom;
|
|
pNewField->rect.top = pField->rect.top;
|
|
pField->rect.right = pNewField->rect.left - 3;
|
|
pNewField->nField = nCtrlIdx + 1;
|
|
pNewField->pszHwndEntry = _T("HWND2");
|
|
nNumFields++;
|
|
nIdx++;
|
|
}
|
|
}
|
|
|
|
return nNumFields;
|
|
}
|
|
|
|
LRESULT WINAPI WMCommandProc(HWND hWnd, UINT id, HWND hwndCtl, UINT codeNotify) {
|
|
int nIdx = FindControlIdx(id);
|
|
// Ignore if the dialog is in the process of being created
|
|
if (g_done || nIdx < 0)
|
|
return 0;
|
|
|
|
switch (pFields[nIdx].nType)
|
|
{
|
|
case FIELD_BROWSEBUTTON:
|
|
--nIdx;
|
|
case FIELD_LINK:
|
|
case FIELD_BUTTON:
|
|
case FIELD_CHECKBOX:
|
|
case FIELD_RADIOBUTTON:
|
|
if (codeNotify != BN_CLICKED)
|
|
return 0;
|
|
break;
|
|
case FIELD_COMBOBOX:
|
|
case FIELD_LISTBOX:
|
|
if (codeNotify != LBN_SELCHANGE) // LBN_SELCHANGE == CBN_SELCHANGE
|
|
return 0;
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
|
|
FieldType *pField = pFields + nIdx;
|
|
|
|
TCHAR szBrowsePath[MAX_PATH];
|
|
|
|
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 = _countof(szBrowsePath);
|
|
ofn.Flags = pField->nFlags & (OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_CREATEPROMPT | OFN_EXPLORER);
|
|
|
|
GetWindowText(pField->hwnd, szBrowsePath, _countof(szBrowsePath));
|
|
|
|
tryagain:
|
|
GetCurrentDirectory(BUFFER_SIZE, szResult); // save working dir
|
|
if ((pField->nFlags & FLAG_SAVEAS) ? GetSaveFileName(&ofn) : GetOpenFileName(&ofn)) {
|
|
mySetWindowText(pField->hwnd, szBrowsePath);
|
|
SetCurrentDirectory(szResult); // restore working dir
|
|
// OFN_NOCHANGEDIR doesn't always work (see MSDN)
|
|
break;
|
|
}
|
|
else if (szBrowsePath[0] && CommDlgExtendedError() == FNERR_INVALIDFILENAME) {
|
|
szBrowsePath[0] = _T('\0');
|
|
goto tryagain;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
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)) {
|
|
mySetWindowText(pField->hwnd, szBrowsePath);
|
|
}
|
|
|
|
CoTaskMemFree(pResult);
|
|
|
|
break;
|
|
}
|
|
|
|
case FIELD_LINK:
|
|
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 & LBS_NOTIFY) {
|
|
// Remember which control was activated then pretend the user clicked Next
|
|
g_NotifyField = nIdx + 1;
|
|
mySendMessage(hMainWindow, WM_NOTIFY_OUTER_NEXT, 1, 0);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void *lpWndProcOld;
|
|
|
|
int g_is_cancel,g_is_back;
|
|
|
|
BOOL CALLBACK ParentWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
BOOL bRes;
|
|
if (message == WM_NOTIFY_OUTER_NEXT && wParam == 1)
|
|
{
|
|
// Don't call leave function if fields aren't valid
|
|
if (!g_NotifyField && !ValidateFields())
|
|
return 0;
|
|
// Get the settings ready for the leave function verification
|
|
SaveSettings();
|
|
// Reset the record of activated control
|
|
g_NotifyField = 0;
|
|
}
|
|
bRes = CallWindowProc((long (__stdcall *)(struct HWND__ *,unsigned int,unsigned int,long))lpWndProcOld,hwnd,message,wParam,lParam);
|
|
if (message == WM_NOTIFY_OUTER_NEXT && !bRes)
|
|
{
|
|
// if leave function didn't abort (bRes != 0 in that case)
|
|
if (wParam == (WPARAM)-1)
|
|
g_is_back++;
|
|
if (wParam == NOTIFY_BYE_BYE)
|
|
g_is_cancel++;
|
|
g_done++;
|
|
PostMessage(hConfigWindow,WM_CLOSE,0,0);
|
|
}
|
|
return bRes;
|
|
}
|
|
|
|
BOOL CALLBACK cfgDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
HANDLE_MSG(hwndDlg, WM_COMMAND, WMCommandProc);
|
|
case WM_DRAWITEM:
|
|
{
|
|
DRAWITEMSTRUCT* lpdis = (DRAWITEMSTRUCT*)lParam;
|
|
int nIdx = FindControlIdx(lpdis->CtlID);
|
|
#ifdef IO_LINK_UNDERLINED
|
|
HFONT OldFont;
|
|
LOGFONT lf;
|
|
#endif
|
|
|
|
if (nIdx < 0)
|
|
break;
|
|
FieldType *pField = pFields + nIdx;
|
|
|
|
#ifdef IO_LINK_UNDERLINED
|
|
GetObject(GetCurrentObject(lpdis->hDC, OBJ_FONT), sizeof(lf), &lf);
|
|
lf.lfUnderline = TRUE;
|
|
OldFont = (HFONT)SelectObject(lpdis->hDC, CreateFontIndirect(&lf));
|
|
#endif
|
|
|
|
// We need lpdis->rcItem later
|
|
RECT rc = lpdis->rcItem;
|
|
|
|
// Calculate needed size of the control
|
|
DrawText(lpdis->hDC, pField->pszText, -1, &rc, DT_VCENTER | DT_WORDBREAK | 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)
|
|
{
|
|
rc.left += lpdis->rcItem.right - rc.right;
|
|
rc.right += lpdis->rcItem.right - rc.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_WORDBREAK | (bRTL ? DT_RTLREADING : 0));
|
|
}
|
|
|
|
// Draw the focus rect if needed
|
|
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);
|
|
}
|
|
|
|
pField->rect = rc;
|
|
|
|
#ifdef IO_LINK_UNDERLINED
|
|
DeleteObject(SelectObject(lpdis->hDC, OldFont));
|
|
#endif
|
|
break;
|
|
}
|
|
case WM_CTLCOLORSTATIC:
|
|
case WM_CTLCOLOREDIT:
|
|
case WM_CTLCOLORDLG:
|
|
case WM_CTLCOLORBTN:
|
|
case WM_CTLCOLORLISTBOX:
|
|
// let the NSIS window handle colors, it knows best
|
|
return mySendMessage(hMainWindow, uMsg, wParam, lParam);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#ifdef IO_ENABLE_LINK
|
|
|
|
#ifndef IDC_HAND
|
|
#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, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
int StaticField = FindControlIdx(GetDlgCtrlID(hWin));
|
|
if (StaticField < 0)
|
|
return 0;
|
|
FieldType *pField = pFields + StaticField;
|
|
|
|
switch(uMsg)
|
|
{
|
|
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:
|
|
{
|
|
if ((HWND)wParam == hWin && LOWORD(lParam) == HTCLIENT)
|
|
{
|
|
HCURSOR hCur = LoadCursor(NULL, IDC_HAND);
|
|
if (hCur)
|
|
{
|
|
SetCursor(hCur);
|
|
return 1; // halt further processing
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return CallWindowProc((WNDPROC)pField->nParentIdx, hWin, uMsg, wParam, lParam);
|
|
}
|
|
#endif
|
|
|
|
int WINAPI NumbersOnlyPasteWndProc(HWND hWin, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
int nIdx = FindControlIdx(GetDlgCtrlID(hWin));
|
|
if (nIdx < 0)
|
|
return 0;
|
|
|
|
FieldType *pField = pFields + nIdx;
|
|
|
|
if (uMsg == WM_PASTE)
|
|
{
|
|
if (OpenClipboard(hWin))
|
|
{
|
|
HGLOBAL hData = GetClipboardData(CF_TEXT);
|
|
|
|
if (hData)
|
|
{
|
|
TCHAR *lpData = (TCHAR *) GlobalLock(hData);
|
|
if (lpData)
|
|
{
|
|
int iLen = lstrlen(lpData);
|
|
TCHAR *lpFilteredData = (TCHAR *) MALLOC((iLen + 1)*sizeof(TCHAR));
|
|
|
|
if (lpFilteredData)
|
|
{
|
|
for (int i = 0, j = 0; i < iLen; i++)
|
|
{
|
|
if (lpData[i] >= _T('0') && lpData[i] <= _T('9'))
|
|
{
|
|
lpFilteredData[j] = lpData[i];
|
|
j++;
|
|
}
|
|
lpFilteredData[j] = 0;
|
|
}
|
|
|
|
SendMessage(hWin, EM_REPLACESEL, TRUE, (LPARAM) lpFilteredData);
|
|
FREE(lpFilteredData);
|
|
}
|
|
|
|
GlobalUnlock(hData);
|
|
}
|
|
}
|
|
|
|
CloseClipboard();
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return CallWindowProc((WNDPROC) pField->wndProc, hWin, uMsg, wParam, lParam);
|
|
}
|
|
|
|
int old_cancel_visible;
|
|
|
|
int WINAPI createCfgDlg()
|
|
{
|
|
g_is_back=0;
|
|
g_is_cancel=0;
|
|
|
|
HWND mainwnd = hMainWindow;
|
|
if (!mainwnd)
|
|
{
|
|
popstring(NULL);
|
|
pushstring(_T("error finding mainwnd"));
|
|
return 1; // cannot be used in silent mode unfortunately.
|
|
}
|
|
|
|
if (!g_stacktop || !*g_stacktop || !(pszFilename = (*g_stacktop)->text) || !pszFilename[0] || !ReadSettings())
|
|
{
|
|
popstring(NULL);
|
|
pushstring(_T("error finding config"));
|
|
return 1;
|
|
}
|
|
|
|
HWND childwnd=GetDlgItem(mainwnd,nRectId);
|
|
if (!childwnd)
|
|
{
|
|
popstring(NULL);
|
|
pushstring(_T("error finding childwnd"));
|
|
return 1;
|
|
}
|
|
|
|
hCancelButton = GetDlgItem(mainwnd,IDCANCEL);
|
|
hNextButton = GetDlgItem(mainwnd,IDOK);
|
|
hBackButton = GetDlgItem(mainwnd,3);
|
|
|
|
mySetWindowText(hCancelButton,pszCancelButtonText);
|
|
mySetWindowText(hNextButton,pszNextButtonText);
|
|
mySetWindowText(hBackButton,pszBackButtonText);
|
|
|
|
if (bBackEnabled!=-1) EnableWindow(hBackButton,bBackEnabled);
|
|
if (bCancelEnabled!=-1)
|
|
{
|
|
EnableWindow(hCancelButton,bCancelEnabled);
|
|
if (bCancelEnabled)
|
|
EnableMenuItem(GetSystemMenu(mainwnd, FALSE), SC_CLOSE, MF_BYCOMMAND | MF_ENABLED);
|
|
else
|
|
EnableMenuItem(GetSystemMenu(mainwnd, FALSE), SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
|
|
}
|
|
if (bCancelShow!=-1) old_cancel_visible=ShowWindow(hCancelButton,bCancelShow?SW_SHOWNA:SW_HIDE);
|
|
|
|
HFONT hFont = (HFONT)mySendMessage(mainwnd, WM_GETFONT, 0, 0);
|
|
|
|
// Prevent WM_COMMANDs from being processed while we are building
|
|
g_done = 1;
|
|
|
|
int mainWndWidth, mainWndHeight;
|
|
hConfigWindow=CreateDialog(m_hInstance,MAKEINTRESOURCE(IDD_DIALOG1),mainwnd,cfgDlgProc);
|
|
if (hConfigWindow)
|
|
{
|
|
RECT dialog_r;
|
|
GetWindowRect(childwnd,&dialog_r);
|
|
MapWindowPoints(0, mainwnd, (LPPOINT) &dialog_r, 2);
|
|
mainWndWidth = dialog_r.right - dialog_r.left;
|
|
mainWndHeight = dialog_r.bottom - dialog_r.top;
|
|
SetWindowPos(
|
|
hConfigWindow,
|
|
0,
|
|
dialog_r.left,
|
|
dialog_r.top,
|
|
mainWndWidth,
|
|
mainWndHeight,
|
|
SWP_NOZORDER|SWP_NOACTIVATE
|
|
);
|
|
// Sets the font of IO window to be the same as the main window
|
|
mySendMessage(hConfigWindow, WM_SETFONT, (WPARAM)hFont, TRUE);
|
|
}
|
|
else
|
|
{
|
|
popstring(NULL);
|
|
pushstring(_T("error creating dialog"));
|
|
return 1;
|
|
}
|
|
|
|
BOOL fFocused = FALSE;
|
|
BOOL fFocusedByFlag = FALSE;
|
|
|
|
#define DEFAULT_STYLES (WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS)
|
|
#define RTL_EX_STYLES (WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR)
|
|
|
|
for (int nIdx = 0; nIdx < nNumFields; nIdx++) {
|
|
static struct {
|
|
TCHAR* pszClass;
|
|
DWORD dwStyle;
|
|
DWORD dwRTLStyle;
|
|
DWORD dwExStyle;
|
|
DWORD dwRTLExStyle;
|
|
} ClassTable[] = {
|
|
{ _T("STATIC"), // FIELD_HLINE
|
|
DEFAULT_STYLES | SS_ETCHEDHORZ | SS_SUNKEN,
|
|
DEFAULT_STYLES | SS_ETCHEDHORZ | SS_SUNKEN,
|
|
WS_EX_TRANSPARENT,
|
|
WS_EX_TRANSPARENT | RTL_EX_STYLES },
|
|
{ _T("STATIC"), // FIELD_VLINE
|
|
DEFAULT_STYLES | SS_ETCHEDVERT | SS_SUNKEN,
|
|
DEFAULT_STYLES | SS_ETCHEDVERT | SS_SUNKEN,
|
|
WS_EX_TRANSPARENT,
|
|
WS_EX_TRANSPARENT | RTL_EX_STYLES },
|
|
{ _T("STATIC"), // FIELD_LABEL
|
|
DEFAULT_STYLES,
|
|
DEFAULT_STYLES | SS_RIGHT,
|
|
WS_EX_TRANSPARENT,
|
|
WS_EX_TRANSPARENT | RTL_EX_STYLES },
|
|
{ _T("STATIC"), // FIELD_ICON
|
|
DEFAULT_STYLES | SS_ICON,
|
|
DEFAULT_STYLES | SS_ICON,
|
|
0,
|
|
RTL_EX_STYLES },
|
|
{ _T("STATIC"), // FIELD_BITMAP
|
|
DEFAULT_STYLES | SS_BITMAP,
|
|
DEFAULT_STYLES | SS_BITMAP,
|
|
0,
|
|
RTL_EX_STYLES },
|
|
{ _T("BUTTON"), // FIELD_BROWSEBUTTON
|
|
DEFAULT_STYLES | WS_TABSTOP,
|
|
DEFAULT_STYLES | WS_TABSTOP,
|
|
0,
|
|
RTL_EX_STYLES },
|
|
{ _T("BUTTON"), // FIELD_LINK
|
|
DEFAULT_STYLES | WS_TABSTOP | BS_OWNERDRAW,
|
|
DEFAULT_STYLES | WS_TABSTOP | BS_OWNERDRAW | BS_RIGHT,
|
|
0,
|
|
RTL_EX_STYLES },
|
|
{ _T("BUTTON"), // FIELD_BUTTON
|
|
DEFAULT_STYLES | WS_TABSTOP,
|
|
DEFAULT_STYLES | WS_TABSTOP,
|
|
0,
|
|
RTL_EX_STYLES },
|
|
{ _T("BUTTON"), // FIELD_GROUPBOX
|
|
DEFAULT_STYLES | BS_GROUPBOX,
|
|
DEFAULT_STYLES | BS_GROUPBOX | BS_RIGHT,
|
|
WS_EX_TRANSPARENT,
|
|
WS_EX_TRANSPARENT | RTL_EX_STYLES },
|
|
{ _T("BUTTON"), // FIELD_CHECKBOX
|
|
DEFAULT_STYLES | WS_TABSTOP | BS_TEXT | BS_VCENTER | BS_AUTOCHECKBOX | BS_MULTILINE,
|
|
DEFAULT_STYLES | WS_TABSTOP | BS_TEXT | BS_VCENTER | BS_AUTOCHECKBOX | BS_MULTILINE | BS_RIGHT | BS_LEFTTEXT,
|
|
0,
|
|
RTL_EX_STYLES },
|
|
{ _T("BUTTON"), // FIELD_RADIOBUTTON
|
|
DEFAULT_STYLES | WS_TABSTOP | BS_TEXT | BS_VCENTER | BS_AUTORADIOBUTTON | BS_MULTILINE,
|
|
DEFAULT_STYLES | WS_TABSTOP | BS_TEXT | BS_VCENTER | BS_AUTORADIOBUTTON | BS_MULTILINE | BS_RIGHT | BS_LEFTTEXT,
|
|
0,
|
|
RTL_EX_STYLES },
|
|
{ _T("EDIT"), // FIELD_TEXT
|
|
DEFAULT_STYLES | WS_TABSTOP | ES_AUTOHSCROLL,
|
|
DEFAULT_STYLES | WS_TABSTOP | ES_AUTOHSCROLL | ES_RIGHT,
|
|
WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
|
|
WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | RTL_EX_STYLES },
|
|
{ _T("EDIT"), // FIELD_FILEREQUEST
|
|
DEFAULT_STYLES | WS_TABSTOP | ES_AUTOHSCROLL,
|
|
DEFAULT_STYLES | WS_TABSTOP | ES_AUTOHSCROLL | ES_RIGHT,
|
|
WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
|
|
WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | RTL_EX_STYLES },
|
|
{ _T("EDIT"), // FIELD_DIRREQUEST
|
|
DEFAULT_STYLES | WS_TABSTOP | ES_AUTOHSCROLL,
|
|
DEFAULT_STYLES | WS_TABSTOP | ES_AUTOHSCROLL | ES_RIGHT,
|
|
WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
|
|
WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | RTL_EX_STYLES },
|
|
{ _T("COMBOBOX"), // FIELD_COMBOBOX
|
|
DEFAULT_STYLES | WS_TABSTOP | WS_VSCROLL | WS_CLIPCHILDREN | CBS_AUTOHSCROLL | CBS_HASSTRINGS,
|
|
DEFAULT_STYLES | WS_TABSTOP | WS_VSCROLL | WS_CLIPCHILDREN | CBS_AUTOHSCROLL | CBS_HASSTRINGS,
|
|
WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
|
|
WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_RIGHT | RTL_EX_STYLES },
|
|
{ _T("LISTBOX"), // FIELD_LISTBOX
|
|
DEFAULT_STYLES | WS_TABSTOP | WS_VSCROLL | LBS_DISABLENOSCROLL | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT,
|
|
DEFAULT_STYLES | WS_TABSTOP | WS_VSCROLL | LBS_DISABLENOSCROLL | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT,
|
|
WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
|
|
WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_RIGHT | RTL_EX_STYLES }
|
|
};
|
|
|
|
FieldType *pField = pFields + nIdx;
|
|
|
|
#undef DEFAULT_STYLES
|
|
|
|
if (pField->nType < 1 || pField->nType > (int)(sizeof(ClassTable) / sizeof(ClassTable[0])))
|
|
continue;
|
|
|
|
DWORD dwStyle, dwExStyle;
|
|
if (bRTL) {
|
|
dwStyle = ClassTable[pField->nType - 1].dwRTLStyle;
|
|
dwExStyle = ClassTable[pField->nType - 1].dwRTLExStyle;
|
|
}
|
|
else {
|
|
dwStyle = ClassTable[pField->nType - 1].dwStyle;
|
|
dwExStyle = ClassTable[pField->nType - 1].dwExStyle;
|
|
}
|
|
|
|
// Convert from dialog units
|
|
|
|
RECT rect = pField->rect;
|
|
// MapDialogRect uses the font used when a dialog is created, and ignores
|
|
// any subsequent WM_SETFONT messages (like we used above); so use the main
|
|
// NSIS window for the conversion, instead of this one.
|
|
MapDialogRect(mainwnd, &rect);
|
|
|
|
if (pField->rect.left < 0)
|
|
rect.left += mainWndWidth;
|
|
if (pField->rect.right < 0)
|
|
rect.right += mainWndWidth;
|
|
if (pField->rect.top < 0)
|
|
rect.top += mainWndHeight;
|
|
if (pField->rect.bottom < 0)
|
|
rect.bottom += mainWndHeight;
|
|
|
|
if (bRTL) {
|
|
int right = rect.right;
|
|
rect.right = mainWndWidth - rect.left;
|
|
rect.left = mainWndWidth - right;
|
|
}
|
|
|
|
TCHAR *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:
|
|
dwStyle ^= pField->nFlags & BS_LEFTTEXT;
|
|
break;
|
|
case FIELD_TEXT:
|
|
case FIELD_FILEREQUEST:
|
|
case FIELD_DIRREQUEST:
|
|
if (pField->nFlags & FLAG_PASSWORD)
|
|
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 & (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;
|
|
}
|
|
break;
|
|
case FIELD_COMBOBOX:
|
|
dwStyle |= (pField->nFlags & FLAG_DROPLIST) ? CBS_DROPDOWNLIST : CBS_DROPDOWN;
|
|
title = pField->pszState;
|
|
break;
|
|
case FIELD_LISTBOX:
|
|
dwStyle |= pField->nFlags & (LBS_NOTIFY | LBS_MULTIPLESEL | LBS_EXTENDEDSEL);
|
|
break;
|
|
}
|
|
|
|
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,
|
|
ClassTable[pField->nType - 1].pszClass,
|
|
title,
|
|
dwStyle,
|
|
rect.left,
|
|
rect.top,
|
|
rect.right - rect.left,
|
|
rect.bottom - rect.top,
|
|
hConfigWindow,
|
|
(HMENU)pField->nControlID,
|
|
m_hInstance,
|
|
NULL
|
|
);
|
|
|
|
{
|
|
TCHAR szField[64];
|
|
TCHAR szHwnd[64];
|
|
wsprintf(szField, _T("Field %d"), pField->nField);
|
|
wsprintf(szHwnd, _T("%d"), hwCtrl);
|
|
WritePrivateProfileString(szField, pField->pszHwndEntry, szHwnd, pszFilename);
|
|
}
|
|
|
|
if (hwCtrl) {
|
|
// Sets the font of IO window to be the same as the main window
|
|
mySendMessage(hwCtrl, WM_SETFONT, (WPARAM)hFont, TRUE);
|
|
// make sure we created the window, then set additional attributes
|
|
switch (pField->nType) {
|
|
case FIELD_TEXT:
|
|
case FIELD_FILEREQUEST:
|
|
case FIELD_DIRREQUEST:
|
|
mySendMessage(hwCtrl, EM_LIMITTEXT, (WPARAM)pField->nMaxLength, (LPARAM)0);
|
|
if (dwStyle & ES_NUMBER)
|
|
{
|
|
pField->wndProc = GetWindowLong(hwCtrl, GWL_WNDPROC);
|
|
SetWindowLong(hwCtrl, GWL_WNDPROC, (long) NumbersOnlyPasteWndProc);
|
|
}
|
|
break;
|
|
|
|
case FIELD_CHECKBOX:
|
|
case FIELD_RADIOBUTTON:
|
|
if (pField->pszState[0] == _T('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;
|
|
}
|
|
else {
|
|
nAddMsg = LB_ADDSTRING;
|
|
nFindMsg = LB_FINDSTRINGEXACT;
|
|
nSetSelMsg = LB_SETCURSEL;
|
|
}
|
|
TCHAR *pszStart, *pszEnd, *pszList;
|
|
pszStart = pszEnd = pszList = STRDUP(pField->pszListItems);
|
|
// pszListItems has a trailing pipe
|
|
while (*pszEnd) {
|
|
if (*pszEnd == _T('|')) {
|
|
*pszEnd = _T('\0');
|
|
if (*pszStart)
|
|
mySendMessage(hwCtrl, nAddMsg, 0, (LPARAM) pszStart);
|
|
pszStart = ++pszEnd;
|
|
}
|
|
else
|
|
pszEnd = CharNext(pszEnd);
|
|
}
|
|
FREE(pszList);
|
|
if (pField->pszState) {
|
|
if (pField->nFlags & (LBS_MULTIPLESEL|LBS_EXTENDEDSEL) && nFindMsg == LB_FINDSTRINGEXACT) {
|
|
mySendMessage(hwCtrl, LB_SETSEL, FALSE, (LPARAM)-1);
|
|
pszStart = pszEnd = pField->pszState;
|
|
for (;;) {
|
|
TCHAR c = *pszEnd;
|
|
if (c == _T('|') || c == _T('\0')) {
|
|
*pszEnd = _T('\0');
|
|
if (*pszStart)
|
|
{
|
|
int nItem = mySendMessage(hwCtrl, LB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)pszStart);
|
|
if (nItem != LB_ERR)
|
|
mySendMessage(hwCtrl, LB_SETSEL, TRUE, nItem);
|
|
}
|
|
if (!c)
|
|
break;
|
|
pszStart = ++pszEnd;
|
|
}
|
|
else
|
|
pszEnd = CharNext(pszEnd);
|
|
}
|
|
}
|
|
else {
|
|
int nItem = mySendMessage(hwCtrl, nFindMsg, (WPARAM)-1, (LPARAM)pField->pszState);
|
|
if (nItem != CB_ERR) { // CB_ERR == LB_ERR == -1
|
|
mySendMessage(hwCtrl, nSetSelMsg, nItem, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
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));
|
|
|
|
if ((pField->nFlags & TRANSPARENT_BMP) && nImageType == IMAGE_BITMAP)
|
|
{
|
|
// based on AdvSplash's SetTransparentRegion
|
|
BITMAP bm;
|
|
HBITMAP hBitmap = (HBITMAP) nImage;
|
|
|
|
if (GetObject(hBitmap, sizeof(bm), &bm))
|
|
{
|
|
HDC dc;
|
|
int x, y;
|
|
HRGN region, cutrgn;
|
|
BITMAPINFO bmi;
|
|
int size = bm.bmWidth * bm.bmHeight * sizeof(int);
|
|
int *bmp = (int *) MALLOC(size);
|
|
if (bmp)
|
|
{
|
|
bmi.bmiHeader.biBitCount = 32;
|
|
bmi.bmiHeader.biCompression = BI_RGB;
|
|
bmi.bmiHeader.biHeight = bm.bmHeight;
|
|
bmi.bmiHeader.biPlanes = 1;
|
|
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
bmi.bmiHeader.biWidth = bm.bmWidth;
|
|
bmi.bmiHeader.biClrUsed = 0;
|
|
bmi.bmiHeader.biClrImportant = 0;
|
|
|
|
dc = CreateCompatibleDC(NULL);
|
|
SelectObject(dc, hBitmap);
|
|
|
|
x = GetDIBits(dc, hBitmap, 0, bm.bmHeight, bmp, &bmi, DIB_RGB_COLORS);
|
|
|
|
region = CreateRectRgn(0, 0, bm.bmWidth, bm.bmHeight);
|
|
|
|
int keycolor = *bmp & 0xFFFFFF;
|
|
|
|
// Search for transparent pixels
|
|
for (y = bm.bmHeight - 1; y >= 0; y--) {
|
|
for (x = 0; x < bm.bmWidth;) {
|
|
if ((*bmp & 0xFFFFFF) == keycolor) {
|
|
int j = x;
|
|
while ((x < bm.bmWidth) && ((*bmp & 0xFFFFFF) == keycolor)) {
|
|
bmp++, x++;
|
|
}
|
|
|
|
// Cut transparent pixels from the original region
|
|
cutrgn = CreateRectRgn(j, y, x, y + 1);
|
|
CombineRgn(region, region, cutrgn, RGN_XOR);
|
|
DeleteObject(cutrgn);
|
|
} else {
|
|
bmp++, x++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set resulting region.
|
|
SetWindowRgn(hwCtrl, region, TRUE);
|
|
DeleteObject(region);
|
|
DeleteObject(dc);
|
|
FREE(bmp);
|
|
}
|
|
}
|
|
}
|
|
|
|
mySendMessage(
|
|
hwCtrl,
|
|
STM_SETIMAGE,
|
|
nImageType,
|
|
nImage
|
|
);
|
|
|
|
if (pField->nType == FIELD_BITMAP)
|
|
{
|
|
// Centre the image in the requested space.
|
|
// Cannot use SS_CENTERIMAGE because it behaves differently on XP to
|
|
// everything else. (Thank you Microsoft.)
|
|
RECT bmp_rect;
|
|
GetClientRect(hwCtrl, &bmp_rect);
|
|
bmp_rect.left = (rect.left + rect.right - bmp_rect.right) / 2;
|
|
bmp_rect.top = (rect.top + rect.bottom - bmp_rect.bottom) / 2;
|
|
SetWindowPos(hwCtrl, NULL, bmp_rect.left, bmp_rect.top, 0, 0,
|
|
SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
#ifdef IO_ENABLE_LINK
|
|
case FIELD_LINK:
|
|
pField->nParentIdx = SetWindowLong(hwCtrl, GWL_WNDPROC, (long)StaticLINKWindowProc);
|
|
break;
|
|
#endif
|
|
}
|
|
|
|
// Set initial focus to the first appropriate field ( with FOCUS flag)
|
|
if (!fFocusedByFlag && (dwStyle & (WS_TABSTOP | WS_DISABLED)) == WS_TABSTOP && pField->nType >= FIELD_SETFOCUS) {
|
|
if (pField->nFlags & FLAG_FOCUS) {
|
|
fFocusedByFlag = TRUE;
|
|
}
|
|
if (!fFocused || fFocusedByFlag) {
|
|
fFocused = TRUE;
|
|
mySetFocus(hwCtrl);
|
|
}
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
|
|
if (!fFocused)
|
|
mySetFocus(hNextButton);
|
|
|
|
mySetWindowText(mainwnd,pszTitle);
|
|
pFilenameStackEntry = *g_stacktop;
|
|
*g_stacktop = (*g_stacktop)->next;
|
|
static TCHAR tmp[32];
|
|
wsprintf(tmp,_T("%d"),hConfigWindow);
|
|
pushstring(tmp);
|
|
return 0;
|
|
}
|
|
|
|
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
|
|
mySendMessage(hMainWindow, WM_NOTIFY_CUSTOM_READY, (WPARAM)hConfigWindow, 0);
|
|
ShowWindow(hConfigWindow, SW_SHOWNA);
|
|
|
|
g_done = g_NotifyField = 0;
|
|
|
|
while (!g_done) {
|
|
MSG msg;
|
|
GetMessage(&msg, NULL, 0, 0);
|
|
if (!IsDialogMessage(hConfigWindow,&msg) && !IsDialogMessage(hMainWindow,&msg))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
|
|
// we don't save settings on cancel since that means your installer will likely
|
|
// quit soon, which means the ini might get flushed late and cause crap. :) anwyay.
|
|
if (!g_is_cancel) SaveSettings();
|
|
|
|
SetWindowLong(hMainWindow,DWL_DLGPROC,(long)lpWndProcOld);
|
|
DestroyWindow(hConfigWindow);
|
|
|
|
// by ORTIM: 13-August-2002
|
|
if (bCancelShow!=-1) ShowWindow(hCancelButton,old_cancel_visible?SW_SHOWNA:SW_HIDE);
|
|
|
|
FREE(pFilenameStackEntry);
|
|
FREE(pszTitle);
|
|
FREE(pszCancelButtonText);
|
|
FREE(pszNextButtonText);
|
|
FREE(pszBackButtonText);
|
|
|
|
int i = nNumFields;
|
|
while (i--) {
|
|
FieldType *pField = pFields + i;
|
|
|
|
int j = FIELD_BUFFERS;
|
|
while (j--)
|
|
FREE(((TCHAR **) pField)[j]);
|
|
|
|
if (pField->nType == FIELD_BITMAP) {
|
|
DeleteObject(pField->hImage);
|
|
}
|
|
if (pField->nType == FIELD_ICON) {
|
|
DestroyIcon((HICON)pField->hImage);
|
|
}
|
|
}
|
|
FREE(pFields);
|
|
|
|
pushstring(g_is_cancel?_T("cancel"):g_is_back?_T("back"):_T("success"));
|
|
}
|
|
|
|
int initCalled;
|
|
|
|
extern "C" void __declspec(dllexport) dialog(HWND hwndParent, int string_size,
|
|
TCHAR *variables, stack_t **stacktop)
|
|
{
|
|
hMainWindow=hwndParent;
|
|
EXDLL_INIT();
|
|
if (initCalled) {
|
|
pushstring(_T("error"));
|
|
return;
|
|
}
|
|
if (createCfgDlg())
|
|
return;
|
|
popstring(NULL);
|
|
showCfgDlg();
|
|
}
|
|
|
|
static UINT_PTR PluginCallback(enum NSPIM msg)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
extern "C" void __declspec(dllexport) initDialog(HWND hwndParent, int string_size,
|
|
TCHAR *variables, stack_t **stacktop,
|
|
extra_parameters *extra)
|
|
{
|
|
hMainWindow=hwndParent;
|
|
EXDLL_INIT();
|
|
|
|
extra->RegisterPluginCallback(m_hInstance, PluginCallback);
|
|
|
|
if (initCalled) {
|
|
pushstring(_T("error"));
|
|
return;
|
|
}
|
|
if (createCfgDlg())
|
|
return;
|
|
initCalled++;
|
|
}
|
|
|
|
extern "C" void __declspec(dllexport) show(HWND hwndParent, int string_size,
|
|
TCHAR *variables, stack_t **stacktop)
|
|
{
|
|
EXDLL_INIT();
|
|
if (!initCalled) {
|
|
pushstring(_T("error"));
|
|
return;
|
|
}
|
|
initCalled--;
|
|
showCfgDlg();
|
|
}
|
|
|
|
extern "C" BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
|
|
{
|
|
m_hInstance=(HINSTANCE) hInst;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/**
|
|
* Looks up a single token in the psTable_ and returns its mapped numerical value.
|
|
*
|
|
* @param psTable_ The lookup table.
|
|
* @param pszToken_ The token to lookup.
|
|
* @return The integer value related to the token, otherwise 0.
|
|
*/
|
|
int WINAPI LookupToken(TableEntry* psTable_, TCHAR* pszToken_)
|
|
{
|
|
for (int i = 0; psTable_[i].pszName; i++)
|
|
if (!lstrcmpi(pszToken_, psTable_[i].pszName))
|
|
return psTable_[i].nValue;
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* In a string of tokens separated by vertical bars '|', look them up in the
|
|
* Lookup Table psTable and return their logical OR of their subsequent
|
|
* integer values.
|
|
*
|
|
* @param psTable_ The lookup table to search in.
|
|
* @param pszToken String of tokens separated by '|' whose values are to be
|
|
* ORed together.
|
|
* @return The ORed value of the token values. If no tokens were found, it
|
|
* will return 0.
|
|
*/
|
|
int WINAPI LookupTokens(TableEntry* psTable_, TCHAR* pszTokens_)
|
|
{
|
|
int n = 0;
|
|
TCHAR *pszStart = pszTokens_;
|
|
TCHAR *pszEnd = pszTokens_;
|
|
for (;;) {
|
|
TCHAR c = *pszEnd;
|
|
if (c == _T('|') || c == _T('\0')) {
|
|
*pszEnd = _T('\0');
|
|
n |= LookupToken(psTable_, pszStart);
|
|
*pszEnd = c;
|
|
if (!c)
|
|
break;
|
|
pszStart = ++pszEnd;
|
|
}
|
|
else
|
|
pszEnd = CharNext(pszEnd);
|
|
}
|
|
return n;
|
|
}
|
|
|
|
/**
|
|
* ConvertNewLines takes a string and turns escape sequences written
|
|
* as separate chars e.g. "\\t" into the special char they represent
|
|
* '\t'. The transformation is done in place.
|
|
*
|
|
* @param str [in/out] The string to convert.
|
|
*/
|
|
void WINAPI ConvertNewLines(TCHAR *str) {
|
|
TCHAR *p1, *p2, *p3;
|
|
|
|
if (!str)
|
|
return;
|
|
|
|
p1 = p2 = str;
|
|
|
|
while (*p1)
|
|
{
|
|
switch (*(LPWORD)p1)
|
|
{
|
|
case CHAR2_TO_WORD(_T('\\'), _T('t')):
|
|
*p2 = _T('\t');
|
|
p1 += 2;
|
|
p2++;
|
|
break;
|
|
case CHAR2_TO_WORD(_T('\\'), _T('n')):
|
|
*p2 = _T('\n');
|
|
p1 += 2;
|
|
p2++;
|
|
break;
|
|
case CHAR2_TO_WORD(_T('\\'), _T('r')):
|
|
*p2 = _T('\r');
|
|
p1 += 2;
|
|
p2++;
|
|
break;
|
|
case CHAR2_TO_WORD(_T('\\'), _T('\\')):
|
|
*p2 = _T('\\');
|
|
p1 += 2;
|
|
p2++;
|
|
break;
|
|
default:
|
|
p3 = CharNext(p1);
|
|
while (p1 < p3)
|
|
*p2++ = *p1++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
*p2 = 0;
|
|
}
|