You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
617 lines
12 KiB
617 lines
12 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: XBox win32 replacements - Mocks trivial windows flow |
|
// |
|
//=============================================================================// |
|
|
|
#include "pch_tier0.h" |
|
#include "xbox/xbox_win32stubs.h" |
|
#include "tier0/memdbgon.h" |
|
|
|
// On the 360, threads can run on any of 6 logical processors |
|
DWORD g_dwProcessAffinityMask = 0x3F; |
|
|
|
#define HWND_MAGIC 0x12345678 |
|
|
|
struct xWndClass_t |
|
{ |
|
char* pClassName; |
|
WNDPROC wndProc; |
|
xWndClass_t* pNext; |
|
}; |
|
|
|
struct xWnd_t |
|
{ |
|
xWndClass_t* pWndClass; |
|
int x; |
|
int y; |
|
int w; |
|
int h; |
|
long windowLongs[GWL_MAX]; |
|
int show; |
|
int nMagic; |
|
xWnd_t* pNext; |
|
}; |
|
|
|
static xWndClass_t* g_pWndClasses; |
|
static xWnd_t* g_pWnds; |
|
static HWND g_focusWindow; |
|
|
|
inline bool IsWndValid( HWND hWnd ) |
|
{ |
|
if ( !hWnd || ((xWnd_t*)hWnd)->nMagic != HWND_MAGIC ) |
|
return false; |
|
return true; |
|
} |
|
|
|
int MessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType) |
|
{ |
|
XBX_Error( lpText ); |
|
Assert( 0 ); |
|
|
|
return (0); |
|
} |
|
|
|
LONG GetWindowLong(HWND hWnd, int nIndex) |
|
{ |
|
LONG oldLong; |
|
|
|
if ( !IsWndValid( hWnd ) ) |
|
return 0; |
|
|
|
switch (nIndex) |
|
{ |
|
case GWL_WNDPROC: |
|
case GWL_USERDATA: |
|
case GWL_STYLE: |
|
case GWL_EXSTYLE: |
|
oldLong = ((xWnd_t*)hWnd)->windowLongs[nIndex]; |
|
break; |
|
default: |
|
// not implemented |
|
Assert( 0 ); |
|
return 0; |
|
} |
|
|
|
return oldLong; |
|
} |
|
|
|
LONG_PTR GetWindowLongPtr(HWND hWnd, int nIndex) |
|
{ |
|
UINT idx; |
|
|
|
switch ( nIndex ) |
|
{ |
|
case GWLP_WNDPROC: |
|
idx = GWL_WNDPROC; |
|
break; |
|
case GWLP_USERDATA: |
|
idx = GWL_USERDATA; |
|
break; |
|
default: |
|
// not implemented |
|
Assert(0); |
|
return 0; |
|
} |
|
|
|
return GetWindowLong( hWnd, idx ); |
|
} |
|
|
|
LONG_PTR GetWindowLongPtrW(HWND hWnd, int nIndex) |
|
{ |
|
AssertMsg( false, "GetWindowLongPtrW does not exist on Xbox 360." ); |
|
return GetWindowLongPtr( hWnd, nIndex ); |
|
} |
|
|
|
|
|
LONG SetWindowLong(HWND hWnd, int nIndex, LONG dwNewLong) |
|
{ |
|
LONG oldLong; |
|
|
|
if ( !IsWndValid( hWnd ) ) |
|
return 0; |
|
|
|
switch ( nIndex ) |
|
{ |
|
case GWL_WNDPROC: |
|
case GWL_USERDATA: |
|
case GWL_STYLE: |
|
oldLong = ((xWnd_t*)hWnd)->windowLongs[nIndex]; |
|
((xWnd_t*)hWnd)->windowLongs[nIndex] = dwNewLong; |
|
break; |
|
default: |
|
// not implemented |
|
Assert( 0 ); |
|
return 0; |
|
} |
|
|
|
return oldLong; |
|
} |
|
|
|
LONG_PTR SetWindowLongPtr(HWND hWnd, int nIndex, LONG_PTR dwNewLong) |
|
{ |
|
UINT idx; |
|
|
|
switch ( nIndex ) |
|
{ |
|
case GWLP_WNDPROC: |
|
idx = GWL_WNDPROC; |
|
break; |
|
case GWLP_USERDATA: |
|
idx = GWL_USERDATA; |
|
break; |
|
default: |
|
// not implemented |
|
Assert( 0 ); |
|
return 0; |
|
} |
|
|
|
return SetWindowLong( hWnd, idx, dwNewLong ); |
|
} |
|
|
|
LONG_PTR SetWindowLongPtrW(HWND hWnd, int nIndex, LONG_PTR dwNewLong) |
|
{ |
|
AssertMsg( false, "SetWindowLongPtrW does not exist on Xbox 360." ); |
|
return SetWindowLongPtr( hWnd, nIndex, dwNewLong ); |
|
} |
|
|
|
HWND CreateWindow(LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam) |
|
{ |
|
// find classname |
|
xWndClass_t* pWndClass = g_pWndClasses; |
|
while ( pWndClass ) |
|
{ |
|
if ( !stricmp( lpClassName, pWndClass->pClassName ) ) |
|
break; |
|
pWndClass = pWndClass->pNext; |
|
} |
|
if ( !pWndClass ) |
|
{ |
|
// no such class |
|
return (HWND)NULL; |
|
} |
|
|
|
// allocate and setup |
|
xWnd_t* pWnd = new xWnd_t; |
|
memset( pWnd, 0, sizeof(xWnd_t) ); |
|
pWnd->pWndClass = pWndClass; |
|
pWnd->windowLongs[GWL_WNDPROC] = (LONG)pWndClass->wndProc; |
|
pWnd->windowLongs[GWL_STYLE] = dwStyle; |
|
pWnd->x = x; |
|
pWnd->y = y; |
|
pWnd->w = nWidth; |
|
pWnd->h = nHeight; |
|
pWnd->nMagic = HWND_MAGIC; |
|
|
|
// link into list |
|
pWnd->pNext = g_pWnds; |
|
g_pWnds = pWnd; |
|
|
|
// force the focus |
|
g_focusWindow = (HWND)pWnd; |
|
|
|
// send the expected message sequence |
|
SendMessage( (HWND)pWnd, WM_CREATE, 0, 0 ); |
|
SendMessage( (HWND)pWnd, WM_ACTIVATEAPP, TRUE, 0 ); |
|
|
|
return (HWND)pWnd; |
|
} |
|
|
|
HWND CreateWindowEx(DWORD dwExStyle, LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam) |
|
{ |
|
return CreateWindow( lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam ); |
|
} |
|
|
|
BOOL DestroyWindow( HWND hWnd ) |
|
{ |
|
if ( !IsWndValid( hWnd ) ) |
|
return FALSE; |
|
|
|
xWnd_t* pPrev = g_pWnds; |
|
xWnd_t* pCur = g_pWnds; |
|
|
|
while ( pCur ) |
|
{ |
|
if ( pCur == (xWnd_t*)hWnd ) |
|
{ |
|
if ( pPrev == g_pWnds ) |
|
{ |
|
// at head of list, fixup |
|
g_pWnds = pCur->pNext; |
|
} |
|
else |
|
{ |
|
// remove from chain |
|
pPrev->pNext = pCur->pNext; |
|
} |
|
pCur->nMagic = 0; |
|
delete pCur; |
|
break; |
|
} |
|
|
|
// advance through list |
|
pPrev = pCur; |
|
pCur = pCur->pNext; |
|
} |
|
|
|
return TRUE; |
|
} |
|
|
|
ATOM RegisterClassEx(CONST WNDCLASSEX *lpwcx) |
|
{ |
|
// create |
|
xWndClass_t* pWndClass = new xWndClass_t; |
|
memset(pWndClass, 0, sizeof(xWndClass_t)); |
|
pWndClass->pClassName = new char[strlen(lpwcx->lpszClassName)+1]; |
|
strcpy(pWndClass->pClassName, lpwcx->lpszClassName); |
|
pWndClass->wndProc = lpwcx->lpfnWndProc; |
|
|
|
// insert into list |
|
pWndClass->pNext = g_pWndClasses; |
|
g_pWndClasses = pWndClass; |
|
|
|
return (ATOM)pWndClass; |
|
} |
|
|
|
ATOM RegisterClass(CONST WNDCLASS *lpwc) |
|
{ |
|
// create |
|
xWndClass_t* pWndClass = new xWndClass_t; |
|
memset(pWndClass, 0, sizeof(xWndClass_t)); |
|
pWndClass->pClassName = new char[strlen(lpwc->lpszClassName)+1]; |
|
strcpy(pWndClass->pClassName, lpwc->lpszClassName); |
|
pWndClass->wndProc = lpwc->lpfnWndProc; |
|
|
|
// insert into list |
|
pWndClass->pNext = g_pWndClasses; |
|
g_pWndClasses = pWndClass; |
|
|
|
return (ATOM)pWndClass; |
|
} |
|
|
|
HWND GetFocus(VOID) |
|
{ |
|
if ( !IsWndValid( g_focusWindow ) ) |
|
return NULL; |
|
|
|
return g_focusWindow; |
|
} |
|
|
|
HWND SetFocus( HWND hWnd ) |
|
{ |
|
HWND hOldFocus = g_focusWindow; |
|
|
|
if ( IsWndValid( hWnd ) ) |
|
{ |
|
g_focusWindow = hWnd; |
|
} |
|
|
|
return hOldFocus; |
|
} |
|
|
|
|
|
LRESULT CallWindowProc(WNDPROC lpPrevWndFunc, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) |
|
{ |
|
return (lpPrevWndFunc(hWnd, Msg, wParam, lParam)); |
|
} |
|
|
|
int GetSystemMetrics(int nIndex) |
|
{ |
|
XVIDEO_MODE videoMode; |
|
XGetVideoMode( &videoMode ); |
|
// default to having the backbuffer the same as the mode resolution. |
|
int nFrameBufferWidth, nFrameBufferHeight; |
|
nFrameBufferWidth = videoMode.dwDisplayWidth; |
|
nFrameBufferHeight = videoMode.dwDisplayHeight; |
|
|
|
// override for cases where we need to have a different backbuffer either for memory reasons |
|
// or for dealing with anamorphic modes. |
|
if ( !videoMode.fIsWideScreen && videoMode.dwDisplayWidth == 640 && videoMode.dwDisplayHeight == 576 ) |
|
{ |
|
// PAL normal |
|
nFrameBufferWidth = 640; |
|
nFrameBufferHeight = 480; |
|
} |
|
else if ( videoMode.fIsWideScreen && videoMode.dwDisplayWidth == 640 && videoMode.dwDisplayHeight == 576 ) |
|
{ |
|
// PAL widescreen |
|
nFrameBufferWidth = 848; |
|
nFrameBufferHeight = 480; |
|
} |
|
else if ( videoMode.fIsWideScreen && videoMode.dwDisplayWidth == 640 && videoMode.dwDisplayHeight == 480 ) |
|
{ |
|
// anamorphic |
|
nFrameBufferWidth = 848; |
|
nFrameBufferHeight = 480; |
|
} |
|
else if ( videoMode.fIsWideScreen && videoMode.dwDisplayWidth == 1024 && videoMode.dwDisplayHeight == 768 ) |
|
{ |
|
// anamorphic |
|
nFrameBufferWidth = 1280; |
|
nFrameBufferHeight = 720; |
|
} |
|
else if ( videoMode.dwDisplayWidth == 1280 && videoMode.dwDisplayHeight == 760 ) |
|
{ |
|
nFrameBufferWidth = 1280; |
|
nFrameBufferHeight = 720; |
|
} |
|
else if ( videoMode.dwDisplayWidth == 1280 && videoMode.dwDisplayHeight == 768 ) |
|
{ |
|
nFrameBufferWidth = 1280; |
|
nFrameBufferHeight = 720; |
|
} |
|
else if ( !videoMode.fIsWideScreen && videoMode.dwDisplayWidth == 1280 && videoMode.dwDisplayHeight == 1024 ) |
|
{ |
|
nFrameBufferWidth = 1024; |
|
nFrameBufferHeight = 768; |
|
} |
|
else if ( videoMode.fIsWideScreen && videoMode.dwDisplayWidth == 1280 && videoMode.dwDisplayHeight == 1024 ) |
|
{ |
|
// anamorphic |
|
nFrameBufferWidth = 1280; |
|
nFrameBufferHeight = 720; |
|
} |
|
else if ( videoMode.dwDisplayWidth == 1360 && videoMode.dwDisplayHeight == 768 ) |
|
{ |
|
nFrameBufferWidth = 1280; |
|
nFrameBufferHeight = 720; |
|
} |
|
else if ( videoMode.dwDisplayWidth == 1920 && videoMode.dwDisplayHeight == 1080 ) |
|
{ |
|
nFrameBufferWidth = 1280; |
|
nFrameBufferHeight = 720; |
|
} |
|
|
|
switch ( nIndex ) |
|
{ |
|
case SM_CXFIXEDFRAME: |
|
case SM_CYFIXEDFRAME: |
|
case SM_CYSIZE: |
|
return 0; |
|
case SM_CXSCREEN: |
|
return nFrameBufferWidth; |
|
case SM_CYSCREEN: |
|
return nFrameBufferHeight; |
|
} |
|
|
|
// not implemented |
|
Assert( 0 ); |
|
return 0; |
|
} |
|
|
|
BOOL ShowWindow(HWND hWnd, int nCmdShow) |
|
{ |
|
if ( !IsWndValid( hWnd ) ) |
|
return FALSE; |
|
|
|
((xWnd_t*)hWnd)->show = nCmdShow; |
|
|
|
if ((nCmdShow == SW_SHOWDEFAULT) || (nCmdShow == SW_SHOWNORMAL) || (nCmdShow == SW_SHOW)) |
|
g_focusWindow = hWnd; |
|
|
|
return TRUE; |
|
} |
|
|
|
LRESULT SendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) |
|
{ |
|
if ( !IsWndValid( hWnd ) ) |
|
return 0L; |
|
|
|
xWnd_t* pWnd = (xWnd_t*)hWnd; |
|
WNDPROC wndProc = (WNDPROC)pWnd->windowLongs[GWL_WNDPROC]; |
|
Assert( wndProc ); |
|
LRESULT result = wndProc(hWnd, Msg, wParam, lParam); |
|
|
|
return result; |
|
} |
|
|
|
LRESULT SendMessageTimeout( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, UINT fuFlags, UINT uTimeout, PDWORD_PTR lpdwResult ) |
|
{ |
|
*lpdwResult = SendMessage( hWnd, Msg, wParam, lParam ); |
|
|
|
return -1; |
|
} |
|
|
|
BOOL GetClientRect(HWND hWnd, LPRECT lpRect) |
|
{ |
|
if ( !IsWndValid( hWnd ) ) |
|
return FALSE; |
|
|
|
xWnd_t* pWnd = (xWnd_t*)hWnd; |
|
lpRect->left = 0; |
|
lpRect->top = 0; |
|
lpRect->right = pWnd->w; |
|
lpRect->bottom = pWnd->h; |
|
|
|
return TRUE; |
|
} |
|
|
|
int GetDeviceCaps(HDC hdc, int nIndex) |
|
{ |
|
switch (nIndex) |
|
{ |
|
case HORZRES: |
|
return GetSystemMetrics( SM_CXSCREEN ); |
|
case VERTRES: |
|
return GetSystemMetrics( SM_CYSCREEN ); |
|
case VREFRESH: |
|
return 60; |
|
} |
|
|
|
Assert( 0 ); |
|
return 0; |
|
} |
|
|
|
BOOL SetWindowPos( HWND hWnd, HWND hWndInsertAfter, int x, int y, int cx, int cy, UINT uFlags ) |
|
{ |
|
if ( !IsWndValid( hWnd ) ) |
|
return FALSE; |
|
|
|
xWnd_t* pWnd = (xWnd_t*)hWnd; |
|
|
|
if ( !( uFlags & SWP_NOMOVE ) ) |
|
{ |
|
pWnd->x = x; |
|
pWnd->y = y; |
|
} |
|
|
|
if ( !( uFlags & SWP_NOSIZE ) ) |
|
{ |
|
pWnd->w = cx; |
|
pWnd->h = cy; |
|
} |
|
|
|
return TRUE; |
|
} |
|
|
|
int XBX_unlink( const char* filename ) |
|
{ |
|
bool bSuccess = DeleteFile( filename ) != 0; |
|
if ( !bSuccess ) |
|
{ |
|
if ( GetLastError() == ERROR_FILE_NOT_FOUND ) |
|
{ |
|
// not a real failure |
|
return 0; |
|
} |
|
} |
|
// 0 = sucess, -1 = failure |
|
return bSuccess ? 0 : -1; |
|
} |
|
|
|
int XBX_mkdir( const char *pszDir ) |
|
{ |
|
char dirPath[MAX_PATH]; |
|
char* ptr; |
|
BOOL bSuccess; |
|
|
|
// prime and skip to first seperator after the drive path |
|
// must create directory one path at a time |
|
bSuccess = false; |
|
strcpy( dirPath, pszDir ); |
|
ptr = strchr( dirPath, '\\' ); |
|
while ( ptr ) |
|
{ |
|
ptr = strchr( ptr+1, '\\' ); |
|
if ( ptr ) |
|
{ |
|
*ptr = '\0'; |
|
bSuccess = CreateDirectory( dirPath, XBOX_DONTCARE ); |
|
if ( !bSuccess && GetLastError() == ERROR_ALREADY_EXISTS ) |
|
{ |
|
// not a real error |
|
bSuccess = true; |
|
} |
|
*ptr = '\\'; |
|
} |
|
} |
|
|
|
return ( bSuccess ? 0 : -1 ); |
|
} |
|
|
|
char *XBX_getcwd( char *buf, size_t size ) |
|
{ |
|
if ( !buf ) |
|
{ |
|
buf = (char*)malloc( 4 ); |
|
} |
|
strncpy( buf, "D:", size ); |
|
return buf; |
|
} |
|
|
|
int XBX_access( const char *path, int mode ) |
|
{ |
|
if ( !path ) |
|
{ |
|
return -1; |
|
} |
|
|
|
// get the fatx attributes |
|
DWORD dwAttr = GetFileAttributes( path ); |
|
if ( dwAttr == (DWORD)-1 ) |
|
{ |
|
return -1; |
|
} |
|
|
|
if ( mode == 0 ) |
|
{ |
|
// is file exist? |
|
return 0; |
|
} |
|
else if ( mode == 2 ) |
|
{ |
|
// is file write only? |
|
return -1; |
|
} |
|
else if ( mode == 4 ) |
|
{ |
|
// is file read only? |
|
if ( dwAttr & FILE_ATTRIBUTE_READONLY ) |
|
return 0; |
|
else |
|
return -1; |
|
} |
|
else if ( mode == 6 ) |
|
{ |
|
// is file read and write? |
|
if ( !( dwAttr & FILE_ATTRIBUTE_READONLY ) ) |
|
return 0; |
|
else |
|
return -1; |
|
} |
|
|
|
return -1; |
|
} |
|
|
|
DWORD XBX_GetCurrentDirectory( DWORD nBufferLength, LPTSTR lpBuffer ) |
|
{ |
|
XBX_getcwd( lpBuffer, nBufferLength ); |
|
return strlen( lpBuffer ); |
|
} |
|
|
|
DWORD XBX_GetModuleFileName( HMODULE hModule, LPTSTR lpFilename, DWORD nSize ) |
|
{ |
|
int len; |
|
char *pStr; |
|
char *pEnd; |
|
char xexName[MAX_PATH]; |
|
|
|
if ( hModule == GetModuleHandle( NULL ) ) |
|
{ |
|
// isolate xex of command line |
|
pStr = GetCommandLine(); |
|
if ( pStr ) |
|
{ |
|
// cull possible quotes around xex |
|
if ( pStr[0] == '\"' ) |
|
{ |
|
pStr++; |
|
pEnd = strchr( pStr, '\"' ); |
|
if ( !pEnd ) |
|
{ |
|
// no ending matching quote |
|
return 0; |
|
} |
|
} |
|
else |
|
{ |
|
// find possible first argument |
|
pEnd = strchr( lpFilename, ' ' ); |
|
if ( !pEnd ) |
|
{ |
|
pEnd = pStr+strlen( pStr ); |
|
} |
|
} |
|
len = pEnd-pStr; |
|
memcpy( xexName, pStr, len ); |
|
xexName[len] = '\0'; |
|
|
|
len = _snprintf( lpFilename, nSize, "D:\\%s", xexName ); |
|
if ( len == -1 ) |
|
lpFilename[nSize-1] = '\0'; |
|
|
|
return strlen( lpFilename ); |
|
} |
|
} |
|
return 0; |
|
}
|
|
|