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_TEXT) { nLength = mySendMessage(pField->hwnd, WM_GETTEXTLENGTH, 0, 0); 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); } mySetFocus(pField->hwnd); return false; } } } return true; }
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; }
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(((char **) 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?"cancel":g_is_back?"back":"success"); }
int WINAPI createCfgDlg() { g_is_back=0; g_is_cancel=0; HWND mainwnd = hMainWindow; if (!mainwnd) { popstring(NULL); pushstring("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("error finding config"); return 1; } HWND childwnd=GetDlgItem(mainwnd,nRectId); if (!childwnd) { popstring(NULL); pushstring("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 (bCancelShow!=-1) old_cancel_visible=ShowWindow(hCancelButton,bCancelShow?SW_SHOWNA:SW_HIDE); HFONT hFont = (HFONT)mySendMessage(mainwnd, WM_GETFONT, 0, 0); RECT dialog_r; int mainWndWidth, mainWndHeight; hConfigWindow=CreateDialog(m_hInstance,MAKEINTRESOURCE(IDD_DIALOG1),mainwnd,cfgDlgProc); if (hConfigWindow) { 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("error creating dialog"); return 1; } // Init dialog unit conversion HDC memDC = CreateCompatibleDC(GetDC(hConfigWindow)); SelectObject(memDC, hFont); TEXTMETRIC tm; GetTextMetrics(memDC, &tm); int baseUnitY = tm.tmHeight; SIZE size; GetTextExtentPoint32(memDC,"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 52, &size); int baseUnitX = (size.cx / 26 + 1) / 2; DeleteDC(memDC); BOOL fFocused = FALSE; #define DEFAULT_STYLES (WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS) for (int nIdx = 0; nIdx < nNumFields; nIdx++) { static struct { char* pszClass; DWORD dwStyle; DWORD dwRTLStyle; DWORD dwExStyle; DWORD dwRTLExStyle; } ClassTable[] = { { "STATIC", // FIELD_LABEL DEFAULT_STYLES, DEFAULT_STYLES | SS_RIGHT, WS_EX_TRANSPARENT, WS_EX_TRANSPARENT | WS_EX_RTLREADING }, { "STATIC", // FIELD_ICON DEFAULT_STYLES | SS_ICON, DEFAULT_STYLES | SS_ICON, 0, WS_EX_RTLREADING }, { "STATIC", // FIELD_BITMAP DEFAULT_STYLES | SS_BITMAP | SS_CENTERIMAGE, DEFAULT_STYLES | SS_BITMAP | SS_CENTERIMAGE, 0, WS_EX_RTLREADING }, { "BUTTON", // FIELD_BROWSEBUTTON DEFAULT_STYLES | WS_TABSTOP, DEFAULT_STYLES | WS_TABSTOP, 0, WS_EX_RTLREADING }, { "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, WS_EX_RTLREADING }, { "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, WS_EX_RTLREADING }, { "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 | WS_EX_RTLREADING }, { "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 | WS_EX_RTLREADING }, { "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 | WS_EX_RTLREADING }, { "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 | WS_EX_RTLREADING }, { "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 | WS_EX_RTLREADING }, { "BUTTON", // FIELD_GROUPBOX DEFAULT_STYLES | BS_GROUPBOX, DEFAULT_STYLES | BS_GROUPBOX | BS_RIGHT, WS_EX_TRANSPARENT, WS_EX_TRANSPARENT | WS_EX_RTLREADING }, { "BUTTON", // FIELD_LINK DEFAULT_STYLES | WS_TABSTOP | BS_OWNERDRAW, DEFAULT_STYLES | WS_TABSTOP | BS_OWNERDRAW | BS_RIGHT, 0, WS_EX_RTLREADING }, { "BUTTON", // FIELD_BUTTON DEFAULT_STYLES | WS_TABSTOP, DEFAULT_STYLES | WS_TABSTOP, 0, WS_EX_RTLREADING } }; FieldType *pField = pFields + nIdx; #undef DEFAULT_STYLES if (pField->nType < 1 || pField->nType > (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; 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 (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; } 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: 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 ); 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); 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; } 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) { mySendMessage(hwCtrl, nAddMsg, 0, (LPARAM)pszStart); } // jump to the next item, skip any redundant | characters do { pszEnd++; } while (*pszEnd == '|'); pszStart = pszEnd; } pszEnd++; } FREE(pszList); if (pField->pszState) { if (pField->nFlags & (LBS_MULTIPLESEL|LBS_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); } } } } 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, nImage ); 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 if (!fFocused && (dwStyle & (WS_TABSTOP | WS_DISABLED)) == WS_TABSTOP) { 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 char tmp[32]; wsprintf(tmp,"%d",hConfigWindow); pushstring(tmp); return 0; }
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_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) { 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_SINGLELINE | (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; }
bool WINAPI SaveSettings(void) { static char szField[25]; int nBufLen = BUFFER_SIZE; char *pszBuffer = (char*)MALLOC(nBufLen); 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, "%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; *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; } } *p2 = 0; nBufLen = nBufLen*2; FREE(pszBuffer); pszBuffer=pszBuf2; } break; } } wsprintf(szField, "Field %d", CurrField); WritePrivateProfileString(szField, "State", pszBuffer, pszFilename); } // Tell NSIS which control was activated, if any wsprintf(pszBuffer, "%d", g_NotifyField); WritePrivateProfileString("Settings", "State", pszBuffer, pszFilename); FREE(pszBuffer); return true; }
void WINAPI mySetFocus(HWND hWnd) { mySendMessage(hMainWindow, WM_NEXTDLGCTL, (WPARAM)hWnd, TRUE); }
int WINAPI createCfgDlg() { g_is_back=0; g_is_cancel=0; HWND mainwnd = hMainWindow; if (!mainwnd) { popstring(NULL); pushstring("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("error finding config"); return 1; } HWND childwnd=GetDlgItem(mainwnd,nRectId); if (!childwnd) { popstring(NULL); pushstring("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 (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("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 { char* pszClass; DWORD dwStyle; DWORD dwRTLStyle; DWORD dwExStyle; DWORD dwRTLExStyle; } ClassTable[] = { { "STATIC", // FIELD_LABEL DEFAULT_STYLES, DEFAULT_STYLES | SS_RIGHT, WS_EX_TRANSPARENT, WS_EX_TRANSPARENT | RTL_EX_STYLES }, { "STATIC", // FIELD_ICON DEFAULT_STYLES | SS_ICON, DEFAULT_STYLES | SS_ICON, 0, RTL_EX_STYLES }, { "STATIC", // FIELD_BITMAP DEFAULT_STYLES | SS_BITMAP, DEFAULT_STYLES | SS_BITMAP, 0, RTL_EX_STYLES }, { "BUTTON", // FIELD_BROWSEBUTTON DEFAULT_STYLES | WS_TABSTOP, DEFAULT_STYLES | WS_TABSTOP, 0, RTL_EX_STYLES }, { "BUTTON", // FIELD_LINK DEFAULT_STYLES | WS_TABSTOP | BS_OWNERDRAW, DEFAULT_STYLES | WS_TABSTOP | BS_OWNERDRAW | BS_RIGHT, 0, RTL_EX_STYLES }, { "BUTTON", // FIELD_BUTTON DEFAULT_STYLES | WS_TABSTOP, DEFAULT_STYLES | WS_TABSTOP, 0, RTL_EX_STYLES }, { "BUTTON", // FIELD_GROUPBOX DEFAULT_STYLES | BS_GROUPBOX, DEFAULT_STYLES | BS_GROUPBOX | BS_RIGHT, WS_EX_TRANSPARENT, WS_EX_TRANSPARENT | RTL_EX_STYLES }, { "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 }, { "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 }, { "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 }, { "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 }, { "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 }, { "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 }, { "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 > (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; } 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: 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 ); { char szField[64]; char szHwnd[64]; wsprintf(szField, "Field %d", pField->nField); wsprintf(szHwnd, "%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] == '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; } char *pszStart, *pszEnd, *pszList; pszStart = pszEnd = pszList = STRDUP(pField->pszListItems); // pszListItems has a trailing pipe while (*pszEnd) { if (*pszEnd == '|') { *pszEnd = '\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 (;;) { char c = *pszEnd; if (c == '|' || c == '\0') { *pszEnd = '\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 char tmp[32]; wsprintf(tmp,"%d",hConfigWindow); pushstring(tmp); return 0; }
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; char 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 = 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: 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] = '\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; }
int main() { // used in control flow int opCode; bool isConnected = false, needQuit = false; // used in network int iResult; WSADATA wsaData; struct addrinfo *result = NULL, hints; SOCKET ConnectSocket = (SOCKET)NULL; char serverName[20], port[10]; // used in multithread DWORD receiveThreadId; HANDLE receiveThread = NULL; // Initialize Winsock iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); if (iResult != 0) { printf("> WSAStartup failed with error: %d\n", iResult); } ZeroMemory(&hints, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; while (!needQuit) { // show menu printf("> Please input option code:\n"); printf(" 1.connect 2.quit"); if (isConnected) { printf(" 3.break 4.get time 5.get name 6.get client 7.send message"); } printf("\n"); scanf_s("%d", &opCode); switch (opCode) { case 1: { printf("> Please input server IP:\n"); getchar(); gets_s(serverName, 20); printf("> Please input port number:\n"); gets_s(port, 10); // Resolve the server address and port iResult = getaddrinfo(serverName, port, &hints, &result); if (iResult != 0) { printf("> Getaddrinfo failed with error: %d\n", iResult); } ConnectSocket = myConnect(result); if (isConnected) { printf("> It's already connected!\n"); } else if (ConnectSocket == INVALID_SOCKET) { printf("> Unable to connect to server!\n"); } else { isConnected = true; receiveThread = CreateThread(NULL, 0, receiveFunction, (LPVOID)ConnectSocket, 0, &receiveThreadId); printf("> Connect success!\n"); } break; } case 2: { needQuit = true; if (isConnected) { closesocket(ConnectSocket); isConnected = false; } printf("> Quit success!\n"); break; } case 3: { closesocket(ConnectSocket); isConnected = false; printf("> Break success!\n"); break; } case 4: { for (int i = 0; i < 1000; ++i) { mySendMessage(ConnectSocket, 4); } break; } case 5: { mySendMessage(ConnectSocket, 5); break; } case 6: { mySendMessage(ConnectSocket, 6); break; } case 7: { mySendMessage(ConnectSocket, 7); break; } default: { // } } Sleep(1000); // wait for receiveThread print printf("\n"); } // cleanup iResult = shutdown(ConnectSocket, SD_SEND); if (iResult == SOCKET_ERROR) { printf("> shutdown failed with error: %d\n", WSAGetLastError()); } freeaddrinfo(result); if (receiveThread != NULL) { CloseHandle(receiveThread); } WSACleanup(); return 0; }