/****************************************************************************/ /* */ /* Copyright (C) 1987-1996 Microsoft Corp. */ /* All Rights Reserved */ /* */ /****************************************************************************/ /****************************** Module Header ******************************* * Module Name: util.c * * Contains miscellaneous utility functions for ImagEdit. * * History: * ****************************************************************************/ #include "imagedit.h" #include #include #define CBOVERHEAD (sizeof(INT)+sizeof(INT)+sizeof(INT)) #define MEMSIGHEAD 0x1234 #define MEMSIGTAIL 0x5678 /**************************************************************************** * MyAlloc * * * * History: * 25-Jul-1989 - Created ****************************************************************************/ VOID *MyAlloc( INT cbAlloc) { register HANDLE hMem; if (hMem = LocalAlloc(LMEM_FIXED, cbAlloc)) { return (VOID *)hMem; } else { MessageBeep(0); Message(MSG_OUTOFMEMORY); return NULL; } } /**************************************************************************** * MyRealloc * * * * History: * 25-Jul-1989 - Created ****************************************************************************/ VOID *MyRealloc( VOID *npMem, INT cbNewAlloc) { npMem = (VOID *)LocalReAlloc((HANDLE)npMem, cbNewAlloc, LMEM_MOVEABLE); if (!npMem) { MessageBeep(0); Message(MSG_OUTOFMEMORY); return NULL; } return npMem; } /**************************************************************************** * MyFree * * * History: * 25-Jul-1989 - Created ****************************************************************************/ VOID *MyFree( VOID *npMem) { if (LocalFree((HANDLE)npMem)) { MessageBeep(0); Message(MSG_MEMERROR); return npMem; } return NULL; } /************************************************************************ * Message * * This function puts up a message box. The message is described in * the gamdMessages table. * * Arguments: * UINT idMsg - Index to the message. * ... - Optional arguments. * * Returns: * What MessageBox returns. * ************************************************************************/ INT Message( UINT idMsg, ...) { va_list marker; INT RetCode; CHAR szT[CCHTEXTMAX]; va_start(marker, idMsg); vsprintf(szT, ids(gamdMessages[idMsg].ids), marker); RetCode = MessageBox(NULL, szT, ids(IDS_PGMTITLE), gamdMessages[idMsg].fMessageBox | MB_TASKMODAL); va_end(marker); return RetCode; } /************************************************************************ * CenterWindow * * This function centers the given window over its owner. It ensures * that the window is entirely within the visible screen, however. * If the window does not have an owner, it is centered over the * desktop. * * Arguments: * HWND hwnd - The window to center. * * History: * ************************************************************************/ VOID CenterWindow( HWND hwnd) { RECT rc; RECT rcOwner; RECT rcCenter; HWND hwndOwner; GetWindowRect(hwnd, &rc); if (!(hwndOwner = GetWindow(hwnd, GW_OWNER))) hwndOwner = GetDesktopWindow(); GetWindowRect(hwndOwner, &rcOwner); /* * Calculate the starting x,y for the new * window so that it would be centered. */ rcCenter.left = rcOwner.left + (((rcOwner.right - rcOwner.left) - (rc.right - rc.left)) / 2); rcCenter.top = rcOwner.top + (((rcOwner.bottom - rcOwner.top) - (rc.bottom - rc.top)) / 2); rcCenter.right = rcCenter.left + (rc.right - rc.left); rcCenter.bottom = rcCenter.top + (rc.bottom - rc.top); FitRectToScreen(&rcCenter); SetWindowPos(hwnd, NULL, rcCenter.left, rcCenter.top, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER); } /************************************************************************ * FitRectToScreen * * This function ensures that the given rectangle is entirely within * the visible screen, adjusting it if necessary. * * Arguments: * PRECT prc - The rectangle. * * History: * ************************************************************************/ VOID FitRectToScreen( PRECT prc) { INT cxScreen; INT cyScreen; INT delta; cxScreen = GetSystemMetrics(SM_CXSCREEN); cyScreen = GetSystemMetrics(SM_CYSCREEN); if (prc->right > cxScreen) { delta = prc->right - prc->left; prc->right = cxScreen; prc->left = prc->right - delta; } if (prc->left < 0) { delta = prc->right - prc->left; prc->left = 0; prc->right = prc->left + delta; } if (prc->bottom > cyScreen) { delta = prc->bottom - prc->top; prc->bottom = cyScreen; prc->top = prc->bottom - delta; } if (prc->top < 0) { delta = prc->bottom - prc->top; prc->top = 0; prc->bottom = prc->top + delta; } } /************************************************************************ * ids * * This function will return a string, given the string id. If this is * the first time that the string has been retrieved, memory will be * allocated for it and it will be loaded. After it is loaded once, it * is then cached in a PSTR array and is available for later without * having to load it again. * * Arguments: * UINT idString - String ID of the string to retrieve. * * History: * ************************************************************************/ PSTR ids( UINT idString) { static PSTR apstr[CSTRINGS]; // String resource array cache. PSTR pstr; INT cch; if (apstr[idString]) return apstr[idString]; if (!(pstr = MyAlloc(CCHTEXTMAX))) return ""; if (!(cch = LoadString(ghInst, idString, pstr, CCHTEXTMAX))) { MyFree(pstr); return ""; } apstr[idString] = pstr = MyRealloc(pstr, cch + 1); return (pstr ? pstr : ""); } /************************************************************************ * MyCreateBitmap * * * * Arguments: * * History: * ************************************************************************/ HBITMAP MyCreateBitmap( HDC hdc, INT cx, INT cy, INT nColors) { BITMAPINFOHEADER bmih; if (nColors == 2) { return CreateBitmap(cx, cy, 1, 1, NULL); } else { bmih.biSize = sizeof(BITMAPINFOHEADER); bmih.biWidth = cx; bmih.biHeight = cy; bmih.biPlanes = 1; // 1 plane, 4 bpp is bmih.biBitCount = 4; // 16 colors. bmih.biCompression = bmih.biSizeImage = bmih.biXPelsPerMeter = bmih.biYPelsPerMeter = bmih.biClrUsed = bmih.biClrImportant = 0; return CreateDIBitmap(hdc, &bmih, 0L, NULL, NULL, 0); } } #if defined(DBG) && defined(WIN16) /**************************************************************************** * DBGStackReport * * This debugging function reports how much stack is used by a program. * To use it, call it with fInit == TRUE right at the beginning of the * program and then with fInit == FALSE just before the program exits. * The stack space used during the current run of the program will be * displayed on the debug terminal. * * It is implemented by filling the stack with a certain value down to * the bottom of the stack (if fInit is TRUE). When it is called with * fInit == FALSE, it starts at the bottom of the stack and looks for * where this "signature" value has been overwritten with data, then * does a little math to compute the used stack. * * Arguments: * BOOL fInit - TRUE if the stack should be initialized, FALSE to * print out the report. * * History: * 28-Aug-1990 - Created ****************************************************************************/ /* * This signature byte will be used to fill the stack. */ #define STACKSIG 'A' /* * This is a C runtime global that is always at the very end of the * global data. Taking its address is a way that the "bottom" of the * stack can be found. */ extern CHAR end; VOID DBGStackReport( BOOL fInit) { static PBYTE pbStackTop; PBYTE pb; BYTE bDummy; if (fInit) { /* * The address of one of this functions local variables is * taken and considered the "top" of the stack. This means * that it will work best when it is called first thing in * the program. */ pbStackTop = pb = &bDummy; /* * Fill the stack up. */ while (pb > &end) *pb-- = STACKSIG; } else { /* * Start at the bottom of the stack and search upwards. */ pb = &end; while (*(++pb) == STACKSIG && pb < pbStackTop) ; /* * Display the results. */ DBGprintf("ImagEdit stack used: %d bytes.", pbStackTop - pb); } } #endif #ifdef DBG /**************************************************************************** * DBGBltImage * * This debugging function blits out the given image in the specified * DC to the screen. Every time that it is called, it will blit the * image to the right of the last one, starting at the top of the * screen. It assumes that each image is 32x32 pixels. * * Arguments: * HDC hdc - The DC with the image to blit. If this is NULL, the * current XOR and AND images are blit'd, with the AND * image below the XOR image. * * History: * 16-Sep-1991 - Created ****************************************************************************/ VOID DBGBltImage( HDC hdc) { static INT x; HDC hdcScreen; hdcScreen = GetDC(NULL); if (hdc) { BitBlt(hdcScreen, x, 0, 32, 32, hdc, 0, 0, SRCCOPY); } else { BitBlt(hdcScreen, x, 0, 32, 32, ghdcImage, 0, 0, SRCCOPY); BitBlt(hdcScreen, x, 32 + 1, 32, 32, ghdcANDMask, 0, 0, SRCCOPY); } ReleaseDC(NULL, hdcScreen); x += 32 + 1; } /**************************************************************************** * DBGprintf * * This debugging function prints out a string to the debug output. * An optional set of substitutional parameters can be specified, * and the final output will be the processed result of these combined * with the format string, just like printf. A newline is always * output after every call to this function. * * Arguments: * PSTR fmt - Format string (printf style). * ... - Variable number of arguments. * * History: * 28-Aug-1990 - Created ****************************************************************************/ VOID DBGprintf(PSTR fmt, ...) { va_list marker; CHAR szBuf[CCHTEXTMAX]; va_start(marker, fmt); vsprintf(szBuf, fmt, marker); va_end(marker); OutputDebugString(szBuf); OutputDebugString("\r\n"); } #endif