Initial commit: ROW Client source code

Game client codebase including:
- CharacterActionControl: Character and creature management
- GlobalScript: Network, items, skills, quests, utilities
- RYLClient: Main client application with GUI and event handlers
- Engine: 3D rendering engine (RYLGL)
- MemoryManager: Custom memory allocation
- Library: Third-party dependencies (DirectX, boost, etc.)
- Tools: Development utilities

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-29 16:24:34 +09:00
commit e067522598
5135 changed files with 1745744 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -0,0 +1,965 @@
//-----------------------------------------------------------------------------
// File: Multimon.cpp
//
// Desc: This sample demonstrates the following programming concepts:
// Writing code for a multi-monitor program that works on both Windows 95
// (which does not support multiple monitors) and later Windows versions
// (which do support it).
// Using DirectDrawEnumerateEx to enumerate displays.
// Working with separate device and focus windows.
// Creating a video-memory sprite that spans multiple screens using multiple
// copies of the image data.
// Creating a system-memory sprite that spans multiple screens using a shared
// copy of the image data.
//
// Copyright (c) 1998-2001 Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
// Multimon.h implements support of the multimon APIs for when your program
// runs on Windows 95 systems. You can #include multimon.h in all your source
// files that use multimon APIs, and you should #define COMPILE_MULTIMON_STUBS
// in only one of your source files.
#define COMPILE_MULTIMON_STUBS
#include <windows.h>
#include <multimon.h>
#include <ddraw.h>
#include "resource.h"
//-----------------------------------------------------------------------------
// Defines, constants, and global variables
//-----------------------------------------------------------------------------
#define NAME TEXT("MultiMon DirectDraw Sample")
#define TITLE TEXT("MultiMon DirectDraw Sample")
// An EnumInfo contains extra enumeration information that is passed
// into the the DDEnumCallbackEx function.
struct EnumInfo
{
BOOL bMultimonSupported;
HRESULT hr;
};
// A Screen represents one display that images can be drawn to.
struct Screen
{
GUID guid;
TCHAR szDesc[200];
HMONITOR hmon;
LPDIRECTDRAW7 pDD;
LPDIRECTDRAWSURFACE7 pDDSFront;
LPDIRECTDRAWSURFACE7 pDDSBack;
Screen* pScreenNext; // For linked list
};
// A ScreenSurface holds a DirectDrawSurface that can be used on a
// particular screen.
struct ScreenSurface
{
Screen* pScreen;
LPDIRECTDRAWSURFACE7 pDDS;
ScreenSurface* pScreenSurfaceNext; // For linked list
// Could add a "last used time" field, which could be used to
// determine whether this ScreenSurface should be
// removed to free up video memory for another surface
};
// A Sprite holds generic information about a drawable image, and
// a linked list of ScreenSurfaces (one per screen).
struct Sprite
{
TCHAR szName[64]; // Name of this Sprite
BOOL bForceSystem; // If TRUE, don't try to create video memory surfaces
RECT rcSrc; // Dimensions of the image
RECT rcDest; // Destination rectangle to draw image into
LONG xVel; // X-Velocity for animation
LONG yVel; // Y-Velocity for animation
HBITMAP hbmImage; // Loaded bitmap image
BYTE* pImageData; // Sharable pointer to DD surface data
DDSURFACEDESC2 ddsd; // Holds pitch and pixel format of pImageData
ScreenSurface* pScreenSurfaceFirst; // Linked list of ScreenSurfaces
};
Screen* g_pScreenFirst = NULL; // Linked list of Screens
Sprite* g_pSprite1 = NULL; // A sprite that uses video memory where possible
Sprite* g_pSprite2 = NULL; // A sprite that always uses system memory
HWND g_hWnd = NULL; // Main app focus HWND
BOOL g_bActive = TRUE; // Whether app is actively drawing
//-----------------------------------------------------------------------------
// Function prototypes
//-----------------------------------------------------------------------------
INT APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, INT nCmdShow );
HRESULT CreateFocusWindow( HINSTANCE hInstance );
HRESULT EnumerateScreens( VOID );
BOOL WINAPI DDEnumCallback( GUID* pGuid, LPTSTR pszDesc, LPTSTR pszDriverName, VOID* pContext );
BOOL WINAPI DDEnumCallbackEx( GUID* pGuid, LPTSTR pszDesc, LPTSTR pszDriverName, VOID* pContext, HMONITOR hmon );
HRESULT InitScreens( VOID );
HRESULT InitSprites( VOID );
HRESULT MainLoop( VOID );
LRESULT CALLBACK WindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
VOID UpdateFrame( VOID );
BOOL RectIntersectsMonitor( RECT* prcSrc, HMONITOR hmon, RECT* prcScreen );
HRESULT FindOrBuildScreenSurface( Sprite* pSprite, Screen* pScreen, ScreenSurface** ppScreenSurface );
HRESULT SetupScreenSurfaceDDS( Sprite* pSprite, ScreenSurface* pScreenSurface );
VOID DestroyScreenSurfaces( Sprite* pSprite );
VOID Cleanup( VOID );
//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: Initializes the application, then starts the main application loop.
//-----------------------------------------------------------------------------
INT APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, INT nCmdShow )
{
HRESULT hr;
if( FAILED( hr = CreateFocusWindow(hInst) ) )
return 0;
if( FAILED( hr = EnumerateScreens() ) )
return 0;
if( FAILED( hr = InitScreens() ) )
return 0;
if( FAILED( hr = InitSprites() ) )
return 0;
if( FAILED( hr = MainLoop() ) )
return 0;
return 0;
}
//-----------------------------------------------------------------------------
// Name: CreateFocusWindow()
// Desc: Creates the focus window, which is the window which will receive user
// input.
//-----------------------------------------------------------------------------
HRESULT CreateFocusWindow( HINSTANCE hInstance )
{
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon( hInstance, MAKEINTRESOURCE(IDI_ICON1) );
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = NAME;
RegisterClass( &wc );
// Window style and dimensions are not important,
// since they will be adjusted elsewhere.
g_hWnd = CreateWindowEx( 0, NAME, TITLE, 0, 0, 0, 0, 0,
NULL, NULL, hInstance, NULL );
// It is important to call ShowWindow on this window to ensure
// that any activity from other windows is obscured.
ShowWindow( g_hWnd, SW_SHOW );
if( g_hWnd == NULL )
return E_FAIL;
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: EnumerateScreens()
// Desc: Creates a Screen structure for every appropriate screen in the user's
// computer.
//-----------------------------------------------------------------------------
HRESULT EnumerateScreens()
{
HRESULT hr;
EnumInfo enumInfo;
ZeroMemory( &enumInfo, sizeof(enumInfo) );
enumInfo.bMultimonSupported = TRUE;
if( FAILED( hr = DirectDrawEnumerateEx( DDEnumCallbackEx,
&enumInfo,
DDENUM_ATTACHEDSECONDARYDEVICES ) ) )
return hr;
// If something failed inside the enumeration, be sure to return that HRESULT
if( FAILED(enumInfo.hr) )
return enumInfo.hr;
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: DDEnumCallbackEx()
// Desc: This callback function is called by DirectDraw once for each
// available DirectDraw device. In this implementation, it saves the
// GUID, device description, and hmon in a Screen structure for later use.
//-----------------------------------------------------------------------------
BOOL WINAPI DDEnumCallbackEx( GUID* pGuid, LPTSTR pszDesc, LPTSTR pszDriverName,
VOID* pContext, HMONITOR hmon )
{
Screen* pScreenNew;
EnumInfo* pEnumInfo = (EnumInfo*)pContext;
GUID guidNull;
ZeroMemory( &guidNull, sizeof(GUID) );
if( g_pScreenFirst != NULL &&
g_pScreenFirst->guid == guidNull )
{
// We must be running on a multimon system, so get rid of the
// guidNull Screen -- we want Screens with specific GUIDs.
delete g_pScreenFirst;
g_pScreenFirst = NULL;
}
// Store all the info in a Screen structure
pScreenNew = new Screen;
if( pScreenNew == NULL )
{
pEnumInfo->hr = E_OUTOFMEMORY;
return FALSE; // fatal error, stop enumerating
}
ZeroMemory( pScreenNew, sizeof(Screen) );
if( pGuid == NULL )
pScreenNew->guid = guidNull;
else
pScreenNew->guid = *pGuid;
lstrcpy( pScreenNew->szDesc, pszDesc );
pScreenNew->hmon = hmon;
// Insert Screen into global linked list
if( g_pScreenFirst == NULL )
{
g_pScreenFirst = pScreenNew;
}
else
{
// Insert at end of list
Screen* pScreen = g_pScreenFirst;
while( pScreen->pScreenNext != NULL )
pScreen = pScreen->pScreenNext;
pScreen->pScreenNext = pScreenNew;
}
return TRUE; // Keep enumerating
}
//-----------------------------------------------------------------------------
// Name: InitScreens()
// Desc: For each Screen, this function initializes DirectDraw and sets up the
// front buffer, back buffer, and a clipper. Many fullscreen DirectDraw
// programs don't need to create clippers, but this one does so to allow
// the sprites to be automatically clipped to each display.
//-----------------------------------------------------------------------------
HRESULT InitScreens( VOID )
{
HRESULT hr;
Screen* pScreen = NULL;
GUID* pGuid = NULL;
DWORD dwFlags;
DDSURFACEDESC2 ddsd;
LPDIRECTDRAWCLIPPER pClip = NULL;
DDSCAPS2 ddsCaps;
RECT rc;
HRGN hrgn;
BYTE rgnDataBuffer[1024];
GUID guidNull;
ZeroMemory( &guidNull, sizeof(GUID) );
for( pScreen = g_pScreenFirst; pScreen != NULL; pScreen = pScreen->pScreenNext )
{
if( pScreen->guid == guidNull )
pGuid = NULL;
else
pGuid = &pScreen->guid;
if( FAILED(hr = DirectDrawCreateEx( pGuid, (VOID**) &(pScreen->pDD),
IID_IDirectDraw7, NULL ) ) )
return hr;
if( pScreen == g_pScreenFirst)
{
dwFlags = DDSCL_SETFOCUSWINDOW;
if( FAILED( hr = pScreen->pDD->SetCooperativeLevel( g_hWnd, dwFlags ) ) )
return hr;
dwFlags = DDSCL_ALLOWREBOOT | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN;
if( FAILED( hr = pScreen->pDD->SetCooperativeLevel(g_hWnd, dwFlags ) ) )
return hr;
}
else
{
dwFlags = DDSCL_SETFOCUSWINDOW | DDSCL_CREATEDEVICEWINDOW |
DDSCL_ALLOWREBOOT | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN;
if( FAILED( hr = pScreen->pDD->SetCooperativeLevel(g_hWnd, dwFlags ) ) )
return hr;
}
if( FAILED( hr = pScreen->pDD->SetDisplayMode( 640, 480, 16, 0, 0 ) ) )
return hr;
}
// Note: It is recommended that programs call SetDisplayMode on all screens
// before creating/acquiring any DirectDrawSurfaces.
for( pScreen = g_pScreenFirst; pScreen != NULL; pScreen = pScreen->pScreenNext )
{
ZeroMemory( &ddsd, sizeof(ddsd) );
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_BACKBUFFERCOUNT | DDSD_CAPS;
ddsd.dwBackBufferCount = 1;
ddsd.ddsCaps.dwCaps = DDSCAPS_COMPLEX | DDSCAPS_FLIP | DDSCAPS_PRIMARYSURFACE;
if( FAILED( hr = pScreen->pDD->CreateSurface( &ddsd,
&pScreen->pDDSFront, NULL ) ) )
{
return hr;
}
ZeroMemory( &ddsCaps, sizeof(ddsCaps) );
ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
if( FAILED( hr = pScreen->pDDSFront->GetAttachedSurface( &ddsCaps,
&pScreen->pDDSBack ) ) )
return hr;
ZeroMemory( &ddsd, sizeof(ddsd) );
ddsd.dwSize = sizeof(ddsd);
if( FAILED( hr = pScreen->pDDSFront->GetSurfaceDesc( &ddsd ) ) )
return hr;
SetRect( &rc, 0, 0, ddsd.dwWidth, ddsd.dwHeight );
hrgn = CreateRectRgn( 0, 0, ddsd.dwWidth, ddsd.dwHeight );
GetRegionData( hrgn, sizeof(rgnDataBuffer), (RGNDATA*)rgnDataBuffer );
DeleteObject( hrgn );
if( FAILED( hr = pScreen->pDD->CreateClipper( 0, &pClip, 0 ) ) )
return hr;
if( FAILED( hr = pClip->SetClipList( (RGNDATA*)rgnDataBuffer, 0 ) ) )
{
pClip->Release();
return hr;
}
if( FAILED( hr = pScreen->pDDSFront->SetClipper( pClip ) ) )
{
pClip->Release();
return hr;
}
if( FAILED( hr = pScreen->pDDSBack->SetClipper( pClip ) ) )
{
pClip->Release();
return hr;
}
pClip->Release();
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: InitSprites()
// Desc: Initializes the objects that will be drawn and animated. Note that
// the ScreenSurfaces are created when they are first needed, not here.
//-----------------------------------------------------------------------------
HRESULT InitSprites( VOID )
{
BITMAP bm;
// Initialize the first Sprite. This sprite will try to use video memory
// on each Screen.
g_pSprite1 = new Sprite;
if( g_pSprite1 == NULL )
return E_OUTOFMEMORY;
ZeroMemory( g_pSprite1, sizeof(Sprite) );
lstrcpy( g_pSprite1->szName, TEXT("Sprite 1") );
g_pSprite1->bForceSystem = FALSE; // This sprite will try to use video memory
g_pSprite1->hbmImage = (HBITMAP) LoadImage( GetModuleHandle(NULL),
MAKEINTRESOURCE(IDB_BITMAP1),
IMAGE_BITMAP, 0, 0,
LR_CREATEDIBSECTION );
if( g_pSprite1->hbmImage == NULL )
return E_FAIL;
GetObject( g_pSprite1->hbmImage, sizeof(bm), &bm ); // get size of bitmap
SetRect( &g_pSprite1->rcSrc, 0, 0, bm.bmWidth, bm.bmHeight );
g_pSprite1->rcDest = g_pSprite1->rcSrc;
g_pSprite1->xVel = 2; // Animation velocity
g_pSprite1->yVel = 1;
// Initialize the second Sprite. This sprite will use system memory (and
// share that memory between ScreenSurfaces whenever possible).
g_pSprite2 = new Sprite;
if( g_pSprite2 == NULL )
return E_OUTOFMEMORY;
ZeroMemory( g_pSprite2, sizeof(Sprite) );
lstrcpy(g_pSprite2->szName, TEXT("Sprite 2"));
g_pSprite2->bForceSystem = TRUE; // This sprite will always use system memory
g_pSprite2->hbmImage = (HBITMAP) LoadImage( GetModuleHandle(NULL),
MAKEINTRESOURCE(IDB_BITMAP2),
IMAGE_BITMAP, 0, 0,
LR_CREATEDIBSECTION );
if( g_pSprite2->hbmImage == NULL )
return E_FAIL;
GetObject( g_pSprite2->hbmImage, sizeof(bm), &bm ); // get size of bitmap
SetRect( &g_pSprite2->rcSrc, 0, 0, bm.bmWidth, bm.bmHeight );
g_pSprite2->rcDest = g_pSprite1->rcSrc;
g_pSprite2->xVel = -1; // Animation velocity
g_pSprite2->yVel = -2;
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: MainLoop()
// Desc: The main window message pump. When the application is active (not
// minimized), it uses PeekMessage so that UpdateFrame can be called
// frequently once all window messages are handled. When it is not
// active, GetMessage is used instead to give more processing time to
// other running programs.
//-----------------------------------------------------------------------------
HRESULT MainLoop( VOID )
{
MSG msg;
BOOL bGotMsg;
while( TRUE )
{
if( g_bActive)
bGotMsg = PeekMessage( &msg, NULL, 0, 0, PM_REMOVE );
else
bGotMsg = GetMessage( &msg, NULL, 0, 0);
if( msg.message == WM_QUIT)
return S_OK;
if( bGotMsg)
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else if( g_bActive)
{
UpdateFrame();
}
}
}
//-----------------------------------------------------------------------------
// Name: WindowProc()
// Desc: Handler for window messages.
//-----------------------------------------------------------------------------
LRESULT CALLBACK WindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch(uMsg)
{
case WM_SIZE:
if( SIZE_MAXHIDE == wParam || SIZE_MINIMIZED == wParam )
{
g_bActive = FALSE;
// Give window an icon and system menu on the taskbar when minimized
SetWindowLong(hWnd, GWL_STYLE, WS_SYSMENU);
}
else
{
g_bActive = TRUE;
// Remove any window "decoration" when fullscreen
SetWindowLong(hWnd, GWL_STYLE, WS_POPUP);
}
return DefWindowProc( hWnd, uMsg, wParam, lParam );
case WM_CLOSE:
return DefWindowProc( hWnd, uMsg, wParam, lParam );
case WM_CHAR:
DestroyWindow( hWnd );
return 0;
case WM_DESTROY:
Cleanup();
PostQuitMessage( 0 );
return 0;
default:
return DefWindowProc( hWnd, uMsg, wParam, lParam );
}
}
//-----------------------------------------------------------------------------
// Name: UpdateFrame()
// Desc: Renders one frame of animation, then updates the sprites for the next
// frame.
//-----------------------------------------------------------------------------
VOID UpdateFrame( VOID )
{
HRESULT hr;
Screen* pScreen;
RECT rcScreen;
ScreenSurface* pScreenSurface;
DDBLTFX ddbltfx;
for( pScreen = g_pScreenFirst; pScreen != NULL; pScreen = pScreen->pScreenNext )
{
// Handle lost surfaces
if( pScreen->pDDSFront->IsLost() == DDERR_SURFACELOST )
{
// Though surface memory can be reaquired via RestoreAllSurfaces, the
// image contents will be undefined. So we destroy all the ScreenSurfaces
// and let them be recreated as needed. Calling RestoreAllSurfaces
// takes care of the remaining surfaces (the front and back buffers).
DestroyScreenSurfaces( g_pSprite1 );
DestroyScreenSurfaces( g_pSprite2 );
hr = pScreen->pDD->RestoreAllSurfaces();
}
// Clear the back buffer for this Screen
ZeroMemory( &ddbltfx, sizeof(ddbltfx) );
ddbltfx.dwSize = sizeof(ddbltfx);
ddbltfx.dwFillColor = 0; // Black
hr = pScreen->pDDSBack->Blt( NULL, NULL, NULL,
DDBLT_COLORFILL | DDBLT_WAIT,
&ddbltfx );
// Draw first sprite
if( RectIntersectsMonitor( &g_pSprite1->rcDest, pScreen->hmon, &rcScreen ) )
{
hr = FindOrBuildScreenSurface( g_pSprite1, pScreen, &pScreenSurface );
if( SUCCEEDED(hr) )
{
hr = pScreen->pDDSBack->Blt( &rcScreen, pScreenSurface->pDDS,
&g_pSprite1->rcSrc,
DDBLT_WAIT, NULL );
}
}
// Draw second sprite
if( RectIntersectsMonitor( &g_pSprite2->rcDest, pScreen->hmon, &rcScreen ) )
{
hr = FindOrBuildScreenSurface( g_pSprite2, pScreen, &pScreenSurface );
if( SUCCEEDED( hr ) )
{
hr = pScreen->pDDSBack->Blt( &rcScreen, pScreenSurface->pDDS,
&g_pSprite2->rcSrc, DDBLT_WAIT, NULL );
}
}
}
// Flip all screens. This is done in a separate loop to make the flips happen
// as close together in time as possible
for( pScreen = g_pScreenFirst; pScreen != NULL; pScreen = pScreen->pScreenNext )
{
hr = pScreen->pDDSFront->Flip( NULL, DDFLIP_WAIT );
}
// Animate Sprites for the next frame. The sprites are bounced against the
// virtual desktop, which may cause them to partially or totally disappear
// if your screens are set up in a way that is non-rectangular. Since the
// animation is not the purpose of this demo, this simplified approach is used.
RECT rcDesktop;
rcDesktop.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
rcDesktop.right = rcDesktop.left + GetSystemMetrics(SM_CXVIRTUALSCREEN);
rcDesktop.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
rcDesktop.bottom = rcDesktop.top + GetSystemMetrics(SM_CYVIRTUALSCREEN);
// Animate first sprite
OffsetRect( &g_pSprite1->rcDest, g_pSprite1->xVel, g_pSprite1->yVel );
if( ( g_pSprite1->rcDest.right > rcDesktop.right && g_pSprite1->xVel > 0 ) ||
( g_pSprite1->rcDest.left < rcDesktop.left && g_pSprite1->xVel < 0 ) )
{
g_pSprite1->xVel = -g_pSprite1->xVel;
}
if( ( g_pSprite1->rcDest.bottom > rcDesktop.bottom && g_pSprite1->yVel > 0 ) ||
( g_pSprite1->rcDest.top < rcDesktop.top && g_pSprite1->yVel < 0 ) )
{
g_pSprite1->yVel = -g_pSprite1->yVel;
}
// Animate second sprite
OffsetRect( &g_pSprite2->rcDest, g_pSprite2->xVel, g_pSprite2->yVel );
if( ( g_pSprite2->rcDest.right > rcDesktop.right && g_pSprite2->xVel > 0 ) ||
( g_pSprite2->rcDest.left < rcDesktop.left && g_pSprite2->xVel < 0 ) )
{
g_pSprite2->xVel = -g_pSprite2->xVel;
}
if( ( g_pSprite2->rcDest.bottom > rcDesktop.bottom && g_pSprite2->yVel > 0 ) ||
( g_pSprite2->rcDest.top < rcDesktop.top && g_pSprite2->yVel < 0 ) )
{
g_pSprite2->yVel = -g_pSprite2->yVel;
}
}
//-----------------------------------------------------------------------------
// Name: RectIntersectsMonitor()
// Desc: Returns TRUE if prcSrc intersects the monitor hmon, and uses prcScreen
// to store prcSrc in that monitor's local coordinate system.
//-----------------------------------------------------------------------------
BOOL RectIntersectsMonitor( RECT* prcSrc, HMONITOR hmon, RECT* prcScreen )
{
MONITORINFO mi;
RECT rcIntersection;
BOOL bIntersects;
ZeroMemory( &mi, sizeof(mi) );
mi.cbSize = sizeof(mi);
if( hmon == NULL )
{
SetRect( &mi.rcMonitor, 0, 0, GetSystemMetrics(SM_CXSCREEN),
GetSystemMetrics(SM_CYSCREEN) );
}
else
{
GetMonitorInfo(hmon, &mi);
}
bIntersects = IntersectRect( &rcIntersection, prcSrc, &mi.rcMonitor );
if( !bIntersects)
return FALSE;
*prcScreen = *prcSrc;
OffsetRect( prcScreen, -mi.rcMonitor.left, -mi.rcMonitor.top );
return TRUE;
}
//-----------------------------------------------------------------------------
// Name: FindOrBuildScreenSurface()
// Desc: This is called when UpdateFrame needs to draw the image of a Sprite
// onto a particular Screen. If a ScreenSurface already exists for this
// Screen and Sprite, a pointer to it is returned. Otherwise, a new
// ScreenSurface is created (and stored for future reuse).
//-----------------------------------------------------------------------------
HRESULT FindOrBuildScreenSurface( Sprite* pSprite, Screen* pScreen,
ScreenSurface** ppScreenSurface )
{
HRESULT hr;
ScreenSurface* pScreenSurface;
for( pScreenSurface = pSprite->pScreenSurfaceFirst;
pScreenSurface != NULL;
pScreenSurface = pScreenSurface->pScreenSurfaceNext )
{
if( pScreenSurface->pScreen == pScreen )
{
// ScreenSurface exists for this Screen, so return a pointer to it
*ppScreenSurface = pScreenSurface;
return S_OK;
}
}
// No ScreenSurface for this Screen exists yet, so build one.
pScreenSurface = new ScreenSurface;
if( pScreenSurface == NULL )
return E_OUTOFMEMORY;
ZeroMemory( pScreenSurface, sizeof(ScreenSurface) );
pScreenSurface->pScreen = pScreen;
if( FAILED( hr = SetupScreenSurfaceDDS(pSprite, pScreenSurface ) ) )
{
delete pScreenSurface;
return hr;
}
// Insert this new ScreenSurface in the Sprite's list:
pScreenSurface->pScreenSurfaceNext = pSprite->pScreenSurfaceFirst;
pSprite->pScreenSurfaceFirst = pScreenSurface;
*ppScreenSurface = pScreenSurface;
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: SetupScreenSurfaceDDS()
// Desc: Generates the DirectDrawSurface for a new ScreenSurface, and draws
// the appropriate image into it.
//-----------------------------------------------------------------------------
HRESULT SetupScreenSurfaceDDS( Sprite* pSprite, ScreenSurface* pScreenSurface )
{
HRESULT hr;
DDSURFACEDESC2 ddsd;
TCHAR sz[200];
Screen* pScreen = pScreenSurface->pScreen;
ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
ddsd.dwWidth = pSprite->rcSrc.right - pSprite->rcSrc.left;
ddsd.dwHeight = pSprite->rcSrc.bottom - pSprite->rcSrc.top;
ddsd.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY;
// Try to create the surface in video memory, unless the bForceSystem flag
// is set on the Sprite.
if( pSprite->bForceSystem ||
FAILED( hr = pScreen->pDD->CreateSurface( &ddsd, &pScreenSurface->pDDS, NULL ) ) )
{
// Either this sprite has the bForceSystem flag, or creation in video
// memory failed, so try to create the surface in system memory.
ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY;
if( FAILED( hr = pScreen->pDD->CreateSurface( &ddsd, &pScreenSurface->pDDS, NULL ) ) )
return hr;
}
if( ddsd.ddsCaps.dwCaps == DDSCAPS_SYSTEMMEMORY &&
pSprite->pImageData != NULL )
{
// See if we can reuse the image data that is stored in the Sprite.
// As long as the pixel formats match, the image is reusable.
ZeroMemory( &ddsd, sizeof(ddsd) );
ddsd.dwSize = sizeof(ddsd);
if( FAILED( hr = pScreenSurface->pDDS->GetSurfaceDesc( &ddsd ) ) )
return hr;
if( ddsd.ddpfPixelFormat.dwRGBBitCount == pSprite->ddsd.ddpfPixelFormat.dwRGBBitCount &&
ddsd.ddpfPixelFormat.dwRBitMask == pSprite->ddsd.ddpfPixelFormat.dwRBitMask &&
ddsd.ddpfPixelFormat.dwGBitMask == pSprite->ddsd.ddpfPixelFormat.dwGBitMask &&
ddsd.ddpfPixelFormat.dwBBitMask == pSprite->ddsd.ddpfPixelFormat.dwBBitMask )
{
// Make the DDS use the Sprite's pImageData for its surface contents
if( FAILED( hr = pScreenSurface->pDDS->SetSurfaceDesc( &pSprite->ddsd, 0 ) ) )
return hr;
return S_OK; // All done! This DDS is ready to use.
}
// Otherwise, we can't share image data, and this system memory surface
// will be for this Screen only.
}
// Copy image data from the Sprite to this ScreenSurface:
HDC hdc;
if( FAILED( hr = pScreenSurface->pDDS->GetDC( &hdc ) ) )
return hr;
HDC hdcImage;
HGDIOBJ hgdiobjOld;
DWORD dwWidth = pSprite->rcSrc.right - pSprite->rcSrc.left;
DWORD dwHeight = pSprite->rcSrc.bottom - pSprite->rcSrc.top;
hdcImage = CreateCompatibleDC(NULL);
hgdiobjOld = SelectObject(hdcImage, pSprite->hbmImage);
StretchBlt( hdc, 0, 0, dwWidth, dwHeight,
hdcImage, 0, 0, dwWidth, dwHeight, SRCCOPY );
SelectObject( hdcImage, hgdiobjOld ); // restore previously selected object
DeleteDC( hdcImage );
TextOut( hdc, 0, 0, pSprite->szName, lstrlen(pSprite->szName) );
pScreenSurface->pDDS->ReleaseDC(hdc);
if( ddsd.ddsCaps.dwCaps == DDSCAPS_VIDEOMEMORY )
{
if( FAILED( hr = pScreenSurface->pDDS->GetDC( &hdc ) ) )
return hr;
wsprintf( sz, TEXT("Video memory copy") );
TextOut( hdc, 0, 20, sz, lstrlen(sz) );
wsprintf( sz, TEXT("for %s"), pScreen->szDesc );
TextOut( hdc, 0, 40, sz, lstrlen(sz) );
pScreenSurface->pDDS->ReleaseDC(hdc);
}
else if( pSprite->pImageData == NULL )
{
// No shared copy exists yet, so create one using data in this
// system memory surface.
if( FAILED( hr = pScreenSurface->pDDS->GetDC( &hdc ) ) )
return hr;
wsprintf(sz, TEXT("Shared System memory copy") );
TextOut(hdc, 0, 20, sz, lstrlen(sz) );
pScreenSurface->pDDS->ReleaseDC( hdc );
// Copy image to pImageData so it can be shared among ScreenSurfaces:
if( SUCCEEDED( hr = pScreenSurface->pDDS->Lock( NULL, &ddsd,
DDLOCK_READONLY | DDLOCK_WAIT,
NULL ) ) )
{
pSprite->pImageData = new BYTE[ ddsd.lPitch * ddsd.dwHeight ];
if( pSprite->pImageData != NULL )
{
// Store size, pitch, pixel format, and surface pointer info in Sprite
pSprite->ddsd = ddsd;
pSprite->ddsd.lpSurface = pSprite->pImageData;
pSprite->ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH |
DDSD_PIXELFORMAT | DDSD_LPSURFACE;
// Copy image data from DDS's surface memory to Sprite's buffer
CopyMemory( pSprite->pImageData, ddsd.lpSurface,
ddsd.lPitch * ddsd.dwHeight );
}
pScreenSurface->pDDS->Unlock(NULL);
if( pSprite->pImageData != NULL )
{
// May as well make this ScreenSurface use the sharable copy too:
if( FAILED( hr = pScreenSurface->pDDS->SetSurfaceDesc( &pSprite->ddsd, 0 ) ) )
return hr;
}
}
}
else
{
// Shared copy exists, but attempt to use it failed (probably due to
// mismatched pixel format), so indicate that this as a non-shared sysmem copy:
if( FAILED( hr = pScreenSurface->pDDS->GetDC( &hdc ) ) )
return hr;
wsprintf( sz, TEXT("System memory copy") );
TextOut( hdc, 0, 20, sz, lstrlen(sz) );
wsprintf( sz, TEXT("for %s"), pScreen->szDesc );
TextOut( hdc, 0, 40, sz, lstrlen(sz) );
pScreenSurface->pDDS->ReleaseDC( hdc );
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: DestroyScreenSurfaces()
// Desc: Destroys all ScreenSurfaces attached to the given Sprite. This is
// called after restoring all surfaces (since image data may be lost) and
// when preparing to exit the program.
//-----------------------------------------------------------------------------
VOID DestroyScreenSurfaces( Sprite* pSprite )
{
ScreenSurface* pScreenSurface;
ScreenSurface* pScreenSurfaceNext;
pScreenSurface = pSprite->pScreenSurfaceFirst;
pSprite->pScreenSurfaceFirst = NULL;
while( pScreenSurface != NULL )
{
pScreenSurfaceNext = pScreenSurface->pScreenSurfaceNext;
pScreenSurface->pDDS->Release();
delete pScreenSurface;
pScreenSurface = pScreenSurfaceNext;
}
if( pSprite->pImageData != NULL )
{
delete pSprite->pImageData;
pSprite->pImageData = NULL;
}
ZeroMemory( &pSprite->ddsd, sizeof(pSprite->ddsd) );
}
//-----------------------------------------------------------------------------
// Name: Cleanup()
// Desc: Releases all resources allocated during this program.
//-----------------------------------------------------------------------------
VOID Cleanup( VOID )
{
if( g_pSprite1 != NULL )
{
DestroyScreenSurfaces(g_pSprite1);
delete g_pSprite1;
g_pSprite1 = NULL;
}
if( g_pSprite2 != NULL )
{
DestroyScreenSurfaces(g_pSprite2);
delete g_pSprite2;
g_pSprite2 = NULL;
}
Screen* pScreen;
Screen* pScreenNext;
pScreen = g_pScreenFirst;
g_pScreenFirst = NULL;
while( pScreen != NULL )
{
pScreenNext = pScreen->pScreenNext;
pScreen->pDDSBack->Release();
pScreen->pDDSFront->Release();
pScreen->pDD->RestoreDisplayMode();
pScreen->pDD->SetCooperativeLevel(g_hWnd, DDSCL_NORMAL);
pScreen->pDD->Release();
delete pScreen;
pScreen = pScreenNext;
}
}

View File

@@ -0,0 +1,127 @@
# Microsoft Developer Studio Project File - Name="multimon" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Application" 0x0101
CFG=multimon - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "multimon.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "multimon.mak" CFG="multimon - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "multimon - Win32 Release" (based on "Win32 (x86) Application")
!MESSAGE "multimon - Win32 Debug" (based on "Win32 (x86) Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "multimon - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /I "..\..\common\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
# ADD LINK32 dxguid.lib odbc32.lib odbccp32.lib dxerr8.lib ddraw.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /machine:I386 /stack:0x200000,0x200000
!ELSEIF "$(CFG)" == "multimon - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\common\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FR /YX /FD /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
# ADD LINK32 dxguid.lib odbc32.lib odbccp32.lib dxerr8.lib ddraw.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept /stack:0x200000,0x200000
!ENDIF
# Begin Target
# Name "multimon - Win32 Release"
# Name "multimon - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\multimon.cpp
# End Source File
# Begin Source File
SOURCE=.\multimon.rc
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# Begin Source File
SOURCE=.\directx.ico
# End Source File
# Begin Source File
SOURCE=.\image1.bmp
# End Source File
# Begin Source File
SOURCE=.\image2.bmp
# End Source File
# Begin Source File
SOURCE=.\resource.h
# End Source File
# End Group
# Begin Source File
SOURCE=.\readme.txt
# End Source File
# End Target
# End Project

View File

@@ -0,0 +1,29 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "multimon"=.\multimon.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################

View File

@@ -0,0 +1,220 @@
# Microsoft Developer Studio Generated NMAKE File, Based on multimon.dsp
!IF "$(CFG)" == ""
CFG=multimon - Win32 Debug
!MESSAGE No configuration specified. Defaulting to multimon - Win32 Debug.
!ENDIF
!IF "$(CFG)" != "multimon - Win32 Release" && "$(CFG)" != "multimon - Win32 Debug"
!MESSAGE Invalid configuration "$(CFG)" specified.
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "multimon.mak" CFG="multimon - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "multimon - Win32 Release" (based on "Win32 (x86) Application")
!MESSAGE "multimon - Win32 Debug" (based on "Win32 (x86) Application")
!MESSAGE
!ERROR An invalid configuration is specified.
!ENDIF
!IF "$(OS)" == "Windows_NT"
NULL=
!ELSE
NULL=nul
!ENDIF
!IF "$(CFG)" == "multimon - Win32 Release"
OUTDIR=.\Release
INTDIR=.\Release
# Begin Custom Macros
OutDir=.\Release
# End Custom Macros
ALL : "$(OUTDIR)\multimon.exe"
CLEAN :
-@erase "$(INTDIR)\multimon.obj"
-@erase "$(INTDIR)\multimon.res"
-@erase "$(INTDIR)\vc60.idb"
-@erase "$(OUTDIR)\multimon.exe"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
CPP=cl.exe
CPP_PROJ=/nologo /ML /W3 /GX /O2 /I "..\..\common\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Fp"$(INTDIR)\multimon.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
.c{$(INTDIR)}.obj::
$(CPP) @<<
$(CPP_PROJ) $<
<<
.cpp{$(INTDIR)}.obj::
$(CPP) @<<
$(CPP_PROJ) $<
<<
.cxx{$(INTDIR)}.obj::
$(CPP) @<<
$(CPP_PROJ) $<
<<
.c{$(INTDIR)}.sbr::
$(CPP) @<<
$(CPP_PROJ) $<
<<
.cpp{$(INTDIR)}.sbr::
$(CPP) @<<
$(CPP_PROJ) $<
<<
.cxx{$(INTDIR)}.sbr::
$(CPP) @<<
$(CPP_PROJ) $<
<<
MTL=midl.exe
MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32
RSC=rc.exe
RSC_PROJ=/l 0x409 /fo"$(INTDIR)\multimon.res" /d "NDEBUG"
BSC32=bscmake.exe
BSC32_FLAGS=/nologo /o"$(OUTDIR)\multimon.bsc"
BSC32_SBRS= \
LINK32=link.exe
LINK32_FLAGS=dxguid.lib odbc32.lib odbccp32.lib dxerr8.lib ddraw.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /incremental:no /pdb:"$(OUTDIR)\multimon.pdb" /machine:I386 /out:"$(OUTDIR)\multimon.exe" /stack:0x200000,0x200000
LINK32_OBJS= \
"$(INTDIR)\multimon.obj" \
"$(INTDIR)\multimon.res"
"$(OUTDIR)\multimon.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ELSEIF "$(CFG)" == "multimon - Win32 Debug"
OUTDIR=.\Debug
INTDIR=.\Debug
# Begin Custom Macros
OutDir=.\Debug
# End Custom Macros
ALL : "$(OUTDIR)\multimon.exe" "$(OUTDIR)\multimon.bsc"
CLEAN :
-@erase "$(INTDIR)\multimon.obj"
-@erase "$(INTDIR)\multimon.res"
-@erase "$(INTDIR)\multimon.sbr"
-@erase "$(INTDIR)\vc60.idb"
-@erase "$(INTDIR)\vc60.pdb"
-@erase "$(OUTDIR)\multimon.bsc"
-@erase "$(OUTDIR)\multimon.exe"
-@erase "$(OUTDIR)\multimon.ilk"
-@erase "$(OUTDIR)\multimon.pdb"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
CPP=cl.exe
CPP_PROJ=/nologo /MLd /W3 /Gm /GX /Zi /Od /I "..\..\common\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FR"$(INTDIR)\\" /Fp"$(INTDIR)\multimon.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
.c{$(INTDIR)}.obj::
$(CPP) @<<
$(CPP_PROJ) $<
<<
.cpp{$(INTDIR)}.obj::
$(CPP) @<<
$(CPP_PROJ) $<
<<
.cxx{$(INTDIR)}.obj::
$(CPP) @<<
$(CPP_PROJ) $<
<<
.c{$(INTDIR)}.sbr::
$(CPP) @<<
$(CPP_PROJ) $<
<<
.cpp{$(INTDIR)}.sbr::
$(CPP) @<<
$(CPP_PROJ) $<
<<
.cxx{$(INTDIR)}.sbr::
$(CPP) @<<
$(CPP_PROJ) $<
<<
MTL=midl.exe
MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32
RSC=rc.exe
RSC_PROJ=/l 0x409 /fo"$(INTDIR)\multimon.res" /d "_DEBUG"
BSC32=bscmake.exe
BSC32_FLAGS=/nologo /o"$(OUTDIR)\multimon.bsc"
BSC32_SBRS= \
"$(INTDIR)\multimon.sbr"
"$(OUTDIR)\multimon.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
$(BSC32) @<<
$(BSC32_FLAGS) $(BSC32_SBRS)
<<
LINK32=link.exe
LINK32_FLAGS=dxguid.lib odbc32.lib odbccp32.lib dxerr8.lib ddraw.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /incremental:yes /pdb:"$(OUTDIR)\multimon.pdb" /debug /machine:I386 /out:"$(OUTDIR)\multimon.exe" /pdbtype:sept /stack:0x200000,0x200000
LINK32_OBJS= \
"$(INTDIR)\multimon.obj" \
"$(INTDIR)\multimon.res"
"$(OUTDIR)\multimon.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ENDIF
!IF "$(NO_EXTERNAL_DEPS)" != "1"
!IF EXISTS("multimon.dep")
!INCLUDE "multimon.dep"
!ELSE
!MESSAGE Warning: cannot find "multimon.dep"
!ENDIF
!ENDIF
!IF "$(CFG)" == "multimon - Win32 Release" || "$(CFG)" == "multimon - Win32 Debug"
SOURCE=.\multimon.cpp
!IF "$(CFG)" == "multimon - Win32 Release"
"$(INTDIR)\multimon.obj" : $(SOURCE) "$(INTDIR)"
!ELSEIF "$(CFG)" == "multimon - Win32 Debug"
"$(INTDIR)\multimon.obj" "$(INTDIR)\multimon.sbr" : $(SOURCE) "$(INTDIR)"
!ENDIF
SOURCE=.\multimon.rc
"$(INTDIR)\multimon.res" : $(SOURCE) "$(INTDIR)"
$(RSC) $(RSC_PROJ) $(SOURCE)
!ENDIF

View File

@@ -0,0 +1,7 @@
#include "resource.h"
IDI_ICON1 ICON DISCARDABLE "directx.ico"
IDB_BITMAP1 BITMAP DISCARDABLE "image1.bmp"
IDB_BITMAP2 BITMAP DISCARDABLE "image2.bmp"

View File

@@ -0,0 +1,74 @@
//-----------------------------------------------------------------------------
//
// Sample Name: Multimon Sample
//
// Copyright (c) 1999-2001 Microsoft Corporation. All rights reserved.
//
//-----------------------------------------------------------------------------
Description
===========
Multimon demonstrates some of the techniques that can be used in writing
an application that takes advantage of multiple monitors.
Path
====
Source: DXSDK\Samples\Multimedia\DDraw\Multimon
Executable: DXSDK\Samples\Multimedia\DDraw\Bin
User's Guide
============
Multimon requires no user input. Press the ESC key to quit the program. Two
"sprites" (moving surfaces) are created. "Sprite 1" uses video memory
whenever possible. "Sprite 2" always uses system memory.
Programming Notes
=================
Multimon shows examples of a variety of topics:
- To use the multimonitor APIs such as GetMonitorInfo and MonitorFromRect
on Windows 95, you can include the file multimon.h. In addition, in one
of the C or C++ files, you need to #define COMPILE_MULTIMON_STUBS before
including multimon.h. This allows the multimon APIs to return reasonable
values when running on Windows 95. If your program does not need to be
compatible with Windows 95, or if you do not use any of the multimonitor
APIs, you do not need to include multimon.h or #define
COMPILE_MULTIMON_STUBS.
- When enumerating DirectDraw devices, you can use either DirectDrawEnumerate
or DirectDrawEnumerateEx. DirectDrawEnumerateEx is available on Windows 98
systems with DX5 and later, and all other systems with DX6 or later.
Because not all systems can be assumed to have DirectDrawEnumerateEx,
DirectDraw was set up so programmers had to use LoadLibrary and
GetProcAddress to check for its presence. In DX7, this restriction has
been removed, so you can call DirectDrawEnumerateEx directly in code, but
you should note that this will prevent your program from running on a system
which does not have at least DX7 installed. This sample shows how to do the
LoadLibrary/GetProcAddress technique, and how to fall back on
DirectDrawEnumerate if DirectDrawEnumerateEx is not available.
- Fullscreen, multimonitor apps need to deal with focus and device windows.
The focus window receives user input messages, and the device windows are
used to cover each screen. This program shows how to call
SetCooperativeLevel to properly create and assign these windows.
- Each screen gets its own DirectDraw interface, and DirectDrawSurfaces created
on one DD interface cannot be used by any other DD interface. So creating
graphics that span multiple monitors takes some extra work. This sample
demonstrates two techniques. For best performance, video memory surfaces
should be used. A separate video memory DirectDrawSurface must be created
on each screen. For the cases where a system memory surface is required or
desired, one must still create separate DirectDrawSurfaces for each screen,
but they can be configured to point to the same surface data memory. The
SetSurfaceDesc API can be used to accomplish this. Doing this has no
performance impact, but it avoids unnecessary consumption of system memory.
- Blt calls usually fail when they would cause data to be written outside the
borders of the destination surface. This failure can be avoided by attaching
clipper objects to the destinations. This sample shows how to create a
clipper for each screen and attach it to the front and back buffers so that
the sprite surfaces can be blitted without being manually clipped by the
application first.

View File

@@ -0,0 +1,3 @@
#define IDI_ICON1 100
#define IDB_BITMAP1 101
#define IDB_BITMAP2 102