/* * Copyright (c) 2005 Massachusetts Institute of Technology * Copyright (c) 2007 Secure Endpoints Inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /* $Id$ */ /* Include the OEMRESOURCE constants for locating standard icon resources. */ #define OEMRESOURCE #include #include ATOM khui_newcredwnd_cls; /* forward dcl */ static void nc_position_credtext(khui_nc_wnd_data * d); /* Common dialog procedure used by the main credential panel (IDD_NC_NEWCRED) and the button bar (IDC_NC_BBAR). */ static void nc_layout_main_panel(khui_nc_wnd_data * d); static void nc_layout_new_cred_window(khui_nc_wnd_data * d); static INT_PTR CALLBACK nc_common_dlg_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_INITDIALOG: { khui_nc_wnd_data * d; d = (khui_nc_wnd_data *) lParam; #pragma warning(push) #pragma warning(disable: 4244) SetWindowLongPtr(hwnd, DWLP_USER, lParam); #pragma warning(pop) if (d->nc->subtype == KMSG_CRED_PASSWORD) { ShowWindow(GetDlgItem(hwnd, IDC_NC_ADVANCED), SW_HIDE); } } return TRUE; case WM_COMMAND: { int ctrl_id; ctrl_id = LOWORD(wParam); if (ctrl_id < KHUI_CW_ID_MIN || ctrl_id > KHUI_CW_ID_MAX) { /* pump it to the parent */ PostMessage(GetParent(hwnd), WM_COMMAND, wParam, lParam); return TRUE; } /* else we allow the message to fall through and get passed into the identity provider's message handler. */ } break; case KHUI_WM_NC_NOTIFY: { khui_nc_wnd_data * d; d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER); /* message sent by parent to notify us of something */ switch(HIWORD(wParam)) { case WMNC_DIALOG_EXPAND: /* fallthrough */ case WMNC_UPDATE_LAYOUT: if(hwnd == d->dlg_main) { nc_layout_main_panel(d); return TRUE; } break; /* nop */ } } return TRUE; } /* check if we have a wnd_data, and if so pass the message on to the identity provider callback. */ { khui_nc_wnd_data * d; d = (khui_nc_wnd_data *) (LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER); /* TODO: filter out and forward only the messages that originated or pertain to the identity selection controls. */ if (d && d->nc && d->nc->ident_cb) { return d->nc->ident_cb(d->nc, WMNC_IDENT_WMSG, hwnd, uMsg, wParam, lParam); } } return FALSE; } static void nc_notify_clear(khui_nc_wnd_data * d) { if (d->notif_type == NC_NOTIFY_NONE) /* there are no notifications anyway. */ return; if (d->hwnd_notif_label) DestroyWindow(d->hwnd_notif_label); if (d->hwnd_notif_aux) DestroyWindow(d->hwnd_notif_aux); d->hwnd_notif_label = NULL; d->hwnd_notif_aux = NULL; SetRectEmpty(&d->r_notif); d->notif_type = NC_NOTIFY_NONE; /* Note that we must call nc_layout_main_panel() after calling this to adjust the layout of the main panel. However we aren't calling it here since we might want to add another set of notifications or make other changes to the main panel content before calling nc_layout_main_panel(). */ } static void nc_notify_marquee(khui_nc_wnd_data * d, const wchar_t * label) { #if (_WIN32_IE >= 0x0600) HDC hdc; size_t length; SIZE label_size; #endif RECT r_label; RECT r_mq; RECT r_row; HFONT hfont; HWND hwnd; HDWP hdefer; /* Clear the notification area. We only support one notification at a time. */ nc_notify_clear(d); #ifdef DEBUG assert(d->dlg_main); #endif #if (_WIN32_IE >= 0x0600) /* We can only show the marquee control if the comctl32 DLL is version 6.0 or later. Otherwise we only show the label. */ if (FAILED(StringCchLength(label, KHUI_MAXCCH_SHORT_DESC, &length))) { #ifdef DEBUG assert(FALSE); #endif length = KHUI_MAXCCH_SHORT_DESC; } /* See how big the notification control needs to be. */ hdc = GetDC(d->dlg_main); #ifdef DEBUG assert(hdc != NULL); #endif GetTextExtentPoint32(hdc, label, (int) length, &label_size); ReleaseDC(d->dlg_main, hdc); CopyRect(&r_row, &d->r_row); if (label_size.cx > d->r_e_label.right - d->r_e_label.left) { /* using an entire row */ CopyRect(&r_label, &d->r_row); CopyRect(&r_mq, &d->r_n_input); OffsetRect(&r_mq, 0, r_row.bottom - r_row.top); r_row.bottom += r_row.bottom - r_row.top; } else if (label_size.cx > d->r_n_label.right - d->r_n_label.left) { /* using large labels */ CopyRect(&r_label, &d->r_e_label); CopyRect(&r_mq, &d->r_e_input); } else { /* normal labels */ CopyRect(&r_label, &d->r_n_label); CopyRect(&r_mq, &d->r_n_input); } InflateRect(&r_mq, 0, - ((r_mq.bottom - r_mq.top) / 4)); #else /* _WIN32_IE < 0x0600 */ /* We are just showing the label */ CopyRect(&r_row, &d->r_row); CopyRect(&r_label, &r_row); SetRectEmpty(&r_mq); #endif /* _WIN32_IE >= 0x0600 */ { long y; if (IsRectEmpty(&d->r_custprompt)) { y = d->r_idspec.bottom; } else { y = d->r_custprompt.bottom; } OffsetRect(&r_row, d->r_area.left, y); OffsetRect(&r_label, r_row.left, r_row.top); OffsetRect(&r_mq, r_row.left, r_row.top); } hfont = (HFONT) SendMessage(d->dlg_main, WM_GETFONT, 0, 0); hdefer = BeginDeferWindowPos(2); /* the label */ hwnd = CreateWindowEx(0, L"STATIC", label, WS_CHILD | SS_ENDELLIPSIS, r_label.left, r_label.top, r_label.right - r_label.left, r_label.bottom - r_label.top, d->dlg_main, NULL, NULL, NULL); #ifdef DEBUG assert(hwnd != NULL); #endif SendMessage(hwnd, WM_SETFONT, (WPARAM) hfont, (LPARAM) TRUE); DeferWindowPos(hdefer, hwnd, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_SHOWWINDOW); d->hwnd_notif_label = hwnd; /* and the marquee */ #if (_WIN32_IE >= 0x0600) /* unfortunately, the marquee is only available on comctl32 version 6.0 or later. On previous versions, we only display the message label. */ hwnd = CreateWindowEx(0, PROGRESS_CLASS, L"", WS_CHILD | PBS_MARQUEE, r_mq.left, r_mq.top, r_mq.right - r_mq.left, r_mq.bottom - r_mq.top, d->dlg_main, NULL, NULL, NULL); #ifdef DEBUG assert(hwnd != NULL); #endif SendMessage(hwnd, PBM_SETMARQUEE, TRUE, 100); DeferWindowPos(hdefer, hwnd, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_SHOWWINDOW); d->hwnd_notif_aux = hwnd; #endif /* _WIN32_IE >= 0x0600 */ EndDeferWindowPos(hdefer); CopyRect(&d->r_notif, &r_row); d->notif_type = NC_NOTIFY_MARQUEE; /* Note that we must call nc_layout_main_panel() after calling this to adjust the layout of the main panel. However we aren't calling it here since we might want to add another set of notifications or make other changes to the main panel content before calling nc_layout_main_panel(). */ } static void nc_notify_message(khui_nc_wnd_data * d, kherr_severity severity, const wchar_t * message) { SIZE icon_size; LPCTSTR icon_res; HICON h_icon; HWND hwnd; HFONT hfont; HDWP hdefer; RECT r_row; RECT r_label; RECT r_icon; nc_notify_clear(d); icon_size.cx = GetSystemMetrics(SM_CXSMICON); icon_size.cy = GetSystemMetrics(SM_CYSMICON); switch(severity) { case KHERR_INFO: icon_res = MAKEINTRESOURCE(OIC_INFORMATION); break; case KHERR_WARNING: icon_res = MAKEINTRESOURCE(OIC_WARNING); break; case KHERR_ERROR: icon_res = MAKEINTRESOURCE(OIC_ERROR); break; default: icon_res = NULL; } if (icon_res != NULL) { h_icon = (HICON) LoadImage(NULL, icon_res, IMAGE_ICON, icon_size.cx, icon_size.cy, LR_DEFAULTCOLOR | LR_SHARED); } else { h_icon = NULL; } CopyRect(&r_row, &d->r_row); #define CENTERVALUE(w,v) ((w)/2 - (v)/2) SetRect(&r_icon, 0, CENTERVALUE(r_row.bottom - r_row.top, icon_size.cy), icon_size.cx, CENTERVALUE(r_row.bottom - r_row.top, icon_size.cy) + icon_size.cy); #undef CENTERVALUE CopyRect(&r_label, &r_row); OffsetRect(&r_label, -r_label.left, -r_label.top); r_label.left += (icon_size.cx * 3) / 2; { long y; if (IsRectEmpty(&d->r_custprompt)) { y = d->r_idspec.bottom; } else { y = d->r_custprompt.bottom; } OffsetRect(&r_row, d->r_area.left, y); OffsetRect(&r_label, r_row.left, r_row.top); OffsetRect(&r_icon, r_row.left, r_row.top); } hfont = (HFONT) SendMessage(d->dlg_main, WM_GETFONT, 0, 0); hdefer = BeginDeferWindowPos(2); hwnd = CreateWindowEx(0, L"STATIC", message, WS_CHILD | SS_ENDELLIPSIS | SS_CENTER, r_label.left, r_label.top, r_label.right - r_label.left, r_label.bottom - r_label.top, d->dlg_main, NULL, NULL, NULL); #ifdef DEBUG assert(hwnd != NULL); #endif SendMessage(hwnd, WM_SETFONT, (WPARAM) hfont, (LPARAM) TRUE); DeferWindowPos(hdefer, hwnd, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_SHOWWINDOW); d->hwnd_notif_label = hwnd; hwnd = CreateWindowEx(0, L"STATIC", NULL, WS_CHILD | SS_ICON | #if (_WIN32_IE >= 0x0600) SS_REALSIZECONTROL #else 0 #endif , r_icon.left, r_icon.top, r_icon.right - r_icon.left, r_icon.bottom - r_icon.top, d->dlg_main, NULL, NULL, NULL); #ifdef DEBUG assert(hwnd != NULL); #endif if (h_icon && hwnd) SendMessage(hwnd, STM_SETICON, (WPARAM) h_icon, 0); DeferWindowPos(hdefer, hwnd, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOZORDER); d->hwnd_notif_aux = hwnd; EndDeferWindowPos(hdefer); CopyRect(&d->r_notif, &r_row); d->notif_type = NC_NOTIFY_MESSAGE; /* Note that we must call nc_layout_main_panel() after calling this to adjust the layout of the main panel. However we aren't calling it here since we might want to add another set of notifications or make other changes to the main panel content before calling nc_layout_main_panel(). */ } static void nc_layout_main_panel(khui_nc_wnd_data * d) { RECT r_main; HWND hw_ct; HWND hw_ct_label; HDWP hdwp; RECT r_used; /* extent used by identity specifiers, custom prompts and notificaiton controls. */ RECT r_wmain; /* extents of the main window in screen coordinates. */ r_main.left = 0; r_main.top = 0; r_main.bottom = NCDLG_HEIGHT; r_main.right = NCDLG_WIDTH; MapDialogRect(d->dlg_main, &r_main); CopyRect(&r_used, &d->r_idspec); GetWindowRect(d->dlg_main, &r_wmain); hdwp = BeginDeferWindowPos(7); /* check if the notification area and the custom prompt area are overlapping. */ if (d->notif_type != NC_NOTIFY_NONE) { long delta_y = 0; RECT r; CopyRect(&r, &d->r_custprompt); if (IsRectEmpty(&d->r_custprompt)) { /* if there are no custom prompts, then the notification area should be immediately below the identitify specifers. */ delta_y = d->r_idspec.bottom - d->r_notif.top; } else { /* otherwise, the notification area should be immediately below the custom prompt area */ delta_y = d->r_custprompt.bottom - d->r_notif.top; } if (delta_y != 0) { RECT r_lbl; RECT r_aux; if (d->hwnd_notif_label) { GetWindowRect(d->hwnd_notif_label, &r_lbl); OffsetRect(&r_lbl, -r_wmain.left, delta_y - r_wmain.top); DeferWindowPos(hdwp, d->hwnd_notif_label, NULL, r_lbl.left, r_lbl.top, 0, 0, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOSIZE); } if (d->hwnd_notif_aux) { GetWindowRect(d->hwnd_notif_aux, &r_aux); OffsetRect(&r_aux, -r_wmain.left, delta_y - r_wmain.top); DeferWindowPos(hdwp, d->hwnd_notif_aux, NULL, r_aux.left, r_aux.top, 0, 0, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOSIZE); } OffsetRect(&d->r_notif, 0, delta_y); } } if (!IsRectEmpty(&d->r_custprompt)) { r_used.bottom = max(d->r_custprompt.bottom, r_used.bottom); } if (!IsRectEmpty(&d->r_notif)) { r_used.bottom = max(d->r_notif.bottom, r_used.bottom); } if (d->nc->mode == KHUI_NC_MODE_MINI) { RECT r_ok; RECT r_cancel; RECT r_advanced; HWND hw; hw = GetDlgItem(d->dlg_main, IDOK); #ifdef DEBUG assert(hw != NULL); #endif GetWindowRect(hw, &r_ok); OffsetRect(&r_ok, -r_wmain.left, -r_ok.top + r_used.bottom); DeferWindowPos(hdwp, hw, NULL, r_ok.left, r_ok.top, 0, 0, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW); hw = GetDlgItem(d->dlg_main, IDCANCEL); #ifdef DEBUG assert(hw != NULL); #endif GetWindowRect(hw, &r_cancel); OffsetRect(&r_cancel, -r_wmain.left, -r_cancel.top + r_used.bottom); DeferWindowPos(hdwp, hw, NULL, r_cancel.left, r_cancel.top, 0, 0, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW); hw = GetDlgItem(d->dlg_main, IDC_NC_ADVANCED); #ifdef DEBUG assert(hw != NULL); #endif GetWindowRect(hw, &r_advanced); OffsetRect(&r_advanced, -r_wmain.left, -r_advanced.top + r_used.bottom); DeferWindowPos(hdwp, hw, NULL, r_advanced.left, r_advanced.top, 0, 0, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW); /* and now update the extents of the main panel */ r_main.bottom = r_used.bottom + (r_ok.bottom - r_ok.top) + d->r_area.top; CopyRect(&d->r_main, &r_main); } else { HWND hw; hw = GetDlgItem(d->dlg_main, IDOK); #ifdef DEBUG assert(hw != NULL); #endif if (IsWindowVisible(hw)) DeferWindowPos(hdwp, hw, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_NOZORDER); hw = GetDlgItem(d->dlg_main, IDCANCEL); #ifdef DEBUG assert(hw != NULL); #endif if (IsWindowVisible(hw)) DeferWindowPos(hdwp, hw, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_NOZORDER); hw = GetDlgItem(d->dlg_main, IDC_NC_ADVANCED); #ifdef DEBUG assert(hw != NULL); #endif if (IsWindowVisible(hw)) DeferWindowPos(hdwp, hw, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_NOZORDER); d->r_credtext.top = r_used.bottom; CopyRect(&d->r_main, &r_main); } /* now update the layout of the credentials text window */ hw_ct = GetDlgItem(d->dlg_main, IDC_NC_CREDTEXT); hw_ct_label = GetDlgItem(d->dlg_main, IDC_NC_CREDTEXT_LABEL); #ifdef DEBUG assert(hw_ct != NULL); assert(hw_ct_label != NULL); #endif if (d->nc->mode == KHUI_NC_MODE_MINI || d->r_credtext.bottom < d->r_credtext.top + d->r_row.bottom * 2) { /* either we aren't supposed to show the credentials text window, or we don't have enough room. */ if (IsWindowVisible(hw_ct) || IsWindowVisible(hw_ct_label)) { DeferWindowPos(hdwp, hw_ct, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE); DeferWindowPos(hdwp, hw_ct_label, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE); } } else { DeferWindowPos(hdwp, hw_ct, NULL, d->r_credtext.left + d->r_n_input.left, /* x */ d->r_credtext.top, /* y */ d->r_n_input.right - d->r_n_input.left, /* width */ d->r_credtext.bottom - d->r_credtext.top, /* height */ SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_SHOWWINDOW); DeferWindowPos(hdwp, hw_ct_label, NULL, d->r_credtext.left + d->r_n_label.left, /* x */ d->r_credtext.top, /* y */ d->r_n_label.right - d->r_n_label.left, /* width */ d->r_n_label.bottom - d->r_n_label.top, /* height */ SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_SHOWWINDOW); } EndDeferWindowPos(hdwp); /* NOTE: although we updated d->r_main, if the new credentials window is in mini mode, we must call nc_layout_new_cred_window() to adjust the size of the new credentials window to fit the main panel. We don't do it here because we need to keep these two operations separate. */ } /* Credential type panel comparison function. Tabs are sorted based on the following criteria: 1) By ordinal - Panels with ordinal -1 will be ranked after panels whose ordinal is not -1. 2) By name - Case insensitive comparison of the name. If the panel does not have a name (i.e. the ->name member is NULL, it will be ranked after panels which have a name. */ static int __cdecl nc_tab_sort_func(const void * v1, const void * v2) { /* v1 and v2 and of type : khui_new_creds_by_type ** */ khui_new_creds_by_type *t1, *t2; t1 = *((khui_new_creds_by_type **) v1); t2 = *((khui_new_creds_by_type **) v2); if(t1->ordinal != -1) { if(t2->ordinal != -1) { if(t1->ordinal == t2->ordinal) { if (t1->name && t2->name) return _wcsicmp(t1->name, t2->name); else if (t1->name) return -1; else if (t2->name) return 1; else return 0; } else { /* safe to convert to an int here */ return (int) (t1->ordinal - t2->ordinal); } } else return -1; } else { if(t2->ordinal != -1) return 1; else if (t1->name && t2->name) return wcscmp(t1->name, t2->name); else if (t1->name) return -1; else if (t2->name) return 1; else return 0; } } static void nc_notify_types(khui_new_creds * c, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL sync) { khm_size i; for(i=0; in_types; i++) { if (c->types[i]->hwnd_panel == NULL) continue; if (sync) SendMessage(c->types[i]->hwnd_panel, uMsg, wParam, lParam); else PostMessage(c->types[i]->hwnd_panel, uMsg, wParam, lParam); } } static void nc_clear_password_fields(khui_nc_wnd_data * d) { khm_size i; khm_boolean need_sync = FALSE; khui_cw_lock_nc(d->nc); for (i=0; i < d->nc->n_prompts; i++) { if ((d->nc->prompts[i]->flags & KHUI_NCPROMPT_FLAG_HIDDEN) && d->nc->prompts[i]->hwnd_edit) { SetWindowText(d->nc->prompts[i]->hwnd_edit, L""); need_sync = TRUE; } } khui_cw_unlock_nc(d->nc); if (need_sync) { khui_cw_sync_prompt_values(d->nc); } } /* used by nc_enable_controls */ struct nc_enum_wnd_data { khui_nc_wnd_data * d; khm_boolean enable; }; static BOOL CALLBACK nc_enum_wnd_proc(HWND hwnd, LPARAM lParam) { struct nc_enum_wnd_data * wd; wd = (struct nc_enum_wnd_data *) lParam; EnableWindow(hwnd, wd->enable); return TRUE; } static void nc_enable_controls(khui_nc_wnd_data * d, khm_boolean enable) { struct nc_enum_wnd_data wd; ZeroMemory(&wd, sizeof(wd)); wd.d = d; wd.enable = enable; EnumChildWindows(d->dlg_main, nc_enum_wnd_proc, (LPARAM) &wd); } #define NC_MAXCCH_CREDTEXT 16384 #define NC_MAXCB_CREDTEXT (NC_MAXCCH_CREDTEXT * sizeof(wchar_t)) static void nc_update_credtext(khui_nc_wnd_data * d) { wchar_t * ctbuf = NULL; wchar_t * buf; BOOL okEnable = FALSE; BOOL validId = FALSE; HWND hw = NULL; size_t cch = 0; ctbuf = PMALLOC(NC_MAXCB_CREDTEXT); assert(ctbuf != NULL); LoadString(khm_hInstance, IDS_NC_CREDTEXT_TABS, ctbuf, NC_MAXCCH_CREDTEXT); StringCchLength(ctbuf, NC_MAXCCH_CREDTEXT, &cch); buf = ctbuf + cch; nc_notify_types(d->nc, KHUI_WM_NC_NOTIFY, MAKEWPARAM(0, WMNC_UPDATE_CREDTEXT), (LPARAM) d->nc, TRUE); /* hopefully all the types have updated their credential texts */ /* if the dialog is in the mini mode, we have to display exceptions using a notification. */ if (d->nc->mode == KHUI_NC_MODE_MINI) { BOOL need_layout = FALSE; if (d->nc->n_identities == 0) { /* There are no identities selected. We don't show any notifications here. */ if (d->notif_type != NC_NOTIFY_NONE) { nc_notify_clear(d); need_layout = TRUE; } } else { wchar_t id_name[KCDB_IDENT_MAXCCH_NAME]; wchar_t format[256]; wchar_t msg[ARRAYLENGTH(format) + ARRAYLENGTH(id_name)]; khm_size cbbuf; khm_int32 flags; kcdb_identity_get_flags(d->nc->identities[0], &flags); cbbuf = sizeof(id_name); kcdb_identity_get_name(d->nc->identities[0], id_name, &cbbuf); if (flags & KCDB_IDENT_FLAG_INVALID) { /* identity is invalid */ LoadString(khm_hInstance, IDS_NCN_IDENT_INVALID, format, ARRAYLENGTH(format)); StringCbPrintf(msg, sizeof(msg), format, id_name); nc_notify_message(d, KHERR_ERROR, msg); need_layout = TRUE; } else if ((flags & KCDB_IDENT_FLAG_VALID) || d->nc->subtype == KMSG_CRED_PASSWORD) { /* special case: If we are going to change the password, we don't expect the identity provider to validate the identity in real time. As such, we assume that the identity is valid. */ /* identity is valid */ if (d->notif_type != NC_NOTIFY_NONE) { nc_notify_clear(d); need_layout = TRUE; } } else if (flags & KCDB_IDENT_FLAG_UNKNOWN) { /* unknown state */ LoadString(khm_hInstance, IDS_NCN_IDENT_UNKNOWN, format, ARRAYLENGTH(format)); StringCbPrintf(msg, sizeof(msg), format, id_name); nc_notify_message(d, KHERR_WARNING, msg); need_layout = TRUE; } else { /* still checking */ LoadString(khm_hInstance, IDS_NCN_IDENT_CHECKING, format, ARRAYLENGTH(format)); StringCbPrintf(msg, sizeof(msg), format, id_name); nc_notify_marquee(d, msg); need_layout = TRUE; } } if (need_layout) { nc_layout_main_panel(d); nc_layout_new_cred_window(d); } } if(d->nc->n_identities == 1) { wchar_t main_fmt[256]; wchar_t id_fmt[256]; wchar_t id_name[KCDB_IDENT_MAXCCH_NAME]; wchar_t id_string[KCDB_IDENT_MAXCCH_NAME + 256]; khm_size cbbuf; khm_int32 flags; LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_ONE, main_fmt, (int) ARRAYLENGTH(main_fmt)); cbbuf = sizeof(id_name); kcdb_identity_get_name(d->nc->identities[0], id_name, &cbbuf); kcdb_identity_get_flags(d->nc->identities[0], &flags); if (flags & KCDB_IDENT_FLAG_INVALID) { LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_INVALID, id_fmt, (int) ARRAYLENGTH(id_fmt)); } else if(flags & KCDB_IDENT_FLAG_VALID) { LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_VALID, id_fmt, (int) ARRAYLENGTH(id_fmt)); } else if(flags & KCDB_IDENT_FLAG_UNKNOWN) { LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_UNCHECKED, id_fmt, (int) ARRAYLENGTH(id_fmt)); } else if(d->nc->subtype == KMSG_CRED_NEW_CREDS) { LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_CHECKING, id_fmt, (int) ARRAYLENGTH(id_fmt)); } else { LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_UNCHECKED, id_fmt, (int) ARRAYLENGTH(id_fmt)); } StringCbPrintf(id_string, sizeof(id_string), id_fmt, id_name); StringCbPrintf(buf, NC_MAXCB_CREDTEXT - cch*sizeof(wchar_t), main_fmt, id_string); if (flags & KCDB_IDENT_FLAG_VALID) { if (flags & KCDB_IDENT_FLAG_DEFAULT) LoadString(khm_hInstance, IDS_NC_ID_DEF, id_string, ARRAYLENGTH(id_string)); else if (d->nc->set_default) LoadString(khm_hInstance, IDS_NC_ID_WDEF, id_string, ARRAYLENGTH(id_string)); else LoadString(khm_hInstance, IDS_NC_ID_NDEF, id_string, ARRAYLENGTH(id_string)); StringCbCat(buf, NC_MAXCB_CREDTEXT - cch * sizeof(wchar_t), id_string); } } else if(d->nc->n_identities > 1) { wchar_t *ids_string; khm_size cb_ids_string; wchar_t id_name[KCDB_IDENT_MAXCCH_NAME]; wchar_t id_fmt[256]; wchar_t id_string[KCDB_IDENT_MAXCCH_NAME + 256]; wchar_t main_fmt[256]; khm_size cbbuf; LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_MANY, main_fmt, (int) ARRAYLENGTH(main_fmt)); /* we are going to concatenate all the identity names into a comma separated string */ /* d->nc->n_identities is at least 2 */ ids_string = PMALLOC((KCDB_IDENT_MAXCB_NAME + sizeof(id_fmt)) * (d->nc->n_identities - 1)); cb_ids_string = (KCDB_IDENT_MAXCB_NAME + sizeof(id_fmt)) * (d->nc->n_identities - 1); assert(ids_string != NULL); ids_string[0] = 0; { khm_size i; khm_int32 flags; for(i=1; inc->n_identities; i++) { if(i>1) { StringCbCat(ids_string, cb_ids_string, L","); } flags = 0; cbbuf = sizeof(id_name); kcdb_identity_get_name(d->nc->identities[i], id_name, &cbbuf); kcdb_identity_get_flags(d->nc->identities[i], &flags); if(flags & KCDB_IDENT_FLAG_INVALID) { LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_INVALID, id_fmt, (int) ARRAYLENGTH(id_fmt)); } else if(flags & KCDB_IDENT_FLAG_VALID) { LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_VALID, id_fmt, (int) ARRAYLENGTH(id_fmt)); } else { LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_UNCHECKED, id_fmt, (int) ARRAYLENGTH(id_fmt)); } StringCbPrintf(id_string, sizeof(id_string), id_fmt, id_name); StringCbCat(ids_string, cb_ids_string, id_string); } cbbuf = sizeof(id_name); kcdb_identity_get_name(d->nc->identities[0], id_name, &cbbuf); kcdb_identity_get_flags(d->nc->identities[0], &flags); if(flags & KCDB_IDENT_FLAG_INVALID) { LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_INVALID, id_fmt, (int) ARRAYLENGTH(id_fmt)); } else if(flags & KCDB_IDENT_FLAG_VALID) { LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_VALID, id_fmt, (int) ARRAYLENGTH(id_fmt)); } else { LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_UNCHECKED, id_fmt, (int) ARRAYLENGTH(id_fmt)); } StringCbPrintf(id_string, sizeof(id_string), id_fmt, id_name); StringCbPrintf(buf, NC_MAXCB_CREDTEXT - cch*sizeof(wchar_t), main_fmt, id_string, ids_string); PFREE(ids_string); } } else { LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_NONE, buf, (int)(NC_MAXCCH_CREDTEXT - cch)); } /* now, append the credtext string from each of the cred types */ { khm_size i; size_t cb; wchar_t * buf; cb = NC_MAXCB_CREDTEXT; buf = ctbuf; for(i=0; inc->n_types; i++) { if(d->nc->types[i]->credtext != NULL) { StringCbCatEx(buf, cb, d->nc->types[i]->credtext, &buf, &cb, 0); } } } SetDlgItemText(d->dlg_main, IDC_NC_CREDTEXT, ctbuf); PFREE(ctbuf); /* so depending on whether the primary identity was found to be invalid, we need to disable the Ok button and set the title to reflect this */ if(d->nc->n_identities > 0) { khm_int32 flags = 0; if(KHM_SUCCEEDED(kcdb_identity_get_flags(d->nc->identities[0], &flags)) && (flags & KCDB_IDENT_FLAG_VALID)) { validId = TRUE; } } if (d->nc->window_title == NULL) { if(validId) { wchar_t wpostfix[256]; wchar_t wtitle[KCDB_IDENT_MAXCCH_NAME + 256]; khm_size cbsize; cbsize = sizeof(wtitle); kcdb_identity_get_name(d->nc->identities[0], wtitle, &cbsize); if (d->nc->subtype == KMSG_CRED_PASSWORD) LoadString(khm_hInstance, IDS_WTPOST_PASSWORD, wpostfix, (int) ARRAYLENGTH(wpostfix)); else LoadString(khm_hInstance, IDS_WTPOST_NEW_CREDS, wpostfix, (int) ARRAYLENGTH(wpostfix)); StringCbCat(wtitle, sizeof(wtitle), wpostfix); SetWindowText(d->nc->hwnd, wtitle); } else { wchar_t wtitle[256]; if (d->nc->subtype == KMSG_CRED_PASSWORD) LoadString(khm_hInstance, IDS_WT_PASSWORD, wtitle, (int) ARRAYLENGTH(wtitle)); else LoadString(khm_hInstance, IDS_WT_NEW_CREDS, wtitle, (int) ARRAYLENGTH(wtitle)); SetWindowText(d->nc->hwnd, wtitle); } } if (!(d->nc->response & KHUI_NC_RESPONSE_PROCESSING)) { if(validId || d->nc->subtype == KMSG_CRED_PASSWORD) { /* TODO: check if all the required fields have valid values before enabling the Ok button */ okEnable = TRUE; } hw = GetDlgItem(d->dlg_main, IDOK); EnableWindow(hw, okEnable); hw = GetDlgItem(d->dlg_bb, IDOK); EnableWindow(hw, okEnable); } } static void nc_layout_new_cred_window(khui_nc_wnd_data * ncd) { khui_new_creds * c; RECT r_main; RECT r_ncdialog; HDWP hdefer; c = ncd->nc; r_main.left = 0; r_main.top = 0; r_main.right = NCDLG_WIDTH; r_main.bottom = NCDLG_HEIGHT; MapDialogRect(ncd->dlg_main, &r_main); hdefer = BeginDeferWindowPos(5); if (c->mode == KHUI_NC_MODE_MINI) { if (IsWindowVisible(ncd->tab_wnd)) { DeferWindowPos(hdefer, ncd->tab_wnd, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER); } if (IsWindowVisible(ncd->dlg_bb)) { DeferWindowPos(hdefer, ncd->dlg_bb, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER); } DeferWindowPos(hdefer, ncd->dlg_main, NULL, r_main.left, r_main.top, r_main.right - r_main.left, r_main.bottom - r_main.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_SHOWWINDOW); /* note that the ncd->r_main.bottom may not be the same as r_main.bottom because ncd->r_main.bottom is set dynamically depending on custom controls. ncd->r_main is valid only once nc_layout_main_panel() is called.*/ CopyRect(&ncd->r_required, &ncd->r_main); } else { RECT r_tabctrl; RECT r_displayarea; RECT r_bbar; khm_size i; /* calculate the size of the tab control so that it fits snugly around the expanded main panel. */ CopyRect(&r_tabctrl, &r_main); TabCtrl_AdjustRect(ncd->tab_wnd, TRUE, &r_tabctrl); if (r_tabctrl.left < 0 || r_tabctrl.top < 0) { OffsetRect(&r_tabctrl, (r_tabctrl.left < 0)? -r_tabctrl.left : 0, (r_tabctrl.top < 0)? -r_tabctrl.top : 0); } #ifdef DEBUG assert(r_tabctrl.left == 0); assert(r_tabctrl.top == 0); #endif OffsetRect(&r_tabctrl, 0, ncd->r_area.top); /* and now calculate the rectangle where the main panel should be inside the tab control. */ CopyRect(&r_displayarea, &r_tabctrl); TabCtrl_AdjustRect(ncd->tab_wnd, FALSE, &r_displayarea); DeferWindowPos(hdefer, ncd->tab_wnd, HWND_BOTTOM, r_tabctrl.left, r_tabctrl.top, r_tabctrl.right - r_tabctrl.left, r_tabctrl.bottom - r_tabctrl.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_SHOWWINDOW); /* we have to place the button bar just to the right of the tab panel. */ r_bbar.left = 0; r_bbar.top = 0; r_bbar.right = NCDLG_BBAR_WIDTH; r_bbar.bottom = NCDLG_BBAR_HEIGHT; MapDialogRect(ncd->dlg_main, &r_bbar); OffsetRect(&r_bbar, r_tabctrl.right, 0); DeferWindowPos(hdefer, ncd->dlg_bb, NULL, r_bbar.left, r_bbar.top, r_bbar.right - r_bbar.left, r_bbar.bottom - r_bbar.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_SHOWWINDOW); /* move the main panel inside the tab control... */ DeferWindowPos(hdefer, ncd->dlg_main, NULL, r_displayarea.left, r_displayarea.top, r_displayarea.right - r_displayarea.left, r_displayarea.bottom - r_displayarea.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | (ncd->current_panel == 0 ? SWP_SHOWWINDOW : SWP_HIDEWINDOW)); /* and also move all the credential type panels (if they have been created) inside the tab control too. */ khui_cw_lock_nc(c); for (i=0; i < c->n_types; i++) { if (c->types[i]->hwnd_panel != NULL) { DeferWindowPos(hdefer, c->types[i]->hwnd_panel, NULL, r_displayarea.left, r_displayarea.top, r_displayarea.right - r_displayarea.left, r_displayarea.bottom - r_displayarea.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | (ncd->current_panel == c->types[i]->ordinal ? SWP_SHOWWINDOW : SWP_HIDEWINDOW)); } } khui_cw_unlock_nc(c); /* then update the required size of the new credentials dialog. */ ncd->r_required.left = 0; ncd->r_required.top = 0; ncd->r_required.right = r_bbar.right; ncd->r_required.bottom = max(r_tabctrl.bottom, r_bbar.bottom) + ncd->r_area.top; } /* commit all the window moves, resizes and hides/shows we did*/ EndDeferWindowPos(hdefer); /* now we have to see if the client area of the new credentials window is the right size. */ GetClientRect(c->hwnd, &r_ncdialog); if ( ((r_ncdialog.right - r_ncdialog.left != ncd->r_required.right - ncd->r_required.left) || (r_ncdialog.bottom - r_ncdialog.top != ncd->r_required.bottom - ncd->r_required.top)) && /* we don't bother if the new creds window is already in the process of changing the size. */ !ncd->size_changing) { /* if not, notify the window that the size needs adjusting. */ if (IsWindowVisible(c->hwnd)) PostMessage(c->hwnd, KHUI_WM_NC_NOTIFY, MAKEWPARAM(0, WMNC_UPDATE_LAYOUT), 0); else SendMessage(c->hwnd, KHUI_WM_NC_NOTIFY, MAKEWPARAM(0, WMNC_UPDATE_LAYOUT), 0); } } #define CW_PARAM DWLP_USER static LRESULT nc_handle_wm_create(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LPCREATESTRUCT lpc; khui_new_creds * c; khui_nc_wnd_data * ncd; int x, y; int width, height; RECT r; HFONT hf_main; lpc = (LPCREATESTRUCT) lParam; ncd = PMALLOC(sizeof(*ncd)); ZeroMemory(ncd, sizeof(*ncd)); c = (khui_new_creds *) lpc->lpCreateParams; ncd->nc = c; c->hwnd = hwnd; #ifdef DEBUG assert(c->subtype == KMSG_CRED_NEW_CREDS || c->subtype == KMSG_CRED_PASSWORD); #endif #pragma warning(push) #pragma warning(disable: 4244) SetWindowLongPtr(hwnd, CW_PARAM, (LONG_PTR) ncd); #pragma warning(pop) /* first, create the tab control that will house the main dialog panel as well as the plug-in specific panels */ ncd->tab_wnd = CreateWindowEx(0, /* extended style */ WC_TABCONTROL, L"TabControloxxrz", /* window name */ TCS_HOTTRACK | TCS_RAGGEDRIGHT | TCS_SINGLELINE | TCS_TABS | WS_CHILD | WS_TABSTOP | WS_CLIPSIBLINGS, 0, 0, 100, 100, /* x,y,width height. We'll be changing these later anyway. */ hwnd, (HMENU) IDC_NC_TABS, NULL, 0); #ifdef DEBUG assert(ncd->tab_wnd != NULL); #endif /* try to create the main dialog panel */ ncd->dlg_main = CreateDialogParam(khm_hInstance, MAKEINTRESOURCE(IDD_NC_NEWCRED), hwnd, nc_common_dlg_proc, (LPARAM) ncd); #ifdef DEBUG assert(ncd->dlg_main != NULL); #endif hf_main = (HFONT) SendMessage(ncd->dlg_main, WM_GETFONT, 0, 0); if (hf_main) SendMessage(ncd->tab_wnd, WM_SETFONT, (WPARAM) hf_main, FALSE); { RECT r_main; RECT r_area; RECT r_row; HWND hw; /* During the operation of the new credentials window, we will need to dynamically change the layout of the controls as a result of custom prompting from credentials providers and identity selectors from identity providers. In order to guide the dynamic layout, we pick out a few metrics from the dialog template for the main panel. The metrics come from hidden STATIC controls in the dialog template. */ GetWindowRect(ncd->dlg_main, &r_main); /* IDC_NC_TPL_PANEL spans the full extent of the dialog that we can populate with custom controls. */ hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_PANEL); #ifdef DEBUG assert(hw); #endif GetWindowRect(hw, &r_area); OffsetRect(&r_area,-r_main.left, -r_main.top); CopyRect(&ncd->r_area, &r_area); /* IDC_NC_TPL_ROW spans the extent of a row of normal sized custom controls. A row of custom controls typicall consist of a text label and an input control. */ hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_ROW); #ifdef DEBUG assert(hw); #endif GetWindowRect(hw, &r); CopyRect(&r_row, &r); OffsetRect(&r,-r.left, -r.top); CopyRect(&ncd->r_row, &r); /* IDC_NC_TPL_LABEL spans the extent that a normal sized label. The control overlaps IDC_NC_TPL_ROW so we can get coordinates relative to the row extents. */ hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_LABEL); #ifdef DEBUG assert(hw); #endif GetWindowRect(hw, &r); OffsetRect(&r,-r_row.left, -r_row.top); CopyRect(&ncd->r_n_label, &r); /* IDC_NC_TPL_INPUT spans the extent of a normal sized input control in a custom control row. The control overlaps IDC_NC_TPL_ROW so we can get relative coordinates. */ hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_INPUT); #ifdef DEBUG assert(hw); #endif GetWindowRect(hw, &r); OffsetRect(&r, -r_row.left, -r_row.top); CopyRect(&ncd->r_n_input, &r); /* IDC_NC_TPL_ROW_LG spans the extent of a row of large sized controls. */ hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_ROW_LG); #ifdef DEBUG assert(hw); #endif GetWindowRect(hw, &r_row); /* IDC_NC_TPL_LABEL_LG is a large sized label. The control overlaps IDC_NC_TPL_ROW_LG. */ hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_LABEL_LG); #ifdef DEBUG assert(hw); #endif GetWindowRect(hw, &r); OffsetRect(&r, -r_row.left, -r_row.top); CopyRect(&ncd->r_e_label, &r); /* IDC_NC_TPL_INPUT_LG is a large sized input control. Overlaps IDC_NC_TPL_ROW_LG. */ hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_INPUT_LG); #ifdef DEBUG assert(hw); #endif GetWindowRect(hw, &r); OffsetRect(&r, -r_row.left, -r_row.top); CopyRect(&ncd->r_e_input, &r); CopyRect(&ncd->r_credtext, &ncd->r_area); CopyRect(&ncd->r_idspec, &ncd->r_area); ncd->r_idspec.bottom = ncd->r_idspec.top; /* And finally the credential text window. The only metric we take from here is the Y coordinate of the bottom of the control since the actual size and position of the credentials window will change depending on the custom controls being displayed. */ hw = GetDlgItem(ncd->dlg_main, IDC_NC_CREDTEXT); #ifdef DEBUG assert(hw); #endif GetWindowRect(hw, &r); OffsetRect(&r, -r_main.left, -r_main.top); ncd->r_credtext.bottom = r.bottom; } /* if the mode is 'mini'*/ r.left = 0; r.top = 0; if(c->mode == KHUI_NC_MODE_MINI) { r.right = NCDLG_WIDTH; r.bottom = NCDLG_HEIGHT; } else { r.right = NCDLG_WIDTH + NCDLG_BBAR_WIDTH; r.bottom = NCDLG_BBAR_HEIGHT; } MapDialogRect(ncd->dlg_main, &r); /* position the new credentials dialog */ width = r.right - r.left; height = r.bottom - r.top; /* adjust width and height to accomodate NC area */ { RECT wr,cr; GetWindowRect(hwnd, &wr); GetClientRect(hwnd, &cr); /* the non-client and client areas have already been calculated at this point. We just use the difference to adjust the width and height */ width += (wr.right - wr.left) - (cr.right - cr.left); height += (wr.bottom - wr.top) - (cr.bottom - cr.top); } /* if the parent window is visible, we center the new credentials dialog over the parent. Otherwise, we center it on the primary display. */ if (IsWindowVisible(lpc->hwndParent)) { GetWindowRect(lpc->hwndParent, &r); } else { if(!SystemParametersInfo(SPI_GETWORKAREA, 0, (PVOID) &r, 0)) { /* failover to the window coordinates */ GetWindowRect(lpc->hwndParent, &r); } } x = (r.right + r.left)/2 - width / 2; y = (r.top + r.bottom)/2 - height / 2; MoveWindow(hwnd, x, y, width, height, FALSE); ncd->dlg_bb = CreateDialogParam(khm_hInstance, MAKEINTRESOURCE(IDD_NC_BBAR), hwnd, nc_common_dlg_proc, (LPARAM) ncd); #ifdef DEBUG assert(ncd->dlg_bb); #endif /* Call the identity provider callback to set the identity selector controls. These controls need to be there before we layout the main panel. */ c->ident_cb(c, WMNC_IDENT_INIT, NULL, 0, 0, (LPARAM) ncd->dlg_main); if (c->mode == KHUI_NC_MODE_EXPANDED) { SendMessage(ncd->dlg_main, KHUI_WM_NC_NOTIFY, MAKEWPARAM(0, WMNC_DIALOG_EXPAND), 0); } else { /* we don't call nc_layout_main_panel() if the dialog is expanded because posting WMNC_DIALOG_EXPAND to the main panel results in it getting called anyway. */ nc_layout_main_panel(ncd); } nc_layout_new_cred_window(ncd); /* add this to the dialog chain */ khm_add_dialog(hwnd); return TRUE; } /* add a control row supplied by an identity provider */ static void nc_add_control_row(khui_nc_wnd_data * d, HWND label, HWND input, khui_control_size size) { RECT r_row; RECT r_label; RECT r_input; HFONT hf; HDWP hdefer; hf = (HFONT) SendMessage(d->dlg_main, WM_GETFONT, 0, 0); SendMessage(label, WM_SETFONT, (WPARAM) hf, FALSE); SendMessage(input, WM_SETFONT, (WPARAM) hf, FALSE); CopyRect(&r_row, &d->r_row); OffsetRect(&r_row, d->r_idspec.left, d->r_idspec.bottom); if (size == KHUI_CTRLSIZE_SMALL) { CopyRect(&r_label, &d->r_n_label); CopyRect(&r_input, &d->r_n_input); OffsetRect(&r_label, r_row.left, r_row.top); OffsetRect(&r_input, r_row.left, r_row.top); } else if (size == KHUI_CTRLSIZE_HALF) { CopyRect(&r_label, &d->r_e_label); CopyRect(&r_input, &d->r_e_input); OffsetRect(&r_label, r_row.left, r_row.top); OffsetRect(&r_input, r_row.left, r_row.top); } else if (size == KHUI_CTRLSIZE_FULL) { CopyRect(&r_label, &d->r_n_label); r_label.right = d->r_row.right; CopyRect(&r_input, &d->r_n_input); OffsetRect(&r_input, r_row.left, r_row.top); OffsetRect(&r_input, 0, r_input.bottom); r_row.bottom += r_input.bottom; OffsetRect(&r_label, r_row.left, r_row.top); } else { SetRectEmpty(&r_label); SetRectEmpty(&r_input); #ifdef DEBUG assert(FALSE); #endif return; } hdefer = BeginDeferWindowPos(2); if (label) DeferWindowPos(hdefer, label, ((d->hwnd_last_idspec != NULL)? d->hwnd_last_idspec: HWND_TOP), r_label.left, r_label.top, r_label.right - r_label.left, r_label.bottom - r_label.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER); if (input) DeferWindowPos(hdefer, input, (label ? label : ((d->hwnd_last_idspec != NULL)? d->hwnd_last_idspec: HWND_TOP)), r_input.left, r_input.top, r_input.right - r_input.left, r_input.bottom - r_input.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER); EndDeferWindowPos(hdefer); d->hwnd_last_idspec = (input ? input : label); d->r_idspec.bottom = r_row.bottom; /* we don't update the layout of the main panel yet, since these control additions happen before the main panel is displayed. A call to nc_layout_main_panel() will be made before the main panel is shown anyway. */ } static LRESULT nc_handle_wm_destroy(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { khui_nc_wnd_data * d; /* remove self from dialog chain */ khm_del_dialog(hwnd); d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, CW_PARAM); d->nc->ident_cb(d->nc, WMNC_IDENT_EXIT, NULL, 0, 0, 0); if (d->hwnd_notif_label) DestroyWindow(d->hwnd_notif_label); if (d->hwnd_notif_aux) DestroyWindow(d->hwnd_notif_aux); if(d->dlg_bb) DestroyWindow(d->dlg_bb); if(d->dlg_main) DestroyWindow(d->dlg_main); d->dlg_bb = NULL; d->dlg_main = NULL; PFREE(d); return TRUE; } static LRESULT nc_handle_wm_command(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { khui_nc_wnd_data * d; d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, CW_PARAM); switch(HIWORD(wParam)) { case BN_CLICKED: switch(LOWORD(wParam)) { case IDOK: d->nc->result = KHUI_NC_RESULT_PROCESS; /* fallthrough */ case IDCANCEL: /* the default value for d->nc->result is set to KHUI_NC_RESULT_CANCEL */ d->nc->response = KHUI_NC_RESPONSE_PROCESSING; nc_enable_controls(d, FALSE); nc_notify_types(d->nc, KHUI_WM_NC_NOTIFY, MAKEWPARAM(0,WMNC_DIALOG_PREPROCESS), (LPARAM) d->nc, TRUE); khui_cw_sync_prompt_values(d->nc); khm_cred_dispatch_process_message(d->nc); /* we won't know whether to abort or not until we get feedback from the plugins, even if the command was to cancel */ { HWND hw; hw = GetDlgItem(d->dlg_main, IDOK); EnableWindow(hw, FALSE); hw = GetDlgItem(d->dlg_main, IDCANCEL); EnableWindow(hw, FALSE); hw = GetDlgItem(d->dlg_main, IDC_NC_ADVANCED); EnableWindow(hw, FALSE); hw = GetDlgItem(d->dlg_bb, IDOK); EnableWindow(hw, FALSE); hw = GetDlgItem(d->dlg_bb, IDCANCEL); EnableWindow(hw, FALSE); } return FALSE; case IDC_NC_HELP: khm_html_help(hwnd, NULL, HH_HELP_CONTEXT, IDH_ACTION_NEW_ID); return FALSE; case IDC_NC_BASIC: case IDC_NC_ADVANCED: /* the Options button in the main window was clicked. we respond by expanding the dialog. */ PostMessage(hwnd, KHUI_WM_NC_NOTIFY, MAKEWPARAM(0, WMNC_DIALOG_EXPAND), 0); return FALSE; case IDC_NC_CREDTEXT: /* credtext link activated */ { khui_htwnd_link * l; wchar_t sid[KHUI_MAXCCH_HTLINK_FIELD]; wchar_t sparam[KHUI_MAXCCH_HTLINK_FIELD]; wchar_t * colon; l = (khui_htwnd_link *) lParam; /* do we have a valid link? */ if(l->id == NULL || l->id_len >= ARRAYLENGTH(sid)) return TRUE; /* nope */ StringCchCopyN(sid, ARRAYLENGTH(sid), l->id, l->id_len); sid[l->id_len] = L'\0'; /* just make sure */ if(l->param != NULL && l->param_len < ARRAYLENGTH(sparam) && l->param_len > 0) { StringCchCopyN(sparam, ARRAYLENGTH(sparam), l->param, l->param_len); sparam[l->param_len] = L'\0'; } else { sparam[0] = L'\0'; } /* If the ID is of the form ':' and is a valid name of a credentials type that is participating in the credentials acquisition process, then we forward the message to the panel that is providing the UI for that cred type. We also switch to that panel first, unless the link is of the form ':!'. */ colon = wcschr(sid, L':'); if (colon != NULL) { khm_int32 credtype; khui_new_creds_by_type * t; *colon = L'\0'; if (KHM_SUCCEEDED(kcdb_credtype_get_id(sid, &credtype)) && KHM_SUCCEEDED(khui_cw_find_type(d->nc, credtype, &t))){ *colon = L':'; if (t->ordinal != d->current_panel && *(colon + 1) != L'!') PostMessage(hwnd, KHUI_WM_NC_NOTIFY, MAKEWPARAM(t->ordinal, WMNC_DIALOG_SWITCH_PANEL), 0); return SendMessage(t->hwnd_panel, KHUI_WM_NC_NOTIFY, MAKEWPARAM(0, WMNC_CREDTEXT_LINK), lParam); } else { *colon = L':'; } } /* if it was for us, then we need to process the message */ if(!_wcsicmp(sid, CTLINKID_SWITCH_PANEL)) { khm_int32 credtype; khui_new_creds_by_type * t; if (KHM_SUCCEEDED(kcdb_credtype_get_id(sparam, &credtype)) && KHM_SUCCEEDED(khui_cw_find_type(d->nc, credtype, &t))) { if (t->ordinal != d->current_panel) PostMessage(hwnd, KHUI_WM_NC_NOTIFY, MAKEWPARAM(t->ordinal, WMNC_DIALOG_SWITCH_PANEL), 0); } } else if (!_wcsicmp(sid, L"NotDef")) { d->nc->set_default = FALSE; nc_update_credtext(d); } else if (!_wcsicmp(sid, L"MakeDef")) { d->nc->set_default = TRUE; nc_update_credtext(d); } } return FALSE; #if 0 case NC_BN_SET_DEF_ID: { d->nc->set_default = (IsDlgButtonChecked(d->dlg_main, NC_BN_SET_DEF_ID) == BST_CHECKED); } return FALSE; #endif } break; } return TRUE; } static LRESULT nc_handle_wm_moving(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { khui_nc_wnd_data * d; d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, CW_PARAM); nc_notify_types(d->nc, KHUI_WM_NC_NOTIFY, MAKEWPARAM(0, WMNC_DIALOG_MOVE), (LPARAM) d->nc, TRUE); return FALSE; } static LRESULT nc_handle_wm_nc_notify(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { khui_nc_wnd_data * d; int id; d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, CW_PARAM); switch(HIWORD(wParam)) { case WMNC_DIALOG_SWITCH_PANEL: id = LOWORD(wParam); if(id >= 0 && id <= (int) d->nc->n_types) { /* one of the tab buttons were pressed */ if(d->current_panel == id) { return TRUE; /* nothing to do */ } d->current_panel = id; TabCtrl_SetCurSel(d->tab_wnd, id); } if(d->nc->mode == KHUI_NC_MODE_EXPANDED) { nc_layout_new_cred_window(d); return TRUE; } /*else*/ /* fallthrough */ case WMNC_DIALOG_EXPAND: /* we are switching from basic to advanced or vice versa */ if (d->nc->mode == KHUI_NC_MODE_EXPANDED) { d->nc->mode = KHUI_NC_MODE_MINI; } else { d->nc->mode = KHUI_NC_MODE_EXPANDED; } /* if we are switching to the advanced mode, we clear any notifications because we now have a credential text area for that. */ if (d->nc->mode == KHUI_NC_MODE_EXPANDED) nc_notify_clear(d); nc_layout_main_panel(d); nc_layout_new_cred_window(d); break; case WMNC_DIALOG_SETUP: if(d->nc->n_types > 0) { khm_size i; for(i=0; i < d->nc->n_types;i++) { if (d->nc->types[i]->dlg_proc == NULL) { d->nc->types[i]->hwnd_panel = NULL; } else { /* Create the dialog panel */ d->nc->types[i]->hwnd_panel = CreateDialogParam(d->nc->types[i]->h_module, d->nc->types[i]->dlg_template, d->nc->hwnd, d->nc->types[i]->dlg_proc, (LPARAM) d->nc); #ifdef DEBUG assert(d->nc->types[i]->hwnd_panel); #endif } } } break; case WMNC_DIALOG_ACTIVATE: { wchar_t wname[KCDB_MAXCCH_NAME]; TCITEM tabitem; khm_int32 t; /* About to activate the window. We should add all the panels to the tab control. */ #ifdef DEBUG assert(d->tab_wnd != NULL); #endif ZeroMemory(&tabitem, sizeof(tabitem)); tabitem.mask = TCIF_PARAM | TCIF_TEXT; LoadString(khm_hInstance, IDS_NC_IDENTITY, wname, ARRAYLENGTH(wname)); tabitem.pszText = wname; tabitem.lParam = 0; /* ordinal */ TabCtrl_InsertItem(d->tab_wnd, 0, &tabitem); khui_cw_lock_nc(d->nc); if(d->nc->n_types > 0) { khm_size i; /* We should sort the tabs first. See nc_tab_sort_func() for sort criteria. */ qsort(d->nc->types, d->nc->n_types, sizeof(*(d->nc->types)), nc_tab_sort_func); for(i=0; i < d->nc->n_types;i++) { d->nc->types[i]->ordinal = i + 1; if(d->nc->types[i]->name) tabitem.pszText = d->nc->types[i]->name; else { khm_size cbsize; cbsize = sizeof(wname); if(KHM_FAILED (kcdb_credtype_describe (d->nc->types[i]->type, wname, &cbsize, KCDB_TS_SHORT))) { #ifdef DEBUG assert(FALSE); #endif wname[0] = L'\0'; } tabitem.pszText = wname; } tabitem.lParam = d->nc->types[i]->ordinal; TabCtrl_InsertItem(d->tab_wnd, d->nc->types[i]->ordinal, &tabitem); } } khui_cw_unlock_nc(d->nc); nc_update_credtext(d); TabCtrl_SetCurSel(d->tab_wnd, 0); /* the first selected tab is the main panel. */ /* bring the window to the top, if necessary */ if (KHM_SUCCEEDED(khc_read_int32(NULL, L"CredWindow\\Windows\\NewCred\\ForceToTop", &t)) && t != 0) { /* it used to be that the above condition also called !khm_is_dialog_active() to find out whether there was a dialog active. If there was, we wouldn't try to bring the new cred window to the foreground. But that was not the behavior we want. */ /* if the main window is not visible, then the SetWindowPos() call is sufficient to bring the new creds window to the top. However, if the main window is visible but not active, the main window needs to be activated before a child window can be activated. */ khm_activate_main_window(); SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, (SWP_NOMOVE | SWP_NOSIZE)); } ShowWindow(hwnd, SW_SHOWNOACTIVATE); /* we don't enable animations until a specific timeout elapses after showing the window. We don't need to animate any size changes if the user has barely had a chance to notice the original size. This prevents the new cred window from appearing in an animated state. */ SetTimer(hwnd, NC_TIMER_ENABLEANIMATE, ENABLEANIMATE_TIMEOUT, NULL); SetFocus(hwnd); if (d->nc->n_identities == 0) break; /* else */ /* fallthrough */ } case WMNC_IDENTITY_CHANGE: { BOOL okEnable = FALSE; nc_notify_types(d->nc, KHUI_WM_NC_NOTIFY, MAKEWPARAM(0, WMNC_IDENTITY_CHANGE), (LPARAM) d->nc, TRUE); if (d->nc->subtype == KMSG_CRED_NEW_CREDS && d->nc->n_identities > 0 && d->nc->identities[0]) { khm_int32 f = 0; kcdb_identity_get_flags(d->nc->identities[0], &f); if (!(f & KCDB_IDENT_FLAG_DEFAULT)) { d->nc->set_default = FALSE; } } nc_update_credtext(d); } break; case WMNC_TYPE_STATE: /* fallthrough */ case WMNC_UPDATE_CREDTEXT: nc_update_credtext(d); break; case WMNC_CLEAR_PROMPTS: { khm_size i; khui_cw_lock_nc(d->nc); if(d->hwnd_banner != NULL) { DestroyWindow(d->hwnd_banner); d->hwnd_banner = NULL; } if(d->hwnd_name != NULL) { DestroyWindow(d->hwnd_name); d->hwnd_name = NULL; } for(i=0;inc->n_prompts;i++) { if(!(d->nc->prompts[i]->flags & KHUI_NCPROMPT_FLAG_STOCK)) { if(d->nc->prompts[i]->hwnd_static != NULL) DestroyWindow(d->nc->prompts[i]->hwnd_static); if(d->nc->prompts[i]->hwnd_edit != NULL) DestroyWindow(d->nc->prompts[i]->hwnd_edit); } d->nc->prompts[i]->hwnd_static = NULL; d->nc->prompts[i]->hwnd_edit = NULL; } khui_cw_unlock_nc(d->nc); SetRectEmpty(&d->r_custprompt); nc_layout_main_panel(d); nc_layout_new_cred_window(d); } break; case WMNC_SET_PROMPTS: { khm_size i; int y; HWND hw, hw_prev; HFONT hf, hfold; HDC hdc; BOOL use_large_lables = FALSE; /* we assume that WMNC_CLEAR_PROMPTS has already been received */ #ifdef DEBUG assert(IsRectEmpty(&d->r_custprompt)); #endif khui_cw_lock_nc(d->nc); #if 0 /* special case, we have one prompt and it is a password prompt. very common */ if(d->nc->n_prompts == 1 && d->nc->prompts[0]->type == KHUI_NCPROMPT_TYPE_PASSWORD) { hw = GetDlgItem(d->dlg_main, IDC_NC_PASSWORD); EnableWindow(hw, TRUE); d->nc->prompts[0]->flags |= KHUI_NCPROMPT_FLAG_STOCK; d->nc->prompts[0]->hwnd_edit = hw; d->nc->prompts[0]->hwnd_static = NULL; /* don't care */ khui_cw_unlock_nc(d->nc); break; } #endif /* for everything else */ y = d->r_idspec.bottom; d->r_custprompt.left = d->r_area.left; d->r_custprompt.right = d->r_area.right; d->r_custprompt.top = y; hf = (HFONT) SendMessage(d->dlg_main, WM_GETFONT, 0, 0); if (d->nc->pname != NULL) { hw = CreateWindowEx (0, L"STATIC", d->nc->pname, SS_SUNKEN | WS_CHILD, d->r_area.left, y, d->r_row.right, d->r_n_label.bottom - d->r_n_label.top, d->dlg_main, NULL, khm_hInstance, NULL); #ifdef DEBUG assert(hw); #endif d->hwnd_name = hw; SendMessage(hw, WM_SETFONT, (WPARAM)hf, (LPARAM) TRUE); ShowWindow(hw, SW_SHOW); y += d->r_n_label.bottom - d->r_n_label.top; } if (d->nc->banner != NULL) { hw = CreateWindowEx (0, L"STATIC", d->nc->banner, WS_CHILD, d->r_area.left, y, d->r_row.right, d->r_row.bottom, d->dlg_main, NULL, khm_hInstance, NULL); #ifdef DEBUG assert(hw); #endif d->hwnd_banner = hw; SendMessage(hw, WM_SETFONT, (WPARAM)hf, (LPARAM)TRUE); ShowWindow(hw, SW_SHOW); y += d->r_row.bottom; } hw_prev = d->hwnd_last_idspec; hdc = GetWindowDC(d->dlg_main); hfold = SelectObject(hdc,hf); /* first do a trial run and see if we should use the larger text labels or not. This is so that all the labels and input controls align properly. */ for (i=0; i < d->nc->n_prompts; i++) { if (d->nc->prompts[i]->prompt != NULL) { SIZE s; GetTextExtentPoint32(hdc, d->nc->prompts[i]->prompt, (int) wcslen(d->nc->prompts[i]->prompt), &s); if(s.cx >= d->r_n_label.right - d->r_n_label.left) { use_large_lables = TRUE; break; } } } for(i=0; inc->n_prompts; i++) { RECT pr, er; SIZE s; int dy; if(d->nc->prompts[i]->prompt != NULL) { GetTextExtentPoint32(hdc, d->nc->prompts[i]->prompt, (int) wcslen(d->nc->prompts[i]->prompt), &s); if(s.cx < d->r_n_label.right - d->r_n_label.left && !use_large_lables) { CopyRect(&pr, &d->r_n_label); CopyRect(&er, &d->r_n_input); dy = d->r_row.bottom; } else if(s.cx < d->r_e_label.right - d->r_e_label.left) { CopyRect(&pr, &d->r_e_label); CopyRect(&er, &d->r_e_input); dy = d->r_row.bottom; } else { /* oops. the prompt doesn't fit in our controls. we need to use up two lines */ pr.left = 0; pr.right = d->r_row.right; pr.top = 0; pr.bottom = d->r_n_label.bottom - d->r_n_label.top; CopyRect(&er, &d->r_n_input); OffsetRect(&er, 0, pr.bottom); dy = er.bottom + (d->r_row.bottom - d->r_n_input.bottom); } } else { SetRectEmpty(&pr); CopyRect(&er, &d->r_n_input); dy = d->r_row.bottom; } if(IsRectEmpty(&pr)) { d->nc->prompts[i]->hwnd_static = NULL; } else { OffsetRect(&pr, d->r_area.left, y); hw = CreateWindowEx (0, L"STATIC", d->nc->prompts[i]->prompt, WS_CHILD, pr.left, pr.top, pr.right - pr.left, pr.bottom - pr.top, d->dlg_main, NULL, khm_hInstance, NULL); #ifdef DEBUG assert(hw); #endif SendMessage(hw, WM_SETFONT, (WPARAM) hf, (LPARAM) TRUE); SetWindowPos(hw, hw_prev, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_SHOWWINDOW); d->nc->prompts[i]->hwnd_static = hw; hw_prev = hw; } OffsetRect(&er, d->r_area.left, y); hw = CreateWindowEx (0, L"EDIT", (d->nc->prompts[i]->def ? d->nc->prompts[i]->def : L""), WS_CHILD | WS_TABSTOP | WS_BORDER | ((d->nc->prompts[i]->flags & KHUI_NCPROMPT_FLAG_HIDDEN)? ES_PASSWORD:0), er.left, er.top, er.right - er.left, er.bottom - er.top, d->dlg_main, NULL, khm_hInstance, NULL); #ifdef DEBUG assert(hw); #endif SendMessage(hw, WM_SETFONT, (WPARAM) hf, (LPARAM) TRUE); SetWindowPos(hw, hw_prev, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_SHOWWINDOW); SendMessage(hw, EM_SETLIMITTEXT, KHUI_MAXCCH_PROMPT_VALUE -1, 0); d->nc->prompts[i]->hwnd_edit = hw; hw_prev = hw; y += dy; } if (d->nc->n_prompts > 0 && d->nc->prompts[0]->hwnd_edit) { PostMessage(d->dlg_main, WM_NEXTDLGCTL, (WPARAM) d->nc->prompts[0]->hwnd_edit, MAKELPARAM(TRUE, 0)); } SelectObject(hdc, hfold); ReleaseDC(d->dlg_main, hdc); khui_cw_unlock_nc(d->nc); d->r_custprompt.bottom = y; if (d->r_custprompt.bottom == d->r_custprompt.top) SetRectEmpty(&d->r_custprompt); nc_layout_main_panel(d); nc_layout_new_cred_window(d); } break; case WMNC_DIALOG_PROCESS_COMPLETE: { khui_new_creds * nc; nc = d->nc; nc->response &= ~KHUI_NC_RESPONSE_PROCESSING; if(nc->response & KHUI_NC_RESPONSE_NOEXIT) { HWND hw; nc_enable_controls(d, TRUE); /* reset state */ nc->result = KHUI_NC_RESULT_CANCEL; hw = GetDlgItem(d->dlg_main, IDOK); EnableWindow(hw, TRUE); hw = GetDlgItem(d->dlg_main, IDCANCEL); EnableWindow(hw, TRUE); hw = GetDlgItem(d->dlg_main, IDC_NC_ADVANCED); EnableWindow(hw, TRUE); hw = GetDlgItem(d->dlg_bb, IDOK); EnableWindow(hw, TRUE); hw = GetDlgItem(d->dlg_bb, IDCANCEL); EnableWindow(hw, TRUE); nc_clear_password_fields(d); return TRUE; } DestroyWindow(hwnd); kmq_post_message(KMSG_CRED, KMSG_CRED_END, 0, (void *) nc); } break; /* MUST be called with SendMessage */ case WMNC_ADD_CONTROL_ROW: { khui_control_row * row; row = (khui_control_row *) lParam; #ifdef DEBUG assert(row->label); assert(row->input); #endif nc_add_control_row(d, row->label, row->input, row->size); } break; case WMNC_UPDATE_LAYOUT: { RECT r_client; khm_int32 animate; khm_int32 steps; khm_int32 timeout; /* We are already adjusting the size of the window. The next time the timer fires, it will notice if the target size has changed. */ if (d->size_changing) return TRUE; GetClientRect(hwnd, &r_client); if ((r_client.right - r_client.left == d->r_required.right - d->r_required.left) && (r_client.bottom - r_client.top == d->r_required.bottom - d->r_required.top)) { /* the window is already at the right size */ return TRUE; } if (!IsWindowVisible(hwnd)) { /* The window is not visible yet. There's no need to animate anything. */ animate = FALSE; } else if (KHM_FAILED(khc_read_int32(NULL, L"CredWindow\\Windows\\NewCred\\AnimateSizeChanges", &animate))) { #ifdef DEBUG assert(FALSE); #endif animate = TRUE; } /* if we aren't animating the window resize, then we just do it in one call. */ if (!animate || !d->animation_enabled) { RECT r_window; CopyRect(&r_window, &d->r_required); AdjustWindowRectEx(&r_window, NC_WINDOW_STYLES, FALSE, NC_WINDOW_EX_STYLES); SetWindowPos(hwnd, NULL, 0, 0, r_window.right - r_window.left, r_window.bottom - r_window.top, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER); return TRUE; } if (KHM_FAILED(khc_read_int32(NULL, L"CredWindow\\Windows\\NewCred\\AnimationSteps", &steps))) { #ifdef DEBUG assert(FALSE); #endif steps = NC_SZ_STEPS_DEF; } else { if (steps < NC_SZ_STEPS_MIN) steps = NC_SZ_STEPS_MIN; else if (steps > NC_SZ_STEPS_MAX) steps = NC_SZ_STEPS_MAX; } if (KHM_FAILED(khc_read_int32(NULL, L"CredWindow\\Windows\\NewCred\\AnimationStepTimeout", &timeout))) { #ifdef DEBUG assert(FALSE); #endif timeout = NC_SZ_TIMEOUT_DEF; } else { if (timeout < NC_SZ_TIMEOUT_MIN) timeout = NC_SZ_TIMEOUT_MIN; else if (timeout > NC_SZ_TIMEOUT_MAX) timeout = NC_SZ_TIMEOUT_MAX; } CopyRect(&d->sz_ch_source, &r_client); OffsetRect(&d->sz_ch_source, -d->sz_ch_source.left, -d->sz_ch_source.top); CopyRect(&d->sz_ch_target, &d->r_required); OffsetRect(&d->sz_ch_target, -d->sz_ch_target.left, -d->sz_ch_target.top); d->sz_ch_increment = 0; d->sz_ch_max = steps; d->sz_ch_timeout = timeout; d->size_changing = TRUE; SetTimer(hwnd, NC_TIMER_SIZER, timeout, NULL); } break; } /* switch(HIWORD(wParam)) */ return TRUE; } static LRESULT nc_handle_wm_timer(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { khui_nc_wnd_data * d; d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, CW_PARAM); if (wParam == NC_TIMER_SIZER) { RECT r_now; /* are we done with this sizing operation? */ if (!d->size_changing || d->sz_ch_increment >= d->sz_ch_max) { d->size_changing = FALSE; KillTimer(hwnd, NC_TIMER_SIZER); return 0; } /* have the requirements changed while we were processing the sizing operation? */ if ((d->r_required.right - d->r_required.left != d->sz_ch_target.right) || (d->r_required.bottom - d->r_required.top != d->sz_ch_target.bottom)) { /* the target size has changed. we need to restart the sizing operation. */ RECT r_client; GetClientRect(hwnd, &r_client); CopyRect(&d->sz_ch_source, &r_client); OffsetRect(&d->sz_ch_source, -d->sz_ch_source.left, -d->sz_ch_source.top); CopyRect(&d->sz_ch_target, &d->r_required); OffsetRect(&d->sz_ch_target, -d->sz_ch_target.left, -d->sz_ch_target.top); d->sz_ch_increment = 0; /* leave the other fields alone */ #ifdef DEBUG assert(d->sz_ch_max >= NC_SZ_STEPS_MIN); assert(d->sz_ch_max <= NC_SZ_STEPS_MAX); assert(d->sz_ch_timeout >= NC_SZ_TIMEOUT_MIN); assert(d->sz_ch_timeout <= NC_SZ_TIMEOUT_MAX); assert(d->size_changing); #endif } /* we are going to do the next increment */ d->sz_ch_increment ++; /* now, figure out the size of the client area for this step */ r_now.left = 0; r_now.top = 0; #define PROPORTION(v1, v2, i, s) (((v1) * ((s) - (i)) + (v2) * (i)) / (s)) r_now.right = PROPORTION(d->sz_ch_source.right, d->sz_ch_target.right, d->sz_ch_increment, d->sz_ch_max); r_now.bottom = PROPORTION(d->sz_ch_source.bottom, d->sz_ch_target.bottom, d->sz_ch_increment, d->sz_ch_max); #undef PROPORTION #ifdef DEBUG { long dx = (r_now.right - d->sz_ch_target.right) * (d->sz_ch_source.right - d->sz_ch_target.right); long dy = (r_now.bottom - d->sz_ch_target.bottom) * (d->sz_ch_source.bottom - d->sz_ch_target.bottom); if (dx < 0 || dy < 0) { KillTimer(hwnd, NC_TIMER_SIZER); assert(dx >= 0); assert(dy >= 0); SetTimer(hwnd, NC_TIMER_SIZER, d->sz_ch_timeout, NULL); } } #endif AdjustWindowRectEx(&r_now, NC_WINDOW_STYLES, FALSE, NC_WINDOW_EX_STYLES); SetWindowPos(hwnd, NULL, 0, 0, r_now.right - r_now.left, r_now.bottom - r_now.top, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER); /* and now we wait for the next timer message */ return 0; } else if (wParam == NC_TIMER_ENABLEANIMATE) { d->animation_enabled = TRUE; KillTimer(hwnd, NC_TIMER_ENABLEANIMATE); } return 0; } static LRESULT nc_handle_wm_notify(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LPNMHDR nmhdr; khui_nc_wnd_data * d; d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, CW_PARAM); nmhdr = (LPNMHDR) lParam; if (nmhdr->code == TCN_SELCHANGE) { /* the current tab has changed. */ int idx; TCITEM tcitem; idx = TabCtrl_GetCurSel(d->tab_wnd); ZeroMemory(&tcitem, sizeof(tcitem)); tcitem.mask = TCIF_PARAM; TabCtrl_GetItem(d->tab_wnd, idx, &tcitem); d->current_panel = (int) tcitem.lParam; nc_layout_new_cred_window(d); return TRUE; } return FALSE; } static LRESULT nc_handle_wm_help(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { static DWORD ctxids[] = { NC_TS_CTRL_ID_MIN, IDH_NC_TABMAIN, NC_TS_CTRL_ID_MIN + 1, IDH_NC_TABBUTTON, NC_TS_CTRL_ID_MIN + 2, IDH_NC_TABBUTTON, NC_TS_CTRL_ID_MIN + 3, IDH_NC_TABBUTTON, NC_TS_CTRL_ID_MIN + 4, IDH_NC_TABBUTTON, NC_TS_CTRL_ID_MIN + 5, IDH_NC_TABBUTTON, NC_TS_CTRL_ID_MIN + 6, IDH_NC_TABBUTTON, NC_TS_CTRL_ID_MIN + 7, IDH_NC_TABBUTTON, IDOK, IDH_NC_OK, IDCANCEL, IDH_NC_CANCEL, IDC_NC_HELP, IDH_NC_HELP, IDC_NC_ADVANCED, IDH_NC_ADVANCED, IDC_NC_CREDTEXT, IDH_NC_CREDWND, 0 }; HELPINFO * hlp; HWND hw = NULL; HWND hw_ctrl; khui_nc_wnd_data * d; d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, CW_PARAM); hlp = (HELPINFO *) lParam; if (d->nc->subtype != KMSG_CRED_NEW_CREDS && d->nc->subtype != KMSG_CRED_PASSWORD) return TRUE; if (hlp->iContextType != HELPINFO_WINDOW) return TRUE; if (hlp->hItemHandle != NULL && hlp->hItemHandle != hwnd) { DWORD id; int i; hw_ctrl =hlp->hItemHandle; id = GetWindowLong(hw_ctrl, GWL_ID); for (i=0; ctxids[i] != 0; i += 2) if (ctxids[i] == id) break; if (ctxids[i] != 0) hw = khm_html_help(hw_ctrl, ((d->nc->subtype == KMSG_CRED_NEW_CREDS)? L"::popups_newcreds.txt": L"::popups_password.txt"), HH_TP_HELP_WM_HELP, (DWORD_PTR) ctxids); } if (hw == NULL) { khm_html_help(hwnd, NULL, HH_HELP_CONTEXT, ((d->nc->subtype == KMSG_CRED_NEW_CREDS)? IDH_ACTION_NEW_ID: IDH_ACTION_PASSWD_ID)); } return TRUE; } static LRESULT CALLBACK nc_window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_CREATE: return nc_handle_wm_create(hwnd, uMsg, wParam, lParam); case WM_DESTROY: return nc_handle_wm_destroy(hwnd, uMsg, wParam, lParam); case WM_COMMAND: return nc_handle_wm_command(hwnd, uMsg, wParam, lParam); case WM_NOTIFY: return nc_handle_wm_notify(hwnd, uMsg, wParam, lParam); case WM_MOVE: case WM_MOVING: return nc_handle_wm_moving(hwnd, uMsg, wParam, lParam); case WM_TIMER: return nc_handle_wm_timer(hwnd, uMsg, wParam, lParam); case WM_HELP: return nc_handle_wm_help(hwnd, uMsg, wParam, lParam); case KHUI_WM_NC_NOTIFY: return nc_handle_wm_nc_notify(hwnd, uMsg, wParam, lParam); } /* Note that this is technically a dialog box */ return DefDlgProc(hwnd, uMsg, wParam, lParam); } void khm_register_newcredwnd_class(void) { WNDCLASSEX wcx; wcx.cbSize = sizeof(wcx); wcx.style = CS_DBLCLKS | CS_OWNDC; wcx.lpfnWndProc = nc_window_proc; wcx.cbClsExtra = 0; wcx.cbWndExtra = DLGWINDOWEXTRA + sizeof(LONG_PTR); wcx.hInstance = khm_hInstance; wcx.hIcon = LoadIcon(khm_hInstance, MAKEINTRESOURCE(IDI_MAIN_APP)); wcx.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW); wcx.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); wcx.lpszMenuName = NULL; wcx.lpszClassName = KHUI_NEWCREDWND_CLASS; wcx.hIconSm = NULL; khui_newcredwnd_cls = RegisterClassEx(&wcx); } void khm_unregister_newcredwnd_class(void) { UnregisterClass((LPWSTR) khui_newcredwnd_cls, khm_hInstance); } HWND khm_create_newcredwnd(HWND parent, khui_new_creds * c) { wchar_t wtitle[256]; HWND hwnd; if (c->window_title == NULL) { if (c->subtype == KMSG_CRED_PASSWORD) LoadString(khm_hInstance, IDS_WT_PASSWORD, wtitle, ARRAYLENGTH(wtitle)); else LoadString(khm_hInstance, IDS_WT_NEW_CREDS, wtitle, ARRAYLENGTH(wtitle)); } hwnd = CreateWindowEx(NC_WINDOW_EX_STYLES, MAKEINTATOM(khui_newcredwnd_cls), ((c->window_title)?c->window_title: wtitle), NC_WINDOW_STYLES, 0,0,400,400, /* bogus values. the window is going to resize and reposition itself anyway */ parent, NULL, khm_hInstance, (LPVOID) c); #ifdef DEBUG assert(hwnd != NULL); #endif /* note that the window is not visible yet. That's because, at this point we don't know what the panels are */ return hwnd; } void khm_prep_newcredwnd(HWND hwnd) { SendMessage(hwnd, KHUI_WM_NC_NOTIFY, MAKEWPARAM(0, WMNC_DIALOG_SETUP), 0); } void khm_show_newcredwnd(HWND hwnd) { /* add all the panels in and prep UI */ PostMessage(hwnd, KHUI_WM_NC_NOTIFY, MAKEWPARAM(0, WMNC_DIALOG_ACTIVATE), 0); }