Example #1
0
static LRESULT CALLBACK groupSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR id, DWORD_PTR data)
{
	LRESULT lResult;
	RECT r;

	if (sharedWndProc(hwnd, uMsg, wParam, lParam, &lResult))
		return lResult;
	switch (uMsg) {
	case WM_WINDOWPOSCHANGING:
	case WM_WINDOWPOSCHANGED:
		// don't use the WINDOWPOS rect here; the coordinates of the controls have to be in real client coordinates
		if (GetClientRect(hwnd, &r) == 0)
			xpanic("error getting client rect of Group for resizing its child Control", GetLastError());
		groupResized((void *) data, r);
		// and chain up
		return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
	case WM_NCDESTROY:
		if ((*fv_RemoveWindowSubclass)(hwnd, groupSubProc, id) == FALSE)
			xpanic("error removing Group subclass (which was for its own event handler)", GetLastError());
		return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
	default:
		return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
	}
	xmissedmsg("Group", "groupSubProc()", uMsg);
	return 0;		// unreached
}
Example #2
0
void paintControlBackground(HWND hwnd, HDC dc)
{
    HWND parent;
    RECT r;
    POINT p, pOrig;

    parent = hwnd;
    for (;;) {
        parent = GetParent(parent);
        if (parent == NULL)
            xpanic("error getting parent control of control in paintControlBackground()", GetLastError());
        // wine sends these messages early, yay...
        if (parent == msgwin)
            return;
        // skip groupboxes; they're (supposed to be) transparent
        if (windowClassOf(parent, L"button", NULL) != 0)
            break;
    }
    if (GetWindowRect(hwnd, &r) == 0)
        xpanic("error getting control's window rect in paintControlBackground()", GetLastError());
    // the above is a window rect; convert to client rect
    p.x = r.left;
    p.y = r.top;
    if (ScreenToClient(parent, &p) == 0)
        xpanic("error getting client origin of control in paintControlBackground()", GetLastError());
    if (SetWindowOrgEx(dc, p.x, p.y, &pOrig) == 0)
        xpanic("error moving window origin in paintControlBackground()", GetLastError());
    SendMessageW(parent, WM_PRINTCLIENT, (WPARAM) dc, PRF_CLIENT);
    if (SetWindowOrgEx(dc, pOrig.x, pOrig.y, NULL) == 0)
        xpanic("error resetting window origin in paintControlBackground()", GetLastError());
}
Example #3
0
static HIMAGELIST newCheckboxImageList(HWND hwnddc, void (*sizefunc)(HDC, int *, int *, HTHEME), void (*drawfunc)(HDC, RECT *, int, HTHEME), HTHEME theme)
{
	int width, height;
	int cbState;
	HDC dc;
	HIMAGELIST il;

	dc = GetDC(hwnddc);
	if (dc == NULL)
		xpanic("error getting DC for making the checkbox image list", GetLastError());
	(*sizefunc)(dc, &width, &height, theme);
	il = (*fv_ImageList_Create)(width, height, ILC_COLOR32, 20, 20);		// should be reasonable
	if (il == NULL)
		xpanic("error creating checkbox image list", GetLastError());
	for (cbState = 0; cbState < checkboxnStates; cbState++) {
		HBITMAP bitmap;

		bitmap = makeCheckboxImageListEntry(dc, width, height, cbState, drawfunc, theme);
		if ((*fv_ImageList_Add)(il, bitmap, NULL) == -1)
			xpanic("error adding checkbox image to image list", GetLastError());
		if (DeleteObject(bitmap) == 0)
			xpanic("error deleting checkbox bitmap", GetLastError());
	}
	if (ReleaseDC(hwnddc, dc) == 0)
		xpanic("error deleting checkbox image list DC", GetLastError());
	return il;
}
Example #4
0
void applyImageList(HWND hwnd, UINT uMsg, WPARAM wParam, HIMAGELIST il, HIMAGELIST old)
{
	if (SendMessageW(hwnd, uMsg, wParam, (LPARAM) il) != (LRESULT) old)
		xpanic("error setting image list", GetLastError());
	if (old != NULL && (*fv_ImageList_Destroy)(old) == 0)
		xpanic("error freeing old checkbox image list", GetLastError());

}
Example #5
0
void repaintArea(HWND hwnd, RECT *r)
{
	// NULL - the whole area; TRUE - have windows erase if possible
	if (InvalidateRect(hwnd, r, TRUE) == 0)
		xpanic("error flagging Area as needing repainting after event", GetLastError());
	if (UpdateWindow(hwnd) == 0)
		xpanic("error repainting Area after event", GetLastError());
}
Example #6
0
void textfieldSetAndShowInvalidBalloonTip(HWND hwnd, WCHAR *text)
{
	EDITBALLOONTIP ti;

	ZeroMemory(&ti, sizeof (EDITBALLOONTIP));
	ti.cbStruct = sizeof (EDITBALLOONTIP);
	ti.pszTitle = L"Invalid Input";		// TODO this is necessary for the icon to show up; figure out some language-neutral thing
	ti.pszText = text;
	ti.ttiIcon = TTI_ERROR;
	if (SendMessageW(hwnd, EM_SHOWBALLOONTIP, 0, (LPARAM) (&ti)) == FALSE)
		xpanic("error showing TextField.Invalid() balloon tip", GetLastError());
	if (MessageBeep(0xFFFFFFFF) == 0)
		xpanic("error beeping in response to TextField.Invalid()", GetLastError());
}
Example #7
0
HWND newAreaTextField(HWND area, void *goarea)
{
	HWND tf;

	tf = CreateWindowExW(textfieldExtStyle,
		L"edit", L"",
		textfieldStyle | WS_CHILD,
		0, 0, 0, 0,
		area, NULL, hInstance, NULL);
	if (tf == NULL)
		xpanic("error making Area TextField", GetLastError());
	if ((*fv_SetWindowSubclass)(tf, areaTextFieldSubProc, 0, (DWORD_PTR) goarea) == FALSE)
		xpanic("error subclassing Area TextField to give it its own WM_KILLFOCUS handler", GetLastError());
	return tf;
}
Example #8
0
static LRESULT CALLBACK tableSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR id, DWORD_PTR data)
{
	NMHDR *nmhdr = (NMHDR *) lParam;
	NMLVDISPINFOW *fill = (NMLVDISPINFO *) lParam;

	switch (uMsg) {
	case msgNOTIFY:
		switch (nmhdr->code) {
		case LVN_GETDISPINFO:
			tableGetCellText((void *) data, fill->item.iItem, fill->item.iSubItem, &(fill->item.pszText));
			return 0;
		}
		return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
	// see table.autoresize() in table_windows.go for the column autosize policy
	case WM_NOTIFY:		// from the contained header control
		if (nmhdr->code == HDN_BEGINTRACK)
			tableStopColumnAutosize((void *) data);
		return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
	case WM_NCDESTROY:
		if ((*fv_RemoveWindowSubclass)(hwnd, tableSubProc, id) == FALSE)
			xpanic("error removing Table subclass (which was for its own event handler)", GetLastError());
		return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
	default:
		return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
	}
	xmissedmsg("Button", "tableSubProc()", uMsg);
	return 0;		// unreached
}
Example #9
0
static LRESULT CALLBACK checkboxSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR id, DWORD_PTR data)
{
	switch (uMsg) {
	case msgCOMMAND:
		if (HIWORD(wParam) == BN_CLICKED) {
			WPARAM check;

			// we didn't use BS_AUTOCHECKBOX (see controls_windows.go) so we have to manage the check state ourselves
			check = BST_CHECKED;
			if (SendMessage(hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED)
				check = BST_UNCHECKED;
			SendMessage(hwnd, BM_SETCHECK, check, 0);
			checkboxToggled((void *) data);
			return 0;
		}
		return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
	case WM_NCDESTROY:
		if ((*fv_RemoveWindowSubclass)(hwnd, checkboxSubProc, id) == FALSE)
			xpanic("error removing Checkbox subclass (which was for its own event handler)", GetLastError());
		return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
	default:
		return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
	}
	xmissedmsg("Checkbox", "checkboxSubProc()", uMsg);
	return 0;		// unreached
}
Example #10
0
void textfieldSetAndShowInvalidBalloonTip(HWND hwnd, WCHAR *text)
{
	EDITBALLOONTIP ti;

	ZeroMemory(&ti, sizeof (EDITBALLOONTIP));
	ti.cbStruct = sizeof (EDITBALLOONTIP);
	// this is required to show the error icon
	// this probably should be localized...
	ti.pszTitle = L"Invalid Input";
	ti.pszText = text;
	ti.ttiIcon = TTI_ERROR;
	if (SendMessageW(hwnd, EM_SHOWBALLOONTIP, 0, (LPARAM) (&ti)) == FALSE)
		xpanic("error showing TextField.Invalid() balloon tip", GetLastError());
	if (MessageBeep(0xFFFFFFFF) == 0)
		xpanic("error beeping in response to TextField.Invalid()", GetLastError());
}
Example #11
0
// this is a helper function that takes the logic of determining window classes and puts it all in one place
// there are a number of places where we need to know what window class an arbitrary handle has
// theoretically we could use the class atom to avoid a _wcsicmp()
// however, raymond chen advises against this - http://blogs.msdn.com/b/oldnewthing/archive/2004/10/11/240744.aspx (and we're not in control of the Tab class, before you say anything)
// usage: windowClassOf(hwnd, L"class 1", L"class 2", ..., NULL)
int windowClassOf(HWND hwnd, ...)
{
// MSDN says 256 is the maximum length of a class name; add a few characters just to be safe (because it doesn't say whether this includes the terminating null character)
#define maxClassName 260
    WCHAR classname[maxClassName + 1];
    va_list ap;
    WCHAR *curname;
    int i;

    if (GetClassNameW(hwnd, classname, maxClassName) == 0)
        xpanic("error getting name of window class in windowClassOf()", GetLastError());
    va_start(ap, hwnd);
    i = 0;
    for (;;) {
        curname = va_arg(ap, WCHAR *);
        if (curname == NULL)
            break;
        if (_wcsicmp(classname, curname) == 0) {
            va_end(ap);
            return i;
        }
        i++;
    }
    // no match
    va_end(ap);
    return -1;
}
Example #12
0
void setWindowText(HWND hwnd, LPWSTR text)
{
    switch (SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM) text)) {
    case FALSE:
        xpanic("WM_SETTEXT failed", GetLastError());
    }
}
Example #13
0
IndexChain *LookupGrid::lichain(int x, int z)
{
  if((x<0)||(z<0)||(x>=xsz)||(z>=zsz))
    xpanic("LookupGrid::lichain(%d,%d) in %dx%d-grid",x,z,xsz,zsz);

  return ichains[ x + (z*xsz) ];
}
Example #14
0
void tableAutosizeColumns(HWND hwnd, int nColumns)
{
	int i;

	for (i = 0; i < nColumns; i++)
		if (SendMessageW(hwnd, LVM_SETCOLUMNWIDTH, (WPARAM) i, (LPARAM) LVSCW_AUTOSIZE_USEHEADER) == FALSE)
			xpanic("error resizing columns of results list view", GetLastError());
}
Example #15
0
RECT containerBounds(HWND hwnd)
{
	RECT r;

	if (GetClientRect(hwnd, &r) == 0)
		xpanic("error getting container client rect for container.bounds()", GetLastError());
	return r;
}
Example #16
0
static void getScrollPos(HWND hwnd, int *xpos, int *ypos)
{
	SCROLLINFO si;

	ZeroMemory(&si, sizeof (SCROLLINFO));
	si.cbSize = sizeof (SCROLLINFO);
	si.fMask = SIF_POS | SIF_TRACKPOS;
	if (GetScrollInfo(hwnd, SB_HORZ, &si) == 0)
		xpanic("error getting horizontal scroll position for Area", GetLastError());
	*xpos = si.nPos;
	// MSDN example code reinitializes this each time, so we'll do it too just to be safe
	ZeroMemory(&si, sizeof (SCROLLINFO));
	si.cbSize = sizeof (SCROLLINFO);
	si.fMask = SIF_POS | SIF_TRACKPOS;
	if (GetScrollInfo(hwnd, SB_VERT, &si) == 0)
		xpanic("error getting vertical scroll position for Area", GetLastError());
	*ypos = si.nPos;
}
Example #17
0
void areaOpenTextField(HWND area, HWND textfield, int x, int y, int width, int height)
{
	int sx, sy;
	int baseX, baseY;
	LONG unused;

	getScrollPos(area, &sx, &sy);
	x += sx;
	y += sy;
	calculateBaseUnits(textfield, &baseX, &baseY, &unused);
	width = MulDiv(width, baseX, 4);
	height = MulDiv(height, baseY, 8);
	if (MoveWindow(textfield, x, y, width, height, TRUE) == 0)
		xpanic("error moving Area TextField in Area.OpenTextFieldAt()", GetLastError());
	ShowWindow(textfield, SW_SHOW);
	if (SetFocus(textfield) == NULL)
		xpanic("error giving Area TextField focus", GetLastError());
}
Example #18
0
bool Mod_TAZ::readTAZFile(const char *fname)
{
  FILE *f;
  rvulong i;

  if(zones != NULL)
    xpanic("Multiple read attempts in Mod_TAZ\n");

  f=fopen(fname,"rb");
  if(f==NULL)
    {
      perror(0, ERROR_FILE_ROPEN, "Cannot open `%s': %s",fname,strerror(errno));
      return false;
    };

  lprintf(1,"Reading `%s'\n",fname);
  fread(&size,sizeof(rvulong),1,f);

  zones=new Mod_TAZ_Entry[size]; MEM(zones);

  for(i=0;i<size;i++)
    {
      fread( &(zones[i].data), RV_TAZ_DATA_SIZE, 1,f);
      /* we are not interested in the rotation of the box, but rather in whether
       * a point is inside it. A point X is inside the box, if
       *
       *  Inv(RotMatrix)*(X - center) < SizeVec
       *
       * So, we can also invert the matrices now:
       */
      zones[i].data.rotation = zones[i].data.rotation.invert();

      zones[i].mods=NULL;
      zones[i].owns_mods=false;

      if(i>0)
	if(zones[i].data.id < zones[i-1].data.id)
	  xpanic("Assumption \"TAZ is sorted by ID's\" is wrong\n");
    };

  fclose(f);
  return true;
}
Example #19
0
static SIZE getAreaControlSize(HWND hwnd)
{
	RECT rect;
	SIZE size;

	if (GetClientRect(hwnd, &rect) == 0)
		xpanic("error getting size of actual Area control", GetLastError());
	size.cx = (LONG) (rect.right - rect.left);
	size.cy = (LONG) (rect.bottom - rect.top);
	return size;
}
Example #20
0
HIMAGELIST newImageList(int width, int height)
{
	HIMAGELIST il;

	// TODO does this strip alpha?
	// sinni800 in irc.freenode.net/#go-nuts suggests our use of *image.RGBA makes this not so much of an issue
	il = (*fv_ImageList_Create)(width, height, ILC_COLOR32, 20, 20);		// should be reasonable
	if (il == NULL)
		xpanic("error creating image list", GetLastError());
	return il;
}
Example #21
0
void calculateBaseUnits(HWND hwnd, int *baseX, int *baseY, LONG *internalLeading)
{
	HDC dc;
	HFONT prevFont;
	TEXTMETRICW tm;
	SIZE size;

	dc = GetDC(hwnd);
	if (dc == NULL)
		xpanic("error getting DC for preferred size calculations", GetLastError());
	prevFont = (HFONT) SelectObject(dc, controlFont);
	if (prevFont == NULL)
		xpanic("error loading control font into device context for preferred size calculation", GetLastError());
	if (GetTextMetricsW(dc, &tm) == 0)
		xpanic("error getting text metrics for preferred size calculations", GetLastError());
	if (GetTextExtentPoint32W(dc, L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 52, &size) == 0)
		xpanic("error getting text extent point for preferred size calculations", GetLastError());
	*baseX = (int) ((size.cx / 26 + 1) / 2);
	*baseY = (int) tm.tmHeight;
	*internalLeading = tm.tmInternalLeading;
	if (SelectObject(dc, prevFont) != controlFont)
		xpanic("error restoring previous font into device context after preferred size calculations", GetLastError());
	if (ReleaseDC(hwnd, dc) == 0)
		xpanic("error releasing DC for preferred size calculations", GetLastError());
}
Example #22
0
void tableAppendColumn(HWND hwnd, int index, LPWSTR name)
{
	LVCOLUMNW col;

	ZeroMemory(&col, sizeof (LVCOLUMNW));
	col.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_ORDER;
	col.fmt = LVCFMT_LEFT;
	col.pszText = name;
	col.iSubItem = index;
	col.iOrder = index;
	if (SendMessageW(hwnd, LVM_INSERTCOLUMN, (WPARAM) index, (LPARAM) (&col)) == (LRESULT) -1)
		xpanic("error adding column to Table", GetLastError());
}
Example #23
0
static HBITMAP makeCheckboxImageListEntry(HDC dc, int width, int height, int cbState, void (*drawfunc)(HDC, RECT *, int, HTHEME), HTHEME theme)
{
	BITMAPINFO bi;
	VOID *ppvBits;
	HBITMAP bitmap;
	RECT r;
	HDC drawDC;
	HBITMAP prevbitmap;

	r.left = 0;
	r.top = 0;
	r.right = width;
	r.bottom = height;
	ZeroMemory(&bi, sizeof (BITMAPINFO));
	bi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
	bi.bmiHeader.biWidth = (LONG) width;
	bi.bmiHeader.biHeight = -((LONG) height);			// negative height to force top-down drawing;
	bi.bmiHeader.biPlanes = 1;
	bi.bmiHeader.biBitCount = 32;
	bi.bmiHeader.biCompression = BI_RGB;
	bi.bmiHeader.biSizeImage = (DWORD) (width * height * 4);
	bitmap = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, &ppvBits, 0, 0);
	if (bitmap == NULL)
		xpanic("error creating HBITMAP for unscaled ImageList image copy", GetLastError());

	drawDC = CreateCompatibleDC(dc);
	if (drawDC == NULL)
		xpanic("error getting DC for checkbox image list bitmap", GetLastError());
	prevbitmap = SelectObject(drawDC, bitmap);
	if (prevbitmap == NULL)
		xpanic("error selecting checkbox image list bitmap into DC", GetLastError());
	(*drawfunc)(drawDC, &r, cbState, theme);
	if (SelectObject(drawDC, prevbitmap) != bitmap)
		xpanic("error selecting previous bitmap into checkbox image's DC", GetLastError());
	if (DeleteDC(drawDC) == 0)
		xpanic("error deleting checkbox image's DC", GetLastError());

	return bitmap;
}
Example #24
0
HWND newArea(void *data)
{
	HWND hwnd;

	hwnd = CreateWindowExW(
		0,
		areaWindowClass, L"",
		WS_HSCROLL | WS_VSCROLL | WS_CHILD | WS_VISIBLE | WS_TABSTOP,
		CW_USEDEFAULT, CW_USEDEFAULT,
		100, 100,
		msgwin, NULL, hInstance, data);
	if (hwnd == NULL)
		xpanic("container creation failed", GetLastError());
	return hwnd;
}
Example #25
0
static void themeSize(HDC dc, int *width, int *height, HTHEME theme)
{
	SIZE size;
	int cbState;

	size = getStateSize(dc, 0, theme);
	for (cbState = 1; cbState < checkboxnStates; cbState++) {
		SIZE against;

		against = getStateSize(dc, cbState, theme);
		if (size.cx != against.cx || size.cy != against.cy)
			xpanic("size mismatch in checkbox states", GetLastError());
	}
	*width = (int) size.cx;
	*height = (int) size.cy;
}
Example #26
0
static LRESULT CALLBACK areaTextFieldSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR id, DWORD_PTR data)
{
	switch (uMsg) {
	case WM_KILLFOCUS:
		ShowWindow(hwnd, SW_HIDE);
		areaTextFieldDone((void *) data);
		return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
	case WM_NCDESTROY:
		if ((*fv_RemoveWindowSubclass)(hwnd, areaTextFieldSubProc, id) == FALSE)
			xpanic("error removing Area TextField subclass (which was for handling WM_KILLFOCUS)", GetLastError());
		return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
	default:
		return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
	}
	xmissedmsg("Area TextField", "areaTextFieldSubProc()", uMsg);
	return 0;		// unreached
}
Example #27
0
bool NameList::add(const char *name, bool dupCheck/*=false*/)
{
  if(!name)
    xpanic("adding NULL name");
  if(cnt==max)
    grow();
  names[cnt]=strdup(name); MEM(names[cnt]);
  touched[cnt]=false;
  cnt++;
  if(dupCheck)
  {
    for(int i=0; i<cnt-1; i++)
      if(!strcmp(name, names[i]))
        return true;
  }
  return false;
}
Example #28
0
static LRESULT CALLBACK buttonSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR id, DWORD_PTR data)
{
	switch (uMsg) {
	case msgCOMMAND:
		if (HIWORD(wParam) == BN_CLICKED) {
			buttonClicked((void *) data);
			return 0;
		}
		return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
	case WM_NCDESTROY:
		if ((*fv_RemoveWindowSubclass)(hwnd, buttonSubProc, id) == FALSE)
			xpanic("error removing Button subclass (which was for its own event handler)", GetLastError());
		return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
	default:
		return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
	}
	xmissedmsg("Button", "buttonSubProc()", uMsg);
	return 0;		// unreached
}
Example #29
0
static LRESULT CALLBACK textfieldSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR id, DWORD_PTR data)
{
	switch (uMsg) {
	case msgCOMMAND:
		if (HIWORD(wParam) == EN_CHANGE) {
			textfieldChanged((void *) data);
			return 0;
		}
		return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
	case WM_NCDESTROY:
		if ((*fv_RemoveWindowSubclass)(hwnd, textfieldSubProc, id) == FALSE)
			xpanic("error removing TextField subclass (which was for its own event handler)", GetLastError());
		return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
	default:
		return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
	}
	xmissedmsg("TextField", "textfieldSubProc()", uMsg);
	return 0;		// unreached
}
Example #30
0
HBITMAP unscaledBitmap(void *i, intptr_t dx, intptr_t dy)
{
	BITMAPINFO bi;
	VOID *ppvBits;
	HBITMAP bitmap;

	ZeroMemory(&bi, sizeof (BITMAPINFO));
	bi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
	bi.bmiHeader.biWidth = (LONG) dx;
	bi.bmiHeader.biHeight = -((LONG) dy);			// negative height to force top-down drawing;
	bi.bmiHeader.biPlanes = 1;
	bi.bmiHeader.biBitCount = 32;
	bi.bmiHeader.biCompression = BI_RGB;
	bi.bmiHeader.biSizeImage = (DWORD) (dx * dy * 4);
	bitmap = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, &ppvBits, 0, 0);
	if (bitmap == NULL)
		xpanic("error creating HBITMAP for unscaled ImageList image copy", GetLastError());
	dotoARGB(i, (void *) ppvBits);
	return bitmap;
}