WINPROC.CPP

/* 
**-----------------------------------------------------------------------------
** File: WinProc.cpp
** Purpose: A sample windows proc for supporting D3D.
** Notes:
**
** Copyright (c) 1995 - 1997 by Microsoft, all rights reserved.
**-----------------------------------------------------------------------------
*/

/*
**-----------------------------------------------------------------------------
**Include Files
**-----------------------------------------------------------------------------
*/

#include "WinProc.h"
#include "WinMain.h"
#include "Debug.h"

/*
**-----------------------------------------------------------------------------
**Local Typedefs
**-----------------------------------------------------------------------------
*/

typedef struct tagChangeDDInfo {
DDDrvInfo * lpDrvOrig;// Original Driver
DDDrvInfo * lpDrvNew;// New Driver (user choice)

D3DDevInfo * lpDevOrig;// Original D3D device
D3DDevInfo * lpDevNew;// New D3D device (user choice)

DDModeInfo * lpModeOrig;// Orignal Mode
DDModeInfo * lpModeNew;// New Mode (user choice)
} ChangeDDInfo;
typedef ChangeDDInfo * LPChangeDDInfo;


/*
**-----------------------------------------------------------------------------
**Local Variables
**-----------------------------------------------------------------------------
*/

BOOL g_fMinimized = FALSE;
BOOL g_fMaximized = FALSE;



/*
**-----------------------------------------------------------------------------
**Local function prototypes
**-----------------------------------------------------------------------------
*/

// About Message proc
BOOL FAR PASCAL AboutBoxProc (HWND hWnd, UINT uiMsg,
WPARAM wParam, LPARAM lParam);

// Change Dialog
BOOL DlgDriversInit (HWND hDlg);
BOOL DlgDevicesInit (HWND hDlg);
BOOL DlgModesInit (HWND hDlg);

int _cdecl CompareModes (const void* element1, const void* element2);

LPDDDrvInfo DlgGetDriver (HWND hDlg);
LPD3DDevInfo DlgGetDevice (HWND hDlg);
LPDDModeInfo DlgGetMode (HWND hDlg);

BOOL FAR PASCAL ChangeDriverProc (HWND hWnd, UINT uiMsg,
WPARAM wParam, LPARAM lParam);
void OnChangeDriver (HWND hWindow, int idDialog);



/*
**-----------------------------------------------------------------------------
**Functions
**-----------------------------------------------------------------------------
*/

/*
**-----------------------------------------------------------------------------
** Name: D3DWindowProc
** Purpose: handles windows messages for D3DWindow's
**-----------------------------------------------------------------------------
*/

LRESULT CALLBACK D3DWindowProc (
HWND hWindow,
UINT uiMsg,
WPARAM wParam,
LPARAM lParam)
{
LONG lResult;

//
// Windows messages
//
switch (uiMsg)
{
case WM_ACTIVATE:
return OnActivate (hWindow, wParam, lParam);

case WM_ACTIVATEAPP:
return OnActivateApp (hWindow, wParam, lParam);

case WM_CLOSE:
return OnClose (hWindow);

case WM_COMMAND:
return OnCommand (hWindow, wParam, lParam);

case WM_CREATE:
return OnCreate (hWindow);

case WM_DESTROY:
return OnDestroy (hWindow);

case WM_DISPLAYCHANGE:
return OnDisplayChange (hWindow);

case WM_ERASEBKGND:
return OnEraseBackground (hWindow, wParam, lParam);

case WM_ENTERMENULOOP:
return OnEnterMenuLoop (hWindow, wParam, lParam);

case WM_EXITMENULOOP:
return OnExitMenuLoop (hWindow, wParam, lParam);

case WM_GETMINMAXINFO:
return OnGetMinMaxInfo (hWindow, wParam, lParam);

case WM_MOVE:
return OnMove (hWindow, wParam, lParam);

case WM_NCPAINT:
return OnNCPaint (hWindow, wParam, lParam);

case WM_PAINT:
{
HDC hdc;
PAINTSTRUCT ps;

hdc = BeginPaint (hWindow, &ps);
lResult = OnPaint (hWindow, hdc, &ps);
EndPaint (hWindow, &ps);
}
return lResult;

case WM_PALETTECHANGED:
// Note: We need to support this
break;

case WM_QUERYNEWPALETTE:
// Note: We need to support this
break;

case WM_SETCURSOR:
return OnSetCursor (hWindow, wParam, lParam);

case WM_SIZE:
return OnSize (hWindow, wParam, lParam);

case WM_SYSCOMMAND:
return OnSysCommand (hWindow, wParam, lParam);

case WM_WINDOWPOSCHANGING:
return OnWindowPosChanging (hWindow, wParam, lParam);

//
// D3D Window Query/Notification messages
//
case D3DWIN_GET_VALID: // Get valid size
{
LPD3DWindow lpd3dWindow;

//Get D3DWindow pointer
lpd3dWindow = (LPD3DWindow)GetWindowLong (hWindow, GWL_USERDATA);
if (! lpd3dWindow)
return FALSE;
return lpd3dWindow->isValid();
}

case D3DWIN_GET_POINTER:
//Get D3DWindow pointer
return (LRESULT)GetWindowLong (hWindow, GWL_USERDATA);

case D3DWIN_GET_SURFACE:
{
LPD3DWindow lpd3dWindow;

//Get D3DWindow pointer
lpd3dWindow = (LPD3DWindow)(void *)GetWindowLong (hWindow, GWL_USERDATA);
if (! lpd3dWindow)
return NULL;
return (LPARAM)(lpd3dWindow->GetRender ());
}

case D3DWIN_INIT:
return OnD3DInit (hWindow, (LPD3DWindow) lParam);

case D3DWIN_FINI:
return OnD3DFini (hWindow, (LPD3DWindow) lParam);

case D3DWIN_CHANGED_DRIVER:
return OnD3DChangeDriver (hWindow);

case D3DWIN_CHANGED_MODE:
return OnD3DChangeMode (hWindow);

case D3DWIN_CHANGED_DEVICE:
return OnD3DChangeDevice (hWindow);

} // End Switch

// Do Default window behavior
return DefWindowProc (hWindow, uiMsg, wParam, lParam);
} // End D3DWindowProc



/*
**-----------------------------------------------------------------------------
** Name: AboutBoxProc
** Purpose: handles messages for About Dialog box
**-----------------------------------------------------------------------------
*/
BOOL
FAR PASCAL AboutBoxProc (HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
switch (uiMsg)
{
case WM_COMMAND:
if (LOWORD(wParam) == IDOK)
EndDialog (hWnd, TRUE);
break;

case WM_INITDIALOG:
return TRUE;
}
return FALSE;
} // End AboutBoxProc



/*
**-----------------------------------------------------------------------------
** Name: OnAbout
** Purpose: Display About Dialog
**-----------------------------------------------------------------------------
*/

LRESULT OnAbout (HWND hWindow)
{
HINSTANCE hInstance;

if ((! hWindow) || (! IsWindow (hWindow)))
return 0L;

hInstance = (HINSTANCE) GetWindowLong (hWindow, GWL_HINSTANCE);
if (! hInstance)
return 0L;

// Pause App
OnPause (hWindow, TRUE);

// Do About Dialog here
DialogBox (hInstance, MAKEINTRESOURCE (IDD_ABOUT), hWindow, (DLGPROC)AboutBoxProc);

// UnPause app
OnPause (hWindow, FALSE);

return 0L;
} // End OnAbout



/*
**-----------------------------------------------------------------------------
** Name: OnActivate
** Purpose: handles WM_ACTIVATE message
**-----------------------------------------------------------------------------
*/

LRESULT OnActivate (HWND hWindow, WPARAM wParam, LPARAM lParam)
{
BOOL fActive= (BOOL) LOWORD(wParam); // activation flag
BOOL fMinimized= (BOOL) HIWORD(wParam); // minimized flag
HWND hwndPrevious= (HWND) lParam; // window handl

// Do Default Behavior
return DefWindowProc (hWindow, WM_ACTIVATE, wParam, lParam);
} // End OnActivate



/*
**-----------------------------------------------------------------------------
** Name: OnActivateApp
** Purpose: handles WM_ACTIVATEAPP message
**-----------------------------------------------------------------------------
*/

LRESULT OnActivateApp (HWND hWindow, WPARAM wParam, LPARAM lParam)
{
BOOLfActive= (BOOL) wParam;// Activate or deactivate
DWORDdwThreadID= (DWORD) lParam;// thread identifier

// Get D3D Window pointer
LPD3DWindow lpd3dWindow = (LPD3DWindow)GetWindowLong (hWindow, GWL_USERDATA);

if (fActive)
{
// Reactivating - Realize current palette
if (lpd3dWindow)
{
lpd3dWindow->turnActiveOn ();
lpd3dWindow->Restore ();
lpd3dWindow->RealizePalette ();
}
}
else
{
//
// If we have been deactivated invalidate
// to show the paused display.
//
if (lpd3dWindow)
{
lpd3dWindow->turnActiveOff ();
InvalidateRect (hWindow, NULL, FALSE);
}

}

// Do default behavior
return DefWindowProc (hWindow, WM_ACTIVATEAPP, wParam, lParam);
} // End OnActivateApp



/*
**-----------------------------------------------------------------------------
** Name: OnClose
** Purpose: handles WM_CLOSE message
**-----------------------------------------------------------------------------
*/

LRESULT OnClose (HWND hWindow)
{
// Close down window
DestroyWindow (hWindow);
return 0L;
} // End OnClose



/*
**-----------------------------------------------------------------------------
** Name: OnCommand
** Purpose: handles WM_COMMAND messages
**-----------------------------------------------------------------------------
*/

LRESULT OnCommand (HWND hWindow, WPARAM wParam, LPARAM lParam)
{
HWND hControl= (HWND)lParam;
DWORD dwNotify= (DWORD)HIWORD(wParam);
DWORD dwID = (DWORD)LOWORD(wParam);

if (hControl)
{
//
// Handle messages from controls here
//
}
else
{
//
// Handle Menu messages here
//
switch (dwID)
{
case IDM_EXIT:
// Close down app
SendMessage (hWindow, WM_CLOSE, 0, 0);
return 0;

case IDM_ABOUT:
// Bring up the "About" dialog
OnAbout (hWindow);
break;

case IDM_CHANGE_DRIVERS:
// Bring up the "Change Driver" dialog
OnChangeDriver (hWindow, IDD_CHANGE_DRIVER);
break;

case IDM_CHANGE_DEVICES:
// Bring up the "Change Device" dialog
OnChangeDriver (hWindow, IDD_CHANGE_DEVICE);
break;

case IDM_CHANGE_MODES:
// Bring up the "Change Mode" dialog
OnChangeDriver (hWindow, IDD_CHANGE_MODE);
break;

default:
// Unknown Menu Command
break;
}
}

// Let Default Window Proc handle it for us.
return DefWindowProc (hWindow, WM_COMMAND, wParam, lParam);
} // End OnCommand



/*
**-----------------------------------------------------------------------------
** Name: OnCreate
** Purpose: Handles WM_CREATE message
**-----------------------------------------------------------------------------
*/

LRESULT OnCreate (HWND hWindow)
{
// Success
return 0L;
} // End OnCreate



/*
**-----------------------------------------------------------------------------
** Name: OnDestroy
** Purpose: Handles WM_DESTROY message
**-----------------------------------------------------------------------------
*/

LRESULT OnDestroy (HWND hWindow)
{
LPD3DWindow lpd3dWindow;

//Delete associated D3DWindow from this window
lpd3dWindow = (LPD3DWindow)GetWindowLong (hWindow, 0L);
if (lpd3dWindow)
lpd3dWindow->Fini ();
SetWindowLong (hWindow, GWL_USERDATA, 0L);

// Tell windows to QUIT!
PostQuitMessage (0);
return 0L;
} // End OnDestroy



/*
**-----------------------------------------------------------------------------
** Name: OnDisplayChange
** Purpose: Handles WM_DISPLAYCHANGE message
** Notes:This means the desktop mode has changed underneath us
**-----------------------------------------------------------------------------
*/

LRESULT OnDisplayChange (HWND hWindow)
{
HRESULThResult;
LPD3DWindow lpd3dWindow;

// Get D3D window pointer
lpd3dWindow = (LPD3DWindow)GetWindowLong (hWindow, GWL_USERDATA);
if (! lpd3dWindow)
return 0L;

// Change Primary surface to new desktop
hResult = lpd3dWindow->ChangeDesktop ();
if (FAILED (hResult))
return 0L;

// Success
return 0L;
} // End OnDestroy



/*
**-----------------------------------------------------------------------------
** Name: OnEraseBackground
** Purpose: Handles WM_ERASEBKGND message
**-----------------------------------------------------------------------------
*/

LRESULT OnEraseBackground (HWND hWindow, WPARAM wParam, LPARAM lParam)
{
LPD3DWindow lpd3dWindow;

// Get D3D window pointer
lpd3dWindow = (LPD3DWindow)GetWindowLong (hWindow, GWL_USERDATA);
if ((lpd3dWindow) &&
(lpd3dWindow->isValid ()) &&
(lpd3dWindow->isActive ()) &&
(! lpd3dWindow->isPaused ()))
{
// Tell system we erased background, even though we didn't
// It will soon get covered up by a frame from RenderScene
return 1L;
}

// Do the Default behavior (erase the background)
return DefWindowProc (hWindow, WM_ERASEBKGND, wParam, lParam);
} // End OnEraseBackground



/*
**-----------------------------------------------------------------------------
** Name: OnEnterMenuLoop
** Purpose: Handles WM_ENTERMENULOOP messages
**-----------------------------------------------------------------------------
*/

LRESULT OnEnterMenuLoop (HWND hWindow, WPARAM wParam, LPARAM lParam)
{
LPD3DWindow lpd3dWindow;

// Get D3D window pointer
lpd3dWindow = (LPD3DWindow)GetWindowLong (hWindow, GWL_USERDATA);
if ((lpd3dWindow) && (lpd3dWindow->isValid ()))
{
// pause app (go into GDI drawing mode)
lpd3dWindow->Pause (TRUE);

// Restore cursor
SetCursor (g_hMainCursor);
}

// Do the Default behavior
return DefWindowProc (hWindow, WM_ENTERMENULOOP, wParam, lParam);
} // End OnEnterMenuLoop



/*
**-----------------------------------------------------------------------------
** Name: OnExitMenuLoop
** Purpose: Handles WM_EXITMENULOOP messages
**-----------------------------------------------------------------------------
*/

LRESULT OnExitMenuLoop (HWND hWindow, WPARAM wParam, LPARAM lParam)
{
LPD3DWindow lpd3dWindow;

// Get D3D window pointer
lpd3dWindow = (LPD3DWindow)GetWindowLong (hWindow, GWL_USERDATA);
if ((lpd3dWindow) && (lpd3dWindow->isValid ()))
{
// Get Rid of cursor again
SetCursor (NULL);

// Unpause app (return from GDI drawing)
lpd3dWindow->Pause (FALSE);
}

// Do the Default behavior
return DefWindowProc (hWindow, WM_EXITMENULOOP, wParam, lParam);
} // End OnExitMenuLoop



/*
**-----------------------------------------------------------------------------
** Name: OnGetMinMaxInfo
** Purpose: Handles WM_GETMINMAXINFO message
**-----------------------------------------------------------------------------
*/

LRESULT OnGetMinMaxInfo (HWND hWindow, WPARAM wParam, LPARAM lParam)
{
LPMINMAXINFOlpmmi;
LPD3DWindowlpd3dWindow;
RECTrSurf;
DWORDdwWidth;
DWORDdwHeight;

lpmmi = (LPMINMAXINFO)lParam;

// Get D3D window pointer
lpd3dWindow = (LPD3DWindow)GetWindowLong (hWindow, GWL_USERDATA);
if ((lpd3dWindow) &&
(lpd3dWindow->isFullscreen ()) &&
(! g_fMinimized))
{
// Get Width and height of current surface
lpd3dWindow->GetSurfaceRect (rSurf);

dwWidth = abs (rSurf.right - rSurf.left);
dwHeight = abs (rSurf.bottom - rSurf.top);

// Prevent changes in size
lpmmi->ptMaxTrackSize.x = dwWidth;
lpmmi->ptMaxTrackSize.y = dwHeight;
lpmmi->ptMinTrackSize.x = dwWidth;
lpmmi->ptMinTrackSize.y = dwHeight;

return 0L;
}

return DefWindowProc (hWindow, WM_GETMINMAXINFO, wParam, lParam);
} // End OnGetMinMaxInfo



/*
**-----------------------------------------------------------------------------
** Name: OnIdle
** Purpose: Animate while system is idle
**-----------------------------------------------------------------------------
*/

void OnIdle (HWND hWindow)
{
HRESULT hResult;
LPD3DWindow lpd3dWindow;

// Get D3D window pointer
lpd3dWindow = (LPD3DWindow)GetWindowLong (hWindow, GWL_USERDATA);
if (! lpd3dWindow)
return;

//
// Only animate if we are the foreground app, we aren't suspended
// and we have completed initialization and we aren't minimized
//
if ((! lpd3dWindow->isActive ()) ||
(lpd3dWindow->isPaused ()) ||
(! lpd3dWindow->isValid ()) ||
(g_fMinimized))
return;

hResult = lpd3dWindow->DrawFrame ();
if (FAILED (hResult))
return;
} // End OnIdle



/*
**-----------------------------------------------------------------------------
** Name: OnMove
** Purpose: handles WM_MOVE message
**-----------------------------------------------------------------------------
*/

LRESULT OnMove (HWND hWindow, WPARAM wParam, LPARAM lParam)
{
// We don't support moving Full-screen windows

// Do default behavior
return DefWindowProc (hWindow, WM_MOVE, wParam, lParam);
} // End OnMove



/*
**-----------------------------------------------------------------------------
** Name: OnNCPaint
** Purpose: Handles WM_NCPaint message
**-----------------------------------------------------------------------------
*/

LRESULT OnNCPaint (HWND hWindow, WPARAM wParam, LPARAM lParam)
{
LPD3DWindow lpd3dWindow;

// Get D3D window pointer
lpd3dWindow = (LPD3DWindow)GetWindowLong (hWindow, GWL_USERDATA);
if ((lpd3dWindow) &&
(lpd3dWindow->isValid ()) &&
(lpd3dWindow->isActive ()) &&
(! lpd3dWindow->isPaused ()) &&
(! g_fMinimized))
{
// Prevent the system from drawing the NC frame
return 0L;
}

// Do the Default behavior (Draw the NC Frame)
return DefWindowProc (hWindow, WM_NCPAINT, wParam, lParam);
} // End OnNCPaint



/*
**-----------------------------------------------------------------------------
** Name: OnPaint
** Purpose:Handles WM_PAINT messages
**-----------------------------------------------------------------------------
*/

LRESULT OnPaint (HWND hWindow, HDC hdc, LPPAINTSTRUCT lpps)
{
HRESULThResult;
LPD3DWindow lpd3dWindow;

// Get D3D Window pointer
lpd3dWindow = (LPD3DWindow)GetWindowLong (hWindow, GWL_USERDATA);

if (lpd3dWindow &&
lpd3dWindow->isActive () &&
!lpd3dWindow->isPaused () &&
lpd3dWindow->isValid() &&
! g_fMinimized)
{
//
// NOTE: DrawFrame() re-renders the scene as well as blitting the
// result to the primary. As all we really want to do here is
// repaint the client area we don't really need to re-render -
// just re-blit. For this simple sample this inefficiency
// doesn't matter but for real applications not re-rendering
// may be a useful optimization.
//
hResult = lpd3dWindow->DrawFrame ();
if (FAILED (hResult))
return 0L;
}
else
{
//
// Show the suspended image if the D3Dwinow is not yet created,
// created, the window is inactive, or paused.
//
PaintPaused (hWindow, hdc);
}

return 0L;
} // End OnPaint



/*
**-----------------------------------------------------------------------------
** Name:OnPause
** Purpose:Pause/Unpause app
**-----------------------------------------------------------------------------
*/

void OnPause (HWND hWindow, BOOL fPause)
{
LPD3DWindow lpd3dWindow;

// Get D3D Window pointer
lpd3dWindow = (LPD3DWindow)GetWindowLong (hWindow, GWL_USERDATA);
if (! lpd3dWindow)
return;

lpd3dWindow->Pause (fPause);
} // End OnPause



/*
**-----------------------------------------------------------------------------
** Name: OnSetCursor
** Purpose:Handles WM_SETCURSOR messages
**-----------------------------------------------------------------------------
*/

LRESULT OnSetCursor (HWND hWindow, WPARAM wParam, LPARAM lParam)
{
LPD3DWindow lpd3dWindow;

// Get D3D window pointer
lpd3dWindow = (LPD3DWindow)GetWindowLong (hWindow, GWL_USERDATA);

// Don't show cursor while in fullscreen
if ((lpd3dWindow) && (lpd3dWindow->isFullscreen ()))
{
if ((lpd3dWindow->isPaused ()) ||
(! lpd3dWindow->isActive ()))
{
// Restore cursor
SetCursor (g_hMainCursor);
}
else
{
// Get rid of cursor
SetCursor (NULL);
}
return TRUE;
}

// Do Default behavior
return DefWindowProc (hWindow, WM_SETCURSOR, wParam, lParam);
} // End OnSetCursor



/*
**-----------------------------------------------------------------------------
** Name: OnSize
** Purpose:Handles WM_SIZE messages
**-----------------------------------------------------------------------------
*/

LRESULT OnSize (HWND hWindow, WPARAM wParam, LPARAM lParam)
{
DWORDfwSizeType= (DWORD)wParam;
LPD3DWindowlpd3dWindow = (LPD3DWindow)GetWindowLong (hWindow, GWL_USERDATA);

switch (fwSizeType)
{
case SIZE_MAXHIDE:
// Message is sent to all pop-up windows when some other window is maximized.
break;

case SIZE_MAXIMIZED:
// Window has been maximized.
g_fMaximized = TRUE;
g_fMinimized = FALSE;
break;

case SIZE_MAXSHOW:
// Message is sent to all pop-up windows when some other window has been restored to its former size.
break;

case SIZE_MINIMIZED:
// Window has been minimized.
g_fMinimized = TRUE;
g_fMaximized = FALSE;
break;

case SIZE_RESTORED:
// Window has been resized but neither minimized nor maximized
if (g_fMinimized)
{
// Restore surfaces
if (lpd3dWindow)
lpd3dWindow->Restore ();

g_fMaximized = FALSE;
g_fMinimized = FALSE;
}
return 0L;
}

// Do Default Behavior
return DefWindowProc (hWindow, WM_SIZE, wParam, lParam);
} // End OnSize




/*
**-----------------------------------------------------------------------------
** Name: OnSysCommand
** Purpose:Handles WM_SYSCOMMAND messages
**-----------------------------------------------------------------------------
*/

LRESULT OnSysCommand (HWND hWindow, WPARAM wParam, LPARAM lParam)
{
// Get D3D window pointer
LPD3DWindowlpd3dWindow = (LPD3DWindow)GetWindowLong (hWindow, GWL_USERDATA);
DWORDuCmdType = wParam; // Type of system command requested
intxPos = LOWORD(lParam); // horizontal postion, in screen coordinates
intyPos = HIWORD(lParam); // vertical postion, in screen coordinates

switch (uCmdType)
{
case SC_MAXIMIZE:
// Maximizes the window.
g_fMaximized = TRUE;
g_fMinimized = FALSE;

// Not supported
return 0L;

case SC_MINIMIZE:
// Minimizes the window.
g_fMinimized = TRUE;
g_fMaximized = FALSE;
break;

case SC_MOVE:
// Moves the window

// Not supported
return 0L;

case SC_RESTORE:
//Restores the window to its normal position and size.
if (g_fMinimized)
{
// Restore app
if (lpd3dWindow)
lpd3dWindow->Restore ();
}

g_fMinimized = FALSE;
g_fMaximized = FALSE;
break;

case SC_SCREENSAVE:
// Executes the screen saver application specified in the [boot] section of the SYSTEM.INI file.
break;

case SC_SIZE:
// Sizes the window.

// Not supported
return 0L;
}

// Do Default Behavior
return DefWindowProc (hWindow, WM_SYSCOMMAND, wParam, lParam);
} // End OnSysCommand



/*
**-----------------------------------------------------------------------------
** Name: OnWindowPosChanging
** Purpose: handles WM_WINDOWPOSCHANGING message
** Notes:
**
**1. This is where we protect ourselves against unwanted moving
** and resizing of the window. (We are fullscreen after all)
**
** 2. First gotcha: Changing the Display mode causes the window
** to change size and we want to let that happen. So we will
** compare the current window size to the current surface size.
** If they don't match we will resize the window to match the surface.
**
** 3. Second gotcha. DirectDraw hooks the window procedure and on
** a deactivate app call trys to minimize the window on our behalf.
** We should allow this to happen!!!
** It can do this by either calling ShowWindow or SetWindowPos
**
**-----------------------------------------------------------------------------
*/

LRESULT OnWindowPosChanging (HWND hWindow, WPARAM wParam, LPARAM lParam)
{
// We don't support moving Full-screen windows
// Get D3D Window pointer
LPD3DWindow lpd3dWindow = (LPD3DWindow)GetWindowLong (hWindow, GWL_USERDATA);
if (lpd3dWindow &&
(lpd3dWindow->isFullscreen ()) &&
(! g_fMinimized))
{
LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;

if (lpwp)
{
// Let minimize commands fall through
// Check for minimize by seeing if window is iconic
// this state should already be set by the time
// we get this window message
if (IsIconic (hWindow))
{
// Looks like we are getting minimized
g_fMinimized = TRUE;
}
else
{
RECTrWin, rSurf;
DWORDdwWinW, dwWinH;
DWORDdwSurfW, dwSurfH;

GetWindowRect (hWindow, &rWin);
dwWinW = abs (rWin.right - rWin.left);
dwWinH = abs (rWin.bottom - rWin.top);

lpd3dWindow->GetSurfaceRect (rSurf);
dwSurfW = abs (rSurf.right - rSurf.left);
dwSurfH = abs (rSurf.bottom - rSurf.top);

// Make sure the surface is some reasonable size
if (dwSurfW < 320)
dwSurfW = 320;
if (dwSurfH < 200)
dwSurfH = 200;

// Is our window the same size as our surface ?!?
if ((dwSurfW != dwWinW) || (dwSurfH != dwWinH))
{
// No, then resize it
lpwp->x = rSurf.left;
lpwp->y = rSurf.top;
lpwp->cx = dwSurfW;
lpwp->cy = dwSurfH;

// Force resize
lpwp->flags &= ~(SWP_NOMOVE | SWP_NOSIZE);
}
else
{
// Prevent resizing and moving
lpwp->flags |= (SWP_NOMOVE | SWP_NOSIZE);
}

// Fall through to default window proc
}
}
}

// Do Default Behavior
return DefWindowProc (hWindow, WM_WINDOWPOSCHANGING, wParam, lParam);
} // End OnWindowPosChanging



/*
**-----------------------------------------------------------------------------
** Name: OnD3DInit
** Purpose:Notification that associated D3D Window object
**has successfully initialized
**-----------------------------------------------------------------------------
*/

LRESULT OnD3DInit (HWND hWindow, LPD3DWindow lpd3dWindow)
{
if ((! lpd3dWindow) || (! lpd3dWindow->isValid ()))
{
// Error, something went wrong
return 0L;
}

// Save the pointer to the D3D Window object
SetWindowLong (hWindow, GWL_USERDATA, (long)(void *)lpd3dWindow);

// Make sure we are properly marked as active/inactive
HWND hActive = GetActiveWindow ();
if (hActive == hWindow)
lpd3dWindow->turnActiveOn ();
else
lpd3dWindow->turnActiveOff ();

// Success
return 0L;
} // End OnD3DInit



/*
**-----------------------------------------------------------------------------
** Name: OnD3DFini
** Purpose:Notification that the D3D window object
**is cleaning up.
**-----------------------------------------------------------------------------
*/

LRESULT OnD3DFini (HWND hWindow, LPD3DWindow lpd3dWindow)
{
// Set our window pointer to NULL
// so we don't attempt to misuse it later.
SetWindowLong (hWindow, GWL_USERDATA, 0L);

// Success
return 0L;
} // End OnD3DFini



/*
**-----------------------------------------------------------------------------
** Name: OnD3DChangeDriver
** Purpose:Notification that our associated D3D Window object
**has changed it's DD Driver.
** Notes:This is a good time to update our Menus
**-----------------------------------------------------------------------------
*/

LRESULT OnD3DChangeDriver (HWND hWindow)
{
// Success
return 0L;
} // End OnD3DChangeDriver




/*
**-----------------------------------------------------------------------------
** Name: OnD3DChangeMode
** Purpose:Notification that our associated D3D Window object
**has changed it's mode.
** Notes:This is a good time to update our Menus
**-----------------------------------------------------------------------------

*/ 

LRESULT OnD3DChangeMode (HWND hWindow)
{
// Success
return 0L;
} // End OnD3DChangeMode



/*
**-----------------------------------------------------------------------------
** Name: OnD3DChangeDevice
** Purpose:Notification that our associated D3D Window object
**has changed it's D3D device.
** Notes:This is a good time to update our Menus
**-----------------------------------------------------------------------------
*/

LRESULT OnD3DChangeDevice (HWND hWindow)
{
// Success
return 0L;
} // End OnD3DChangeDevice



/*
**-----------------------------------------------------------------------------
** Name: PaintPaused
** Purpose:Paint the window as Paused
** Notes:
**
** 1. We show the paused state by drawing a text string
** in the client area of the window.
**
**-----------------------------------------------------------------------------
*/

void PaintPaused (HWND hWindow, HDC hdc)
{
HPEN hOldPen;
HBRUSH hOldBrush;
COLORREF crOldTextColor;
INT oldMode;
INT x;
INT y;
SIZE size;
RECT rect;
INT nStrLen;

//
// Black background.
//
hOldPen = (HPEN)SelectObject (hdc, GetStockObject (NULL_PEN));
hOldBrush = (HBRUSH)SelectObject (hdc, GetStockObject (BLACK_BRUSH));

//
// White text.
//
oldMode = SetBkMode (hdc, TRANSPARENT);
crOldTextColor = SetTextColor (hdc, RGB(255, 255, 255));

//
GetClientRect (hWindow, &rect);

//
// Clear the client area.
//
Rectangle (hdc, rect.left, rect.top, rect.right + 1, rect.bottom + 1);

//
// Draw the string centered in the client area.
//
nStrLen = strlen (g_szPaused);
GetTextExtentPoint32 (hdc, g_szPaused, nStrLen, &size);
x = (rect.right - size.cx) / 2;
y = (rect.bottom - size.cy) / 2;
TextOut (hdc, x, y, g_szPaused, nStrLen);

// Cleanup
SetTextColor (hdc, crOldTextColor);
SetBkMode (hdc, oldMode);

SelectObject (hdc, hOldBrush);
SelectObject (hdc, hOldPen);
} // End PaintPaused




/*
**-----------------------------------------------------------------------------
**Dialog Functions
**-----------------------------------------------------------------------------
*/

/*
**-----------------------------------------------------------------------------
** Name: DlgDriversInit
** Purpose: Set up Drivers for dialog
** Notes:Shows list of current Drivers
**-----------------------------------------------------------------------------
*/

BOOL DlgDriversInit (HWND hDlg)
{
LPChangeDDInfolpChange;
LPDDDrvInfolpDriver;
LPDDDrvInfolpCurr, lpNext;
DWORDdwIndex;
LPGUIDlpGuidDD;

// Check Parameters
lpChange = (LPChangeDDInfo)(void *)GetWindowLong (hDlg, DWL_USER);
if (! lpChange)
return FALSE;

lpDriver = lpChange->lpDrvNew;

// Validate Driver
if (! lpDriver)
lpGuidDD = NULL;
else
lpGuidDD = lpDriver->GetGuid ();
lpDriver = ValidateDriver (lpGuidDD);
if (! lpDriver)
return FALSE;

// Dump Driver list to Combo Box
dwIndex = 0;
lpCurr = DDDrvMgr::g_lpDriverRoot;
while (lpCurr)
{
TCHAR szBuff[80];
DWORD dwNew;

lpNext = lpCurr->lpNext;

if (lpCurr->isPrimary ())
wsprintf (szBuff, TEXT("%s (Primary)"), lpCurr->szName);
else
wsprintf (szBuff, TEXT("%s"), lpCurr->szName);

// Add String to Combo Box
dwNew = SendDlgItemMessage (hDlg, IDC_DRIVERS, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)szBuff);

// Set up pointer to driver for this item
SendDlgItemMessage (hDlg, IDC_DRIVERS, CB_SETITEMDATA, (WPARAM)dwNew, (LPARAM)(void *)lpCurr);

// Is it the current Driver
if (lpDriver == lpCurr)
{
// Set as our current selection
SendDlgItemMessage (hDlg, IDC_DRIVERS, CB_SETCURSEL, (WPARAM)dwNew, 0L);
}

lpCurr = lpNext;
}

// Success
return TRUE;
} // End DlgDriversInit



/*
**-----------------------------------------------------------------------------
** Name: DlgDevicesInit
** Purpose: Set up Devices for dialog
** Notes:Shows list of current Devices
**-----------------------------------------------------------------------------
*/

BOOL DlgDevicesInit (HWND hDlg)
{
LPChangeDDInfolpChange;
LPDDDrvInfolpDriver;
LPD3DDevInfolpDevice;
LPD3DDevInfolpCurr, lpNext;
DWORDdwIndex;
LPGUIDlpGuidD3D;

// Check Parameters
lpChange = (LPChangeDDInfo)(void *)GetWindowLong (hDlg, DWL_USER);
if (! lpChange)
return FALSE;

lpDriver = lpChange->lpDrvNew;
if (! lpDriver)
return FALSE;

lpDevice = lpChange->lpDevNew;

// Validate Device
if (! lpDevice)
lpGuidD3D = NULL;
else
lpGuidD3D = &(lpDevice->guid);
lpDevice = ValidateDevice (lpDriver, lpGuidD3D, NULL);
if (! lpDevice)
return FALSE;

// Dump Device list to Combo Box
dwIndex = 0;
lpCurr = lpDriver->lpDeviceRoot;
while (lpCurr)
{
TCHAR szBuff[80];
DWORD dwNew;

lpNext = lpCurr->lpNext;

// Get Device String
wsprintf (szBuff, TEXT("%s"), lpCurr->szName);

// Add String to Combo Box
dwNew = SendDlgItemMessage (hDlg, IDC_DEVICES, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)szBuff);

// Set up pointer to device for this item
SendDlgItemMessage (hDlg, IDC_DEVICES, CB_SETITEMDATA, (WPARAM)dwNew, (LPARAM)(void *)lpCurr);

// Is it the current device
if (lpDevice == lpCurr)
{
// Set as our current selection
SendDlgItemMessage (hDlg, IDC_DEVICES, CB_SETCURSEL, (WPARAM)dwNew, 0L);
}

lpCurr = lpNext;
}

// Success
return TRUE;
} // End DlgDevicesInit



/*
**-----------------------------------------------------------------------------
** Name: CompareModes
** Purpose: Comparision function used with Quick sort
**to get sorted list of modes
**-----------------------------------------------------------------------------
*/

int _cdecl CompareModes (const void * element1, const void * element2)
{
LPDDModeInfo lpMode1;
LPDDModeInfo lpMode2;
DWORD w1, h1, bpp1, refresh1;
DWORD w2, h2, bpp2, refresh2;
int iCompare = 0;

lpMode1 = *((LPDDModeInfo *)element1);
lpMode2 = *((LPDDModeInfo *)element2);

// Handle Null pointers
if ((! lpMode1) && (! lpMode2))
return 0;
if ((lpMode1) && (! lpMode2))
return -1;
if ((! lpMode2) && (lpMode2))
return 1;

// Get Mode Data
lpMode1->GetMode (w1, h1, bpp1, refresh1);
lpMode2->GetMode (w2, h2, bpp2, refresh2);

// Sort first on BPP then width then height
if (bpp1 < bpp2)
iCompare = -1;
else if (bpp1 > bpp2)
iCompare = 1;
else if (w1 < w2)
iCompare = -1;
else if (w1 > w2)
iCompare = 1;
else if (h1 < h2)
iCompare = -1;
else if (h1 > h2)
iCompare = 1;

// Equality
return iCompare;
} // End CompareModes



/*
**-----------------------------------------------------------------------------
** Name: DlgModesInit
** Purpose: Set up Modes for dialog
** Notes:Shows list of current modes, compatible with the current
**device. This list is displayed in sorted order (bpp, w, h)
**-----------------------------------------------------------------------------
*/

BOOL DlgModesInit (HWND hDlg)
{
LPChangeDDInfolpChange;
LPDDDrvInfolpDriver;
LPD3DDevInfolpDevice;
LPDDModeInfolpModeCurr, lpModeRoot, lpCurr, lpNext;
DWORDcModes;
DWORDcbSize;
DWORDdwIndex;
LPDDModeInfo *lpModes;

// Check Parameters
lpChange = (LPChangeDDInfo)(void *)GetWindowLong (hDlg, DWL_USER);
if (! lpChange)
return FALSE;

lpDriver = lpChange->lpDrvNew;
lpDevice = lpChange->lpDevNew;
lpModeCurr = lpChange->lpModeNew;

if (! lpDriver)
return FALSE;

if (! lpDevice)
{
lpDevice = ValidateDevice (lpDriver, NULL, NULL);
if (! lpDevice)
return FALSE;
}

lpModeRoot = lpDriver->lpModeRoot;
if (! lpModeRoot)
return FALSE;

cModes = lpDriver->countModes ();
if (! cModes)
return FALSE;

if (! lpModeCurr)
{
lpModeCurr = ValidateMode (lpDriver, 640, 480, 16, 0, lpDevice);
}

// Get memory for Mode list
cbSize = cModes * sizeof (LPDDModeInfo);
lpModes = (LPDDModeInfo *) malloc (cbSize);
if (! lpModes)
return FALSE;

// Create Mode List
dwIndex = 0;
lpCurr = lpModeRoot;
while (lpCurr)
{
lpNext = lpCurr->lpNext;

lpModes[dwIndex] = lpCurr;

dwIndex++;

lpCurr = lpNext;
}

// Sort Mode list
qsort ((void *)lpModes, (size_t)cModes, sizeof(LPDDModeInfo), CompareModes);

// Dump Mode list to Combo Box
for (dwIndex = 0; dwIndex < cModes; dwIndex++)
{
// Make sure mode is supported by D3D device
if ((lpModes[dwIndex]) &&
(lpModes[dwIndex]->ModeSupported (lpDevice)))
{
TCHAR szBuff[80];
DWORD w, h, bpp, refresh;
DWORD dwNew;

lpModes[dwIndex]->GetMode (w, h, bpp, refresh);

// Set up Mode String
if (refresh)
wsprintf (szBuff, TEXT("%4d x %4d x %4d (%4d Hz)"),
w, h, bpp, refresh);
else
wsprintf (szBuff, TEXT("%4d x %4d x %4d"),
w, h, bpp);

// Add String to Combo Box
dwNew = SendDlgItemMessage (hDlg, IDC_MODES, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)szBuff);

// Set up pointer to Mode Info for this item
SendDlgItemMessage (hDlg, IDC_MODES, CB_SETITEMDATA, (WPARAM)dwNew, (LPARAM)(void *)lpModes[dwIndex]);

// Is it the current Mode
if (lpModeCurr == lpModes[dwIndex])
{
// Set as our current selection
SendDlgItemMessage (hDlg, IDC_MODES, CB_SETCURSEL, (WPARAM)dwNew, 0L);
}
}
}

// Cleanup Memory
free (lpModes);
lpModes = NULL;

// Success
return TRUE;
} // End DlgModesInit




/*
**-----------------------------------------------------------------------------
** Name: DlgGetDriver
** Purpose: Get current driver selection
**-----------------------------------------------------------------------------
*/

LPDDDrvInfo DlgGetDriver (HWND hDlg)
{
DWORD dwIndex = SendDlgItemMessage (hDlg, IDC_DRIVERS, CB_GETCURSEL, 0, 0);
if (dwIndex != CB_ERR)
{
// Get pointer to driver
LPDDDrvInfo lpDriver = (LPDDDrvInfo) SendDlgItemMessage (hDlg,
IDC_DRIVERS,
CB_GETITEMDATA,
(WPARAM)dwIndex,
(LPARAM)0);
return lpDriver;
}

// Failure
return NULL;
} // End DlgGetDriver



/*
**-----------------------------------------------------------------------------
** Name: DlgGetDevice
** Purpose: Get current device selection
**-----------------------------------------------------------------------------
*/

LPD3DDevInfo DlgGetDevice (HWND hDlg)
{
DWORD dwIndex = SendDlgItemMessage (hDlg, IDC_DEVICES, CB_GETCURSEL, 0, 0);
if (dwIndex != CB_ERR)
{
// Get pointer to device
LPD3DDevInfo lpDevice = (LPD3DDevInfo) SendDlgItemMessage (hDlg,
IDC_DEVICES,
CB_GETITEMDATA,
(WPARAM)dwIndex,
(LPARAM)0);
return lpDevice;
}

// Failure
return NULL;
} // End DlgGetDevice



/*
**-----------------------------------------------------------------------------
** Name: DlgGetMode
** Purpose: Get current mode selection
**-----------------------------------------------------------------------------
*/

LPDDModeInfo DlgGetMode (HWND hDlg)
{
DWORD dwIndex = SendDlgItemMessage (hDlg, IDC_MODES, CB_GETCURSEL, 0, 0);
if (dwIndex != CB_ERR)
{
// Get pointer to device
LPDDModeInfo lpMode = (LPDDModeInfo) SendDlgItemMessage (hDlg,
IDC_MODES,
CB_GETITEMDATA,
(WPARAM)dwIndex,
(LPARAM)0);
return lpMode;
}

// Failure
return NULL;
} // End DlgGetMode





/*
**-----------------------------------------------------------------------------
** Name: OnChangeDriver
** Purpose: Allows user to choose a new Driver from dialog
**Notes:User can also choose a new device and mode
**-----------------------------------------------------------------------------
*/

void OnChangeDriver (HWND hWindow, int idDialog)
{
HINSTANCEhInstance;
intfResult;
ChangeDDInfochangeInfo;
LPD3DWindowlpd3dWindow;

// Get application instance
hInstance = (HINSTANCE) GetWindowLong (hWindow, GWL_HINSTANCE);
if (! hInstance)
return;

// Get D3D Window pointer
lpd3dWindow = (LPD3DWindow)GetWindowLong (hWindow, GWL_USERDATA);
if (! lpd3dWindow)
return;

// Setup Change info
changeInfo.lpDrvOrig= lpd3dWindow->GetDriverInfo ();
changeInfo.lpDrvNew= changeInfo.lpDrvOrig;

changeInfo.lpDevOrig= lpd3dWindow->GetDeviceInfo ();
changeInfo.lpDevNew= changeInfo.lpDevOrig;

changeInfo.lpModeOrig= lpd3dWindow->GetModeInfo ();
changeInfo.lpModeNew= changeInfo.lpModeOrig;


// Pause App
OnPause (hWindow, TRUE);

// Do Change Mode Dialog here
fResult = DialogBoxParam (hInstance, MAKEINTRESOURCE (idDialog),
hWindow, (DLGPROC)ChangeDriverProc,
(LPARAM)(void *)&changeInfo);

// UnPause app
OnPause (hWindow, FALSE);

// Did user request a change ?!?
if (fResult == TRUE)
{
LPGUID lpGuidDD, lpGuidD3D;
DWORD w, h, bpp, refresh;

if (changeInfo.lpDrvOrig != changeInfo.lpDrvNew)
{
if (changeInfo.lpDrvNew)
lpGuidDD = changeInfo.lpDrvNew->GetGuid ();
else
lpGuidDD = NULL;

lpd3dWindow->ChangeDriver (lpGuidDD,
changeInfo.lpDevNew,
changeInfo.lpModeNew);
}
else if (changeInfo.lpDevOrig != changeInfo.lpDevNew)
{
if (changeInfo.lpDevNew)
lpGuidD3D = &(changeInfo.lpDevNew->guid);
else
lpGuidD3D = NULL;

lpd3dWindow->ChangeDevice (lpGuidD3D, changeInfo.lpModeNew);
}
else if (changeInfo.lpModeOrig != changeInfo.lpModeNew)
{
changeInfo.lpModeNew->GetMode (w, h, bpp, refresh);
lpd3dWindow->ChangeMode (w, h, bpp, refresh);
}
}
} // End OnChangeDriver



/*
**-----------------------------------------------------------------------------
** Name: ChangeDriverProc
** Purpose: handles messages for Change Driver,
**D3D device, and mode dialog boxes
**-----------------------------------------------------------------------------
*/

BOOL CALLBACK ChangeDriverProc(
HWND hDlg,// handle to dialog box
UINT uiMsg,// message
WPARAM wParam,// first message parameter
LPARAM lParam) // second message parameter
{
BOOLfChanged;
LPChangeDDInfo lpChange;
LPDDDrvInfolpDriver;
LPDDModeInfolpMode;
LPD3DDevInfolpDevice;

switch (uiMsg)
{
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
// Get Change Info
lpChange = (LPChangeDDInfo) GetWindowLong (hDlg, DWL_USER);
if (! lpChange)
EndDialog (hDlg, FALSE);

fChanged = FALSE;

// Get New Driver
lpDriver = DlgGetDriver (hDlg);
if ((lpDriver) && (lpDriver != lpChange->lpDrvOrig))
{
fChanged = TRUE;
lpChange->lpDrvNew = lpDriver;
}
else
lpChange->lpDrvNew = lpChange->lpDrvOrig;

// Get New Device
lpDevice = DlgGetDevice (hDlg);
if ((lpDevice) && (lpDevice != lpChange->lpDevOrig))
{
fChanged = TRUE;
lpChange->lpDevNew = lpDevice;
}
else
lpChange->lpDevNew = lpChange->lpDevOrig;

// Get New Mode
lpMode = DlgGetMode (hDlg);
if ((lpMode) && (lpMode != lpChange->lpModeOrig))
{
fChanged = TRUE;
lpChange->lpModeNew = lpMode;
}
else
lpChange->lpModeNew = lpChange->lpModeOrig;

// Return success/failure
EndDialog (hDlg, fChanged);
break;

case IDCANCEL:
EndDialog (hDlg, FALSE);
break;

case IDC_DRIVERS:
switch (HIWORD (wParam))
{
case CBN_SELENDOK:
// User has changed the current driver
lpChange = (LPChangeDDInfo) GetWindowLong (hDlg, DWL_USER);

// Check if user has changed the Driver
lpDriver = DlgGetDriver (hDlg);
if ((lpDriver) && (lpDriver != lpChange->lpDrvNew))
{
lpChange->lpDrvNew = lpDriver;
lpChange->lpDevNew = NULL;// Pick a new device
lpChange->lpModeNew = NULL;// Pick a new mode

// Update the Device list
SendDlgItemMessage (hDlg, IDC_DEVICES, CB_RESETCONTENT, 0, 0);
DlgDevicesInit (hDlg);

// Update the Mode list
SendDlgItemMessage (hDlg, IDC_MODES, CB_RESETCONTENT, 0, 0);
DlgModesInit (hDlg);
}
break;
}
break;

case IDC_DEVICES:
switch (HIWORD (wParam))
{
case CBN_SELENDOK:
// User has changed the current device
lpChange = (LPChangeDDInfo) GetWindowLong (hDlg, DWL_USER);

// Check if user has changed the device
lpDevice = DlgGetDevice (hDlg);
if ((lpDevice) && (lpDevice != lpChange->lpDevNew))
{
lpChange->lpDevNew = lpDevice;

// Update the Mode list
SendDlgItemMessage (hDlg, IDC_MODES, CB_RESETCONTENT, 0, 0);
DlgModesInit (hDlg);
}
break;
}
break;

case IDC_MODES:
switch (HIWORD (wParam))
{
case CBN_SELENDOK:
// User has changed the current mode
lpChange = (LPChangeDDInfo) GetWindowLong (hDlg, DWL_USER);

// Check if user has changed the Mode
lpMode = DlgGetMode (hDlg);
if ((lpMode) && (lpMode != lpChange->lpModeNew))
{
lpChange->lpModeNew = lpMode;
}
break;
}
break;
}
break;

case WM_INITDIALOG:
// Save pointer to ChangeInfo
SetWindowLong (hDlg, DWL_USER, (long)lParam);

// Set up the current driver, device, and mode lists
if (GetDlgItem (hDlg, IDC_DRIVERS))
if (! DlgDriversInit (hDlg))
return FALSE;

if (GetDlgItem (hDlg, IDC_DEVICES))
if (! DlgDevicesInit (hDlg))
return FALSE;

if (GetDlgItem (hDlg, IDC_MODES))
if (! DlgModesInit (hDlg))
return FALSE;

// Successful init
return TRUE;
}
return FALSE;
} // End ChangeDriverProc




/*
**-----------------------------------------------------------------------------
** End of File
**-----------------------------------------------------------------------------
*/