DEBUG2.C

/************************************************************************* 
**
** OLE 2 Sample Code
**
** debug2.c
**
** This file contains various debug / subclass routines for the
** ABOUT dialog
**
** (c) Copyright Microsoft Corp. 1992 - 1996 All Rights Reserved
**
*************************************************************************/

#include "outline.h"
#include <stdlib.h>
#include <time.h>

extern LPOUTLINEAPP g_lpApp;

LONG CALLBACK EXPORT DebugAbout(HWND hWnd, unsigned uMsg, WORD wParam, LONG lParam);
void RandomizeStars(HDC hDC);
BOOL InitStrings(void);
BOOL DrawString(int iCount, HDC hDC, LPRECT rcDrawIn);

static FARPROC lpRealAboutProc = 0L;
static int width, height;
static RECT rc;
static HANDLE hStrBlock = NULL;
static LPSTR lpStrings = NULL;
static WORD wLineHeight;


/* TraceDebug
* ----------
*
* Called once when our About Box's gets the INITDIALOG message. Subclasses
* dialog.
*/

void TraceDebug(HWND hDlg, int iControl)
{

// Load strings, if the strings aren't there, then don't subclass
// the dialog
if (InitStrings() != TRUE)
return;

// Subclass the dialog
lpRealAboutProc = (FARPROC)(LONG)GetWindowLong(hDlg, GWL_WNDPROC);
SetWindowLong(hDlg, GWL_WNDPROC, (LONG)(FARPROC)DebugAbout);

// Get rect of control in screen coords, and translate to our dialog
// box's coordinates
GetWindowRect(GetDlgItem(hDlg, iControl), &rc);
MapWindowPoints(NULL, hDlg, (LPPOINT)&rc, 2);

width = rc.right - rc.left;
height = rc.bottom - rc.top;
}

/* DebugAbout
* ----------
*
* The subclassed About dialog's main window proc.
*/

LONG CALLBACK EXPORT DebugAbout(HWND hWnd, unsigned uMsg, WORD wParam, LONG lParam)
{
RECT rcOut;
static BOOL bTimerStarted = FALSE;
static int iTopLocation;
HDC hDCScr;
static HDC hDCMem;
static HBITMAP hBitmap;
static HBITMAP hBitmapOld;
static RECT rcMem;
static HFONT hFont;

switch (uMsg)
{

/*
* If we get a LBUTTONDBLCLICK in the upper left of
* the dialog, fire off the about box effects
*/

case WM_LBUTTONDBLCLK:
if ((wParam & MK_CONTROL) && (wParam & MK_SHIFT)
&& LOWORD(lParam) < 10 && HIWORD(lParam) < 10 &&
bTimerStarted == FALSE)
{
if (SetTimer ( hWnd, 1, 10, NULL ))
{
LOGFONT lf;
int i;

bTimerStarted = TRUE;

// "Open up" the window
hDCScr = GetDC ( hWnd );
hDCMem = CreateCompatibleDC ( hDCScr );

hBitmap = CreateCompatibleBitmap(hDCScr, width, height);
hBitmapOld = SelectObject(hDCMem, hBitmap);

// Blt from dialog to memDC
BitBlt(hDCMem, 0, 0, width, height,
hDCScr, rc.left, rc.top, SRCCOPY);

for (i=0;i<height;i+=1)
{
BitBlt(hDCScr, rc.left, rc.top + i + 1, width, height-i-1, hDCMem, 0, 0, SRCCOPY);
PatBlt(hDCScr, rc.left, rc.top + i, width, 1, BLACKNESS);
}

SelectObject(hDCMem, hBitmapOld);
DeleteObject(hBitmap);

// Set up memory DC with default attributes
hBitmap = CreateCompatibleBitmap(hDCScr, width, height);
ReleaseDC(hWnd, hDCScr);

hBitmapOld = SelectObject(hDCMem, hBitmap);

SetBkMode(hDCMem, TRANSPARENT);
SetBkColor(hDCMem, RGB(0,0,0));

// Create font
memset(&lf, 0, sizeof(LOGFONT));
lf.lfHeight = -(height / 7); // Fit 7 lines of text in box
lf.lfWeight = FW_BOLD;
strcpy(lf.lfFaceName, "Arial");
hFont = CreateFontIndirect(&lf);

// If we can't create the font, revert and use the standard
// system font.
if (!hFont)
GetObject(GetStockObject(SYSTEM_FONT), sizeof(LOGFONT), &lf);

wLineHeight = abs(lf.lfHeight) + 5; // 5 pixels between lines

// Set location of top of banner at bottom of the window
iTopLocation = height + 50;

SetRect(&rcMem, 0, 0, width, height);
}
}
// Call our real window procedure in case they want to
// handle LBUTTONDOWN messages also
goto Default;

case WM_TIMER:
{
int iCount;
HFONT hfold;

/*
* On each timer message, we are going to construct the next image
* in the animation sequence, then bitblt this to our dialog.
*/

// Clear out old bitmap and place random star image on background
PatBlt(hDCMem, rcMem.left, rcMem.top, rcMem.right, rcMem.bottom, BLACKNESS);
RandomizeStars(hDCMem);

// Set initial location to draw text
rcOut = rcMem;
rcOut.top = 0 + iTopLocation;
rcOut.bottom = rcOut.top + wLineHeight;

iCount = 0;
if (hFont) hfold = SelectObject(hDCMem, hFont);

SetTextColor(hDCMem, RGB(0,255,0));
while (DrawString(iCount, hDCMem, &rcOut) == TRUE)
{
rcOut.top += wLineHeight;
rcOut.bottom += wLineHeight;
iCount++;
}
if (hFont) SelectObject(hDCMem, hfold);

// Now blt the memory dc that we have just constructed
// to the screen
hDCScr = GetDC(hWnd);
BitBlt(hDCScr, rc.left, rc.top, rc.right, rc.bottom,
hDCMem, 0, 0, SRCCOPY);
ReleaseDC(hWnd, hDCScr);

// For the next animation sequence, we want to move the
// whole thing up, so decrement the location of the top
// of the banner

iTopLocation -= 2;

// If we've gone through the banner once, reset it
if (iTopLocation < -(int)(wLineHeight * iCount))
iTopLocation = height + 50;
}
// Goto default
goto Default;

case WM_NCDESTROY:
{
LONG defReturn;

/*
* We're being destroyed. Clean up what we created.
*/

if (bTimerStarted)
{
KillTimer(hWnd, 1);
SelectObject (hDCMem, hBitmapOld);
DeleteObject (hBitmap);
DeleteDC (hDCMem);
if (hFont) DeleteObject(hFont);
bTimerStarted = FALSE;
}

if (lpStrings)
UnlockResource(hStrBlock), lpStrings = NULL;
if (hStrBlock)
FreeResource(hStrBlock), hStrBlock = NULL;

// Pass the NCDESTROY on to our real window procedure. Since
// this is the last message that we are going to be getting,
// we can go ahead and free the proc instance here.

defReturn = CallWindowProc((WNDPROC)lpRealAboutProc, hWnd,
uMsg, wParam, lParam);
return defReturn;
}

Default:
default:
return CallWindowProc(
(WNDPROC)lpRealAboutProc, hWnd, uMsg, wParam, lParam);
}
return 0L;
}


/* RandomizeStars
* --------------
*
* Paints random stars on the specified hDC
*
*/

void RandomizeStars(HDC hDC)
{
int i;

// Seed the random number generator with current time. This will,
// in effect, only change the seed every second, so our
// starfield will change only every second.
srand((unsigned)time(NULL));

// Generate random white stars
for (i=0;i<20;i++)
PatBlt(hDC, getrandom(0,width), getrandom(0,height), 2, 2, WHITENESS);
}

/* InitStrings
* --------------
*
* Reads strings from stringtable. Returns TRUE if it worked OK.
*
*/

BOOL InitStrings()
{
HRSRC hResStrings;
LPSTR lpWalk;

// Load the block of strings
if ((hResStrings = FindResource(
g_lpApp->m_hInst,
MAKEINTRESOURCE(9999),
RT_RCDATA)) == NULL)
return FALSE;
if ((hStrBlock = LoadResource(g_lpApp->m_hInst, hResStrings)) == NULL)
return FALSE;
if ((lpStrings = LockResource(hStrBlock)) == NULL)
return FALSE;

if (lpStrings && *(lpStrings+2)!=0x45)
{
lpWalk = lpStrings;
while (*(UNALIGNED WORD *)lpWalk != (WORD)0x0000)
{
if (*lpWalk != (char)0x00)
*((UNALIGNED WORD *)lpWalk) ^= 0x98;
lpWalk++;
}
}
return TRUE;
}

/* DrawString
* ----------
*
* Draws the next string on the specified hDC using the
* output rectangle. If iCount == 0, reset to start of list.
*
* Returns: TRUE to contine, FALSE if we're done
*/

BOOL DrawString(int iCount, HDC hDC, LPRECT rcDrawIn)
{
static LPSTR lpPtr = NULL;

if (iCount == 0)
// First time, reset pointer
lpPtr = lpStrings;

if (*lpPtr == '\0') // If we've hit a NULL string, we're done
return FALSE;

// If we're drawing outside of visible box, don't call DrawText
if ((rcDrawIn->bottom > 0) && (rcDrawIn->top < height))
DrawText(hDC, lpPtr, -1, rcDrawIn, DT_CENTER);

// Advance pointer to next string
lpPtr += lstrlen(lpPtr) + 1;

return TRUE;
}