summaryrefslogtreecommitdiffstats
path: root/src/windows/lib/vardlg.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/windows/lib/vardlg.c')
-rw-r--r--src/windows/lib/vardlg.c450
1 files changed, 450 insertions, 0 deletions
diff --git a/src/windows/lib/vardlg.c b/src/windows/lib/vardlg.c
new file mode 100644
index 0000000000..41d897bf7b
--- /dev/null
+++ b/src/windows/lib/vardlg.c
@@ -0,0 +1,450 @@
+/*
+ * Dialog box building for various numbers of (label, entry) fields.
+ *
+ * This code is somewhat hardcoded to build boxes for the krb5_get_init_creds()
+ * function.
+ *
+ * Copyright (C) 1997 Cygnus Solutions.
+ *
+ * Author: Michael Graff
+ */
+
+#include <windows.h>
+#include <windowsx.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "krb5.h"
+#include "vardlg.h"
+
+/*
+ * a hack, I know... No error checking below, either.
+ */
+static unsigned char dlg[DLG_BUF];
+
+/*
+ * Add a WORD (16-bit int) to the buffer. Return the number of characters
+ * added.
+ */
+static int
+ADD_WORD(unsigned char *p, WORD w)
+{
+ *((WORD *)p) = w;
+
+ return 2;
+}
+
+static int
+ADD_DWORD(unsigned char *p, DWORD dw)
+{
+ *((DWORD *)p) = dw;
+
+ return 4;
+}
+
+static int
+ADD_UNICODE_STRING(unsigned char *p, const char *s)
+{
+ WORD *w;
+ int i;
+ int len;
+
+ w = (WORD *)p;
+
+ len = strlen(s) + 1; /* copy the null, too */
+
+ for (i = 0 ; i < len ; i++)
+ *w++ = *s++;
+
+ return (len * 2);
+}
+
+#define DWORD_ALIGN(p) { while ((DWORD)p % 4) *p++ = 0x00; }
+
+static int
+ADD_DLGTEMPLATE(unsigned char *dlg, short x, short y, short cx, short cy,
+ const char *caption, const char *fontname, WORD fontsize,
+ WORD n)
+{
+ unsigned char *p;
+ DLGTEMPLATE dlt;
+
+ p = dlg;
+
+ dlt.style = (DS_MODALFRAME | WS_POPUP);
+ if (caption != NULL)
+ dlt.style |= WS_CAPTION;
+ if (fontname != NULL)
+ dlt.style |= DS_SETFONT;
+ dlt.dwExtendedStyle = 0;
+ dlt.cdit = n;
+ dlt.x = x;
+ dlt.y = y;
+ dlt.cx = cx;
+ dlt.cy = cy;
+ memcpy(p, &dlt, sizeof(dlt));
+ p += sizeof(dlt);
+
+ p += ADD_WORD(p, 0x0000); /* menu == none */
+
+ p += ADD_WORD(p, 0x0000); /* class == default? */
+
+ if (caption != NULL)
+ p += ADD_UNICODE_STRING(p, caption);
+ else
+ p += ADD_WORD(p, 0x0000);
+
+ if (fontname != NULL) {
+ p += ADD_WORD(p, fontsize);
+ p += ADD_UNICODE_STRING(p, fontname);
+ }
+
+ DWORD_ALIGN(p);
+
+ return (p - dlg);
+}
+
+static int
+ADD_DLGITEM(unsigned char *dlg, short x, short y, short cx, short cy,
+ const char *label, WORD id, WORD type, DWORD style)
+{
+ unsigned char *p;
+ DLGITEMTEMPLATE dit;
+
+ p = dlg;
+
+ dit.style = style;
+ dit.dwExtendedStyle = 0;
+ dit.x = x;
+ dit.y = y;
+ dit.cx = cx;
+ dit.cy = cy;
+ dit.id = id;
+ memcpy(p, &dit, sizeof(dit));
+ p += sizeof(dit);
+
+ p += ADD_WORD(p, 0xffff);
+ p += ADD_WORD(p, type);
+
+ p += ADD_UNICODE_STRING(p, label);
+
+ /*
+ * creation data? For now, just make this empty, like the resource
+ * compiler does.
+ */
+ p += ADD_WORD(p, 0x0000);
+
+ DWORD_ALIGN(p);
+
+ return (p - dlg);
+}
+
+#define ADD_DLGITEM_defpushbutton(a, b, c, d, e, f, g) \
+ ADD_DLGITEM((a), (b), (c), (d), (e), (f), (g), 0x0080, 0x50010001);
+
+#define ADD_DLGITEM_pushbutton(a, b, c, d, e, f, g) \
+ ADD_DLGITEM((a), (b), (c), (d), (e), (f), (g), 0x0080, 0x50010000);
+
+#define ADD_DLGITEM_left_static(a, b, c, d, e, f, g) \
+ ADD_DLGITEM((a), (b), (c), (d), (e), (f), (g), 0x0082, 0x50020000);
+
+#define ADD_DLGITEM_centered_static(a, b, c, d, e, f, g) \
+ ADD_DLGITEM((a), (b), (c), (d), (e), (f), (g), 0x0082, 0x50020001);
+
+#define ADD_DLGITEM_right_static(a, b, c, d, e, f, g) \
+ ADD_DLGITEM((a), (b), (c), (d), (e), (f), (g), 0x0082, 0x50020002);
+
+#define ADD_DLGITEM_entry(a, b, c, d, e, f, g) \
+ ADD_DLGITEM((a), (b), (c), (d), (e), (f), (g), 0x0081, 0x50810080);
+
+#define ADD_DLGITEM_hidden_entry(a, b, c, d, e, f, g) \
+ ADD_DLGITEM((a), (b), (c), (d), (e), (f), (g), 0x0081, 0x508100a0);
+
+
+/*
+ * "build" the dialog box. In this bit of code, we create the dialog box,
+ * create the OK button, and a static label for the banner text.
+ *
+ * If there are items, we also create a Cancel button and one (label, entry)
+ * fields for each item.
+ */
+void *
+vardlg_build(WORD cx, const char *banner, WORD n, krb5_prompt prompts[],
+ WORD id)
+{
+ unsigned char *p;
+ WORD i;
+
+ p = dlg; /* global */
+
+ if (cx < MIN_WIDTH)
+ cx = MIN_WIDTH;
+ if (cx > MAX_WIDTH)
+ cx = MAX_WIDTH;
+
+ /*
+ * Store the dialog template
+ */
+ p += ADD_DLGTEMPLATE(p, 0, 0, cx, 0, "KerbNet", "MS Sans Serif", 8,
+ (WORD)(n * 2 + 3));
+
+ /*
+ * Create a label for the banner. This will be ID (id).
+ */
+ p += ADD_DLGITEM_left_static(p, 0, 0, 0, 0, "", id++);
+
+ /*
+ * Each label field is ID (id + 1) + (item * 2), and each entry field
+ * is (id + 2) + (item * 2)
+ */
+ for (i = 0 ; i < n ; i++) {
+ p += ADD_DLGITEM_right_static(p, 0, 0, 0, 0, "", id++);
+ if (prompts[i].hidden) {
+ p += ADD_DLGITEM_hidden_entry(p, 0, 0, 0, 0, "", id++);
+ } else {
+ p += ADD_DLGITEM_entry(p, 0, 0, 0, 0, "", id++);
+ }
+ }
+
+ /*
+ * Create the OK and Cancel buttons.
+ */
+ p += ADD_DLGITEM_defpushbutton(p, 0, 0, 0, 0,
+ "OK", IDOK);
+ if (n != 0)
+ p += ADD_DLGITEM_pushbutton(p, 0, 0, 0, 0,
+ "Cancel", IDCANCEL);
+
+ return dlg;
+}
+
+#define SPACE_Y 4 /* logical units */
+#define SPACE_X 4 /* logical units */
+#define ENTRY_PX 120 /* pixels */
+#define BUTTON_PX 70 /* pixels */
+#define BUTTON_PY 30 /* pixels */
+
+void
+vardlg_config(HWND hwnd, WORD width, const char *banner, WORD num_prompts,
+ krb5_prompt *prompts, WORD id)
+{
+ int n;
+ WORD cid;
+ HDC hdc;
+ SIZE csize;
+ SIZE maxsize;
+ LONG cx, cy;
+ LONG ccx, ccy;
+ LONG space_x, space_y;
+ LONG max_x, max_y;
+ LONG banner_y;
+ RECT rect;
+ int done;
+ const char *p;
+
+ /*
+ * First, set the banner's text.
+ */
+ Static_SetText(GetDlgItem(hwnd, id), banner);
+
+ /*
+ * Next, run through the items and set their static text.
+ * Also, set the corresponding edit string and set the
+ * maximum input length.
+ */
+ cid = (id + 1);
+
+ for (n = 0 ; n < num_prompts ; n++) {
+ Static_SetText(GetDlgItem(hwnd, cid), prompts[n].prompt);
+ cid++;
+ Edit_SetText(GetDlgItem(hwnd, cid), "");
+ Edit_LimitText(GetDlgItem(hwnd, cid), prompts[n].reply->length);
+ cid++;
+ }
+
+ /*
+ * Now run through the entry fields and find the longest string.
+ */
+ maxsize.cx = maxsize.cy = 0;
+ cid = (id + 1);
+ hdc = GetDC(GetDlgItem(hwnd, cid)); /* assume one label is the same as all the others */
+
+ for (n = 0 ; n < num_prompts ; n++) {
+ GetTextExtentPoint32(hdc, prompts[n].prompt, strlen(prompts[n].prompt), &csize);
+ if (csize.cx > maxsize.cx)
+ maxsize.cx = csize.cx;
+ if (csize.cy > maxsize.cy)
+ maxsize.cy = csize.cy;
+ }
+
+#if 0
+ /*
+ * convert the maximum values into pixels. Ugh.
+ */
+ rect.left = 0;
+ rect.top = 0;
+ rect.right = maxsize.cx;
+ rect.bottom = maxsize.cy;
+ MapDialogRect(hwnd, &rect);
+
+ max_x = rect.right;
+ max_y = rect.bottom;
+#else
+ max_x = maxsize.cx;
+ max_y = (long)(((double)maxsize.cy) * 1.5);
+#endif
+
+ /*
+ * convert the spacing values, too. Ugh. Ugh.
+ */
+ rect.left = 0;
+ rect.top = 0;
+ rect.right = SPACE_X;
+ rect.bottom = SPACE_Y;
+ MapDialogRect(hwnd, &rect);
+
+ space_x = rect.right;
+ space_y = rect.bottom;
+
+ /*
+ * Now we know the maximum length of the string for the entry labels. Guestimate
+ * that the entry fields should be ENTRY_PX pixels long and resize the dialog
+ * window to fit the longest string plus the entry fields (plus a little for the
+ * spacing between the edges of the windows and the static and edit fields, and
+ * between the static and edit fields themselves.)
+ */
+ cx = max_x + ENTRY_PX + (space_x * 3);
+ cy = (max_y + space_y) * num_prompts;
+
+ /*
+ * resize the dialog box itself (take 1)
+ */
+ SetWindowPos(hwnd, HWND_TOPMOST,
+ 0, 0,
+ cx + 10, cy + 30,
+ SWP_NOMOVE);
+
+ /*
+ * position the dialog items. First, the banner. (take 1)
+ */
+ SetWindowPos(GetDlgItem(hwnd, id), HWND_BOTTOM,
+ space_x, space_y,
+ (cx - space_x * 2), max_y,
+ 0);
+
+ /*
+ * Now that the window for the banner is in place, convert the width into logical units
+ * and find out how many lines we need to reserve room for.
+ */
+ done = 0;
+ p = banner;
+ banner_y = 0;
+
+ do {
+ int nFit;
+ int pDx[128];
+
+ hdc = GetDC(GetDlgItem(hwnd, id));
+
+ GetTextExtentExPoint(hdc, p, strlen(p), cx, &nFit,
+ pDx, &csize);
+
+ banner_y += csize.cy;
+
+ p += nFit;
+
+ } while (*p != 0);
+
+ banner_y += space_y;
+
+ /*
+ * position the banner (take 2)
+ */
+ SetWindowPos(GetDlgItem(hwnd, id), HWND_BOTTOM,
+ space_x, space_y,
+ (cx - space_x * 2), banner_y,
+ 0);
+
+ /*
+ * Don't forget to include the banner estimate and the buttons, too. Once again,
+ * assume the buttons are BUTTON_PY pixels high. The extra three space_y's are
+ * for between the top of the dialog and the banner, between the banner and the
+ * first label, and between the buttons and the bottom of the screen.
+ */
+ cy += banner_y + BUTTON_PY + (space_y * 3);
+
+ /*
+ * resize the dialog box itself (Again... ugh!)
+ */
+ SetWindowPos(hwnd, HWND_TOPMOST,
+ 0, 0,
+ cx + 10, cy + 30,
+ SWP_NOMOVE);
+
+ cid = (id + 1);
+ ccy = banner_y + (space_y * 2);
+ ccx = max_x + (space_x * 2); /* where the edit fields start */
+
+ for (n = 0 ; n < num_prompts ; n++) {
+ SetWindowPos(GetDlgItem(hwnd, cid), HWND_BOTTOM,
+ space_x, ccy,
+ max_x, max_y, 0);
+ cid++;
+ SetWindowPos(GetDlgItem(hwnd, cid), HWND_BOTTOM,
+ ccx, ccy,
+ ENTRY_PX, max_y - 3, 0);
+ cid++;
+ ccy += (max_y + space_y);
+ }
+
+ /*
+ * Now the buttons. If there are any entries we will have both an OK and a
+ * Cancel button. If we don't have any entries, we will have only an OK.
+ */
+ if (num_prompts == 0) {
+ SetWindowPos(GetDlgItem(hwnd, IDOK), HWND_BOTTOM,
+ (cx / 2), cy - space_y - BUTTON_PY,
+ BUTTON_PX, BUTTON_PY, 0);
+ } else {
+ SetWindowPos(GetDlgItem(hwnd, IDOK), HWND_BOTTOM,
+ space_x, cy - space_y - BUTTON_PY,
+ BUTTON_PX, BUTTON_PY, 0);
+ SetWindowPos(GetDlgItem(hwnd, IDCANCEL), HWND_BOTTOM,
+ cx - space_x - BUTTON_PX, cy - space_y - BUTTON_PY,
+ BUTTON_PX, BUTTON_PY, 0);
+ }
+
+ return;
+}
+
+/*
+ * To use these functions, first create the dialog box and entries.
+ * You will always get an OK button. If there are at least one item,
+ * you will also get a cancel button. The OK button is IDOK, and the cancel
+ * button is IDCANCEL, as usual.
+ *
+ * After calling bld_dlg, the banner will have ID "id", and the labels
+ * will be "1 + id + i * 2" (i is the entry number, starting with zero) and
+ * the entries will be "2 + id + i * 2".
+ *
+ * unsigned char *dlg = vardlg_build(minwidth, banner, num_prompts,
+ * krb5_prompt[], id);
+ *
+ * Then, "run" the dialog using:
+ *
+ * rc = DialogBoxIndirect(hinstance, (LPDLGTEMPLATE)dlg,
+ * HWND_DESKTOP, myDialogProc);
+ *
+ * Note that the vardlg_build function uses a static data area and so cannot
+ * be used more than once before the DialogBoxIndirect() procedure is called.
+ * I assume windows won't need that area after that call is complete.
+ *
+ * In the dialog's _initialization_ procedure, call
+ *
+ * vardlg_config(hwnd, banner, num_prompts, krb5_prompt[], id);
+ *
+ * This function will resize the various elements of the dialog and fill in the
+ * labels.
+ */