SRB2/src/win32ce/win_main.c
2014-03-15 13:11:35 -04:00

539 lines
13 KiB
C

// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// Copyright (C) 1998-2000 by DooM Legacy Team.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//-----------------------------------------------------------------------------
/// \file
/// \brief Win32 WinMain Entry Point
///
/// Win32 Sonic Robo Blast 2
///
/// NOTE:
/// To compile WINDOWS SRB2 version : define a '_WINDOWS' symbol.
/// to do this go to Project/Settings/ menu, click C/C++ tab, in
/// 'Preprocessor definitions:' add '_WINDOWS'
#include "../doomdef.h"
#include <stdio.h>
#include "../doomstat.h" // netgame
#include "resource.h"
#include "../m_argv.h"
#include "../d_main.h"
#include "../i_system.h"
#include "../keys.h" //hack quick test
#include "../console.h"
#include "fabdxlib.h"
#include "win_main.h"
#include "win_dbg.h"
#include "../i_sound.h" // midi pause/unpause
#include "../g_input.h" // KEY_MOUSEWHEELxxx
// MSWheel support for Win95/NT3.51
#include <zmouse.h>
#ifndef WM_XBUTTONDOWN
#define WM_XBUTTONDOWN 523
#endif
#ifndef WM_XBUTTONUP
#define WM_XBUTTONUP 524
#endif
#ifndef MK_XBUTTON1
#define MK_XBUTTON1 32
#endif
#ifndef MK_XBUTTON2
#define MK_XBUTTON2 64
#endif
typedef BOOL (WINAPI *MyFunc)(VOID);
HINSTANCE myInstance = NULL;
HWND hWndMain = NULL;
static HCURSOR windowCursor = NULL; // main window cursor
boolean appActive = false; // app window is active
#ifdef LOGMESSAGES
// this is were I log debug text, cons_printf, I_error ect for window port debugging
HANDLE logstream;
#endif
BOOL nodinput = FALSE;
static LRESULT CALLBACK MainWndproc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
event_t ev; //Doom input event
int mouse_keys;
// judgecutor:
// Response MSH Mouse Wheel event
if (message == MSHWheelMessage)
{
message = WM_MOUSEWHEEL;
if (win9x)
wParam <<= 16;
}
switch (message)
{
case WM_CREATE:
nodinput = M_CheckParm("-nodinput");
break;
case WM_ACTIVATEAPP: // Handle task switching
appActive = (int)wParam;
// pause music when alt-tab
if (appActive && !paused)
I_ResumeSong(0);
else if (!paused)
I_PauseSong(0);
{
HANDLE ci = GetStdHandle(STD_INPUT_HANDLE);
if (ci != INVALID_HANDLE_VALUE && GetFileType(ci) == FILE_TYPE_CHAR)
appActive = true;
}
InvalidateRect (hWnd, NULL, TRUE);
break;
//for MIDI music
case WM_MSTREAM_UPDATEVOLUME:
I_SetMidiChannelVolume((DWORD)wParam, dwVolumePercent);
break;
case WM_PAINT:
if (!appActive && !bAppFullScreen && !netgame)
// app becomes inactive (if windowed)
{
// Paint "Game Paused" in the middle of the screen
PAINTSTRUCT ps;
RECT rect;
HDC hdc = BeginPaint (hWnd, &ps);
GetClientRect (hWnd, &rect);
DrawText (hdc, TEXT("Game Paused"), -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint (hWnd, &ps);
return 0;
}
break;
//case WM_RBUTTONDOWN:
//case WM_LBUTTONDOWN:
case WM_MOVE:
if (bAppFullScreen)
{
SetWindowPos(hWnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
return 0;
}
else
{
windowPosX = (SHORT) LOWORD(lParam); // horizontal position
windowPosY = (SHORT) HIWORD(lParam); // vertical position
break;
}
break;
// This is where switching windowed/fullscreen is handled. DirectDraw
// objects must be destroyed, recreated, and artwork reloaded.
case WM_DISPLAYCHANGE:
case WM_SIZE:
break;
case WM_SETCURSOR:
if (bAppFullScreen)
SetCursor(NULL);
else
SetCursor(windowCursor);
return TRUE;
case WM_KEYUP:
ev.type = ev_keyup;
goto handleKeyDoom;
break;
case WM_KEYDOWN:
ev.type = ev_keydown;
handleKeyDoom:
ev.data1 = 0;
if (wParam == VK_PAUSE)
// intercept PAUSE key
{
ev.data1 = KEY_PAUSE;
}
else if (!keyboard_started)
// post some keys during the game startup
// (allow escaping from network synchronization, or pressing enter after
// an error message in the console)
{
switch (wParam)
{
case VK_ESCAPE: ev.data1 = KEY_ESCAPE; break;
case VK_RETURN: ev.data1 = KEY_ENTER; break;
default: ev.data1 = MapVirtualKey((DWORD)wParam,2); // convert in to char
}
}
if (ev.data1)
D_PostEvent (&ev);
return 0;
break;
// judgecutor:
// Handle mouse events
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_XBUTTONDOWN:
case WM_XBUTTONUP:
case WM_MOUSEMOVE:
if (nodinput)
{
mouse_keys = 0;
if (wParam & MK_LBUTTON)
mouse_keys |= 1;
if (wParam & MK_RBUTTON)
mouse_keys |= 2;
if (wParam & MK_MBUTTON)
mouse_keys |= 4;
if (wParam & MK_XBUTTON1)
mouse_keys |= 8;
if (wParam & MK_XBUTTON2)
mouse_keys |= 16;
I_GetSysMouseEvents(mouse_keys);
}
break;
case WM_MOUSEWHEEL:
//CONS_Printf("MW_WHEEL dispatched.\n");
ev.type = ev_keydown;
if ((INT16)HIWORD(wParam) > 0)
ev.data1 = KEY_MOUSEWHEELUP;
else
ev.data1 = KEY_MOUSEWHEELDOWN;
D_PostEvent(&ev);
break;
case WM_SETTEXT:
COM_BufAddText((LPCSTR)lParam);
return TRUE;
break;
case WM_CLOSE:
PostQuitMessage(0); //to quit while in-game
ev.data1 = KEY_ESCAPE; //to exit network synchronization
ev.type = ev_keydown;
D_PostEvent (&ev);
return 0;
case WM_DESTROY:
//faB: main app loop will exit the loop and proceed with I_Quit()
PostQuitMessage(0);
break;
default:
break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
static inline VOID OpenTextConsole(void)
{
HANDLE ci, co;
const BOOL tco = M_CheckParm("-console") != 0;
dedicated = M_CheckParm("-dedicated") != 0;
if (!(dedicated || tco))
return;
FreeConsole();
AllocConsole(); //Let get the real console HANDLE, because Mingw's Bash is bad!
ci = CreateFile(TEXT("CONIN$") , GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
co = CreateFile(TEXT("CONOUT$"), GENERIC_WRITE|GENERIC_READ, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (ci != (HANDLE)-1)
{
const DWORD CM = ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT|ENABLE_PROCESSED_INPUT;
SetStdHandle(STD_INPUT_HANDLE,ci);
if(GetFileType(ci) == FILE_TYPE_CHAR)
SetConsoleMode(ci,CM); //default mode but no ENABLE_MOUSE_INPUT
}
if(co != (HANDLE)-1)
{
SetStdHandle(STD_OUTPUT_HANDLE,co);
SetStdHandle(STD_ERROR_HANDLE,co); //maybe logstream?
}
}
//
// Do that Windows initialization stuff...
//
static HWND OpenMainWindow (HINSTANCE hInstance, int nCmdShow, LPSTR wTitle)
{
HWND hWnd;
WNDCLASS wc;
// Set up and register window class
nCmdShow = 0;
wc.style = CS_HREDRAW | CS_VREDRAW /*| CS_DBLCLKS*/;
wc.lpfnWndProc = MainWndproc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_DLICON1));
windowCursor = LoadCursor(NULL, IDC_WAIT); //LoadCursor(hInstance, MAKEINTRESOURCE(IDC_DLCURSOR1));
wc.hCursor = windowCursor;
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = TEXT("SRB2WC");
if (!RegisterClass(&wc))
return (HANDLE)-1;
// Create a window
// CreateWindowEx - seems to create just the interior, not the borders
hWnd = CreateWindowExA(
#ifdef _DEBUG
0, //ExStyle
#else
dedicated ? 0:WS_EX_TOPMOST, //ExStyle
#endif
"SRB2WC", //Classname
wTitle, //Windowname
WS_CAPTION|WS_POPUP|WS_SYSMENU, //dwStyle //WS_VISIBLE|WS_POPUP for bAppFullScreen
0,
0,
dedicated ? 0:BASEVIDWIDTH, //GetSystemMetrics(SM_CXSCREEN),
dedicated ? 0:BASEVIDHEIGHT, //GetSystemMetrics(SM_CYSCREEN),
NULL, //hWnd Parent
NULL, //hMenu Menu
hInstance,
NULL);
return hWnd;
}
static inline BOOL tlErrorMessage(const TCHAR *err)
{
/* make the cursor visible */
SetCursor(LoadCursor(NULL, IDC_ARROW));
//
// warn user if there is one
//
printf("Error %s..\n", err);
fflush(stdout);
MessageBox(hWndMain, err, TEXT("ERROR"), MB_OK);
return FALSE;
}
// ------------------
// Command line stuff
// ------------------
#define MAXCMDLINEARGS 64
static char * myWargv[MAXCMDLINEARGS+1];
static char myCmdline[512];
static VOID GetArgcArgv (LPSTR cmdline)
{
LPSTR token;
size_t i = 0, len;
char cSep = ' ';
BOOL bCvar = FALSE, prevCvar = FALSE;
// split arguments of command line into argv
strncpy (myCmdline, cmdline, 511); // in case window's cmdline is in protected memory..for strtok
len = strlen (myCmdline);
myargc = 0;
while (myargc < MAXCMDLINEARGS)
{
// get token
while (myCmdline[i] == cSep)
i++;
if (i >= len)
break;
token = myCmdline + i;
if (myCmdline[i] == '"')
{
cSep = '"';
i++;
if (!prevCvar) //cvar leave the "" in
token++;
}
else
cSep = ' ';
//cvar
if (myCmdline[i] == '+' && cSep == ' ') //a + begins a cvarname, but not after quotes
bCvar = TRUE;
else
bCvar = FALSE;
while (myCmdline[i] &&
myCmdline[i] != cSep)
i++;
if (myCmdline[i] == '"')
{
cSep = ' ';
if (prevCvar)
i++; // get ending " quote in arg
}
prevCvar = bCvar;
if (myCmdline + i > token)
{
myWargv[myargc++] = token;
}
if (!myCmdline[i] || i >= len)
break;
myCmdline[i++] = '\0';
}
myWargv[myargc] = NULL;
// m_argv.c uses myargv[], we used myWargv because we fill the arguments ourselves
// and myargv is just a pointer, so we set it to point myWargv
myargv = myWargv;
}
static inline VOID MakeCodeWritable(VOID)
{
#ifdef USEASM
// Disable write-protection of code segment
DWORD OldRights;
BYTE *pBaseOfImage = (BYTE *)GetModuleHandle(NULL);
IMAGE_OPTIONAL_HEADER *pHeader = (IMAGE_OPTIONAL_HEADER *)
(pBaseOfImage + ((IMAGE_DOS_HEADER*)pBaseOfImage)->e_lfanew +
sizeof (IMAGE_NT_SIGNATURE) + sizeof (IMAGE_FILE_HEADER));
if (!VirtualProtect(pBaseOfImage+pHeader->BaseOfCode,pHeader->SizeOfCode,PAGE_EXECUTE_READWRITE,&OldRights))
I_Error("Could not make code writable\n");
#endif
}
// -----------------------------------------------------------------------------
// HandledWinMain : called by exception handler
// -----------------------------------------------------------------------------
static int WINAPI HandledWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
int i;
LPSTR args;
lpCmdLine = NULL;
hPrevInstance = NULL;
#ifdef LOGMESSAGES
// DEBUG!!! - set logstream to NULL to disable debug log
logstream = INVALID_HANDLE_VALUE;
logstream = CreateFile (TEXT("log.txt"), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL); //file flag writethrough?
#endif
// fill myargc,myargv for m_argv.c retrieval of cmdline arguments
CONS_Printf("GetArgcArgv() ...\n");
args = GetCommandLineA();
CONS_Printf("lpCmdLine is '%s'\n", args);
GetArgcArgv(args);
// Create a text console window
OpenTextConsole();
CONS_Printf("Myargc: %d\n", myargc);
for (i = 0; i < myargc; i++)
CONS_Printf("myargv[%d] : '%s'\n", i, myargv[i]);
// store for later use, will we need it ?
myInstance = hInstance;
// open a dummy window, both OpenGL and DirectX need one.
if ((hWndMain = OpenMainWindow(hInstance,nCmdShow,
va("SRB2 "VERSIONSTRING))) == (HANDLE)-1)
{
tlErrorMessage(TEXT("Couldn't open window"));
return FALSE;
}
// currently starts DirectInput
CONS_Printf("I_StartupSystem() ...\n");
I_StartupSystem();
MakeCodeWritable();
// startup SRB2
CONS_Printf("D_SRB2Main() ...\n");
D_SRB2Main();
CONS_Printf("Entering main app loop...\n");
// never return
D_SRB2Loop();
// back to Windoze
return 0;
}
// -----------------------------------------------------------------------------
// Exception handler calls WinMain for catching exceptions
// -----------------------------------------------------------------------------
int WINAPI WinMain (HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
int Result = -1;
#if 1
HMODULE h = GetModuleHandleA("kernel32.dll");
MyFunc pfnIsDebuggerPresent = NULL;
if (h)
pfnIsDebuggerPresent = (MyFunc)GetProcAddress(h,"IsDebuggerPresent");
if (!pfnIsDebuggerPresent || !pfnIsDebuggerPresent())
LoadLibrary("exchndl.dll");
#endif
#ifdef NO_SEH_MINGW
__try1(RecordExceptionInfo(GetExceptionInformation()/*, "main thread", lpCmdLine*/))
#else
__try
#endif
{
Result = HandledWinMain (hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
#ifdef NO_SEH_MINGW
__except1
#else
__except (RecordExceptionInfo(GetExceptionInformation()/*, "main thread", lpCmdLine*/))
#endif
{
SetUnhandledExceptionFilter(EXCEPTION_CONTINUE_SEARCH); //Do nothing here.
}
return Result;
}