Changes to be committed: modified: include/winprocs.h modified: src/options.c modified: sys/share/pcmain.c new file: sys/share/safeproc.c modified: sys/winnt/Makefile.msc modified: sys/winnt/stubs.c new file: sys/winnt/windmain.c modified: sys/winnt/winnt.c modified: win/win32/vs2017/NetHack.vcxproj modified: win/win32/vs2017/NetHackW.vcxproj modified: win/win32/winhack.c Because multiple window ports are supported on Windows now, even in the same executable and selectable via config file in some cases, some adjustments became necessary. There will likely be some further refining of this over the next day or two. List of changes: Move Windows startup from sys/share/pcmain.c and into its own sys/winnt/windmain.c so that it can be modified to fix some current breakage, and allow altering the order of some things. There is startup processing code that is common to all of the Windows WindowPorts, but that startup processing code needs to have no dependency on any one of those WindowPorts. Yet, during startup processing, some of the initialization routines can end up calling NetHack functions that expect an active Window port underneath, and if there isn't one, routines like pline, impossible, panic can end up invoking null function pointers. Place a new file sys/share/safeproc.c, in which a complete window port is available for early startup processing purposes. It's WindowPort name field is set to "safe-startup" just for reference. The prototypes in include/winprocs.h require that SAFEPROCS be Usage: windowprocs = get_safe_procs(0); initializes a set of winprocs function pointers that ensure none of the function pointers are left null, but that's all it does. windowprocs = get_safe_procs(1); initializes a set of winprocs functions pointers that ensure none of the function pointers are left null, but also provides some basic output and input functionality using nothing other than C stdio routines (no platform or OS specific code). The conditional code related to WIN32 has been removed from sys/share/pcmain.c The code common to all of the Windows WindowPorts calls get_safe_procs() almost immediately to ensure that there is a set of WindowPort winprocs available.
426 lines
13 KiB
C
426 lines
13 KiB
C
/* NetHack 3.6 winhack.c $NHDT-Date: 1449488876 2015/12/07 11:47:56 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.44 $ */
|
|
/* Copyright (C) 2001 by Alex Kompel */
|
|
/* NetHack may be freely redistributed. See license for details. */
|
|
|
|
// winhack.cpp : Defines the entry point for the application.
|
|
//
|
|
|
|
#include "win10.h"
|
|
#include <process.h>
|
|
|
|
#include "winMS.h"
|
|
#include "hack.h"
|
|
#include "dlb.h"
|
|
#include "resource.h"
|
|
#include "mhmain.h"
|
|
#include "mhmap.h"
|
|
|
|
#if !defined(SAFEPROCS)
|
|
#error You must #define SAFEPROCS to build winhack.c
|
|
#endif
|
|
|
|
/* Borland and MinGW redefine "boolean" in shlwapi.h,
|
|
so just use the little bit we need */
|
|
typedef struct _DLLVERSIONINFO {
|
|
DWORD cbSize;
|
|
DWORD dwMajorVersion; // Major version
|
|
DWORD dwMinorVersion; // Minor version
|
|
DWORD dwBuildNumber; // Build number
|
|
DWORD dwPlatformID; // DLLVER_PLATFORM_*
|
|
} DLLVERSIONINFO;
|
|
|
|
//
|
|
// The caller should always GetProcAddress("DllGetVersion"), not
|
|
// implicitly link to it.
|
|
//
|
|
|
|
typedef HRESULT(CALLBACK *DLLGETVERSIONPROC)(DLLVERSIONINFO *);
|
|
|
|
/* end of shlwapi.h */
|
|
|
|
/* Minimal common control library version
|
|
Version _WIN_32IE Platform/IE
|
|
======= ========= ===========
|
|
4.00 0x0200 Microsoft(r) Windows 95/Windows NT 4.0
|
|
4.70 0x0300 Microsoft(r) Internet Explorer 3.x
|
|
4.71 0x0400 Microsoft(r) Internet Explorer 4.0
|
|
4.72 0x0401 Microsoft(r) Internet Explorer 4.01
|
|
...and probably going on infinitely...
|
|
*/
|
|
#define MIN_COMCTLMAJOR 4
|
|
#define MIN_COMCTLMINOR 71
|
|
#define INSTALL_NOTES "http://www.nethack.org/v340/ports/download-win.html#cc"
|
|
/*#define COMCTL_URL
|
|
* "http://www.microsoft.com/msdownload/ieplatform/ie/comctrlx86.asp"*/
|
|
|
|
extern void FDECL(nethack_exit, (int));
|
|
static TCHAR *_get_cmd_arg(TCHAR *pCmdLine);
|
|
static HRESULT GetComCtlVersion(LPDWORD pdwMajor, LPDWORD pdwMinor);
|
|
BOOL WINAPI
|
|
_nhapply_image_transparent(HDC hDC, int x, int y, int width, int height,
|
|
HDC sourceDC, int s_x, int s_y, int s_width,
|
|
int s_height, UINT cTransparent);
|
|
|
|
// Global Variables:
|
|
NHWinApp _nethack_app;
|
|
|
|
#ifdef __BORLANDC__
|
|
#define _stricmp(s1, s2) stricmp(s1, s2)
|
|
#define _strdup(s1) strdup(s1)
|
|
#endif
|
|
|
|
// Foward declarations of functions included in this code module:
|
|
extern boolean FDECL(main, (int, char **));
|
|
static void __cdecl mswin_moveloop(void *);
|
|
|
|
#define MAX_CMDLINE_PARAM 255
|
|
|
|
int APIENTRY
|
|
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
|
|
int nCmdShow)
|
|
{
|
|
INITCOMMONCONTROLSEX InitCtrls;
|
|
int argc;
|
|
char *argv[MAX_CMDLINE_PARAM];
|
|
size_t len;
|
|
TCHAR *p;
|
|
TCHAR wbuf[BUFSZ];
|
|
char buf[BUFSZ];
|
|
|
|
DWORD major, minor;
|
|
/* OSVERSIONINFO osvi; */
|
|
|
|
UNREFERENCED_PARAMETER(hPrevInstance);
|
|
UNREFERENCED_PARAMETER(lpCmdLine);
|
|
UNREFERENCED_PARAMETER(nCmdShow);
|
|
|
|
/*
|
|
* Get a set of valid safe windowport function
|
|
* pointers during early startup initialization.
|
|
*
|
|
* When get_safe_procs is called with 0 as the param,
|
|
* non-functional, but safe function pointers are set
|
|
* for all windowport routines.
|
|
*
|
|
* When get_safe_procs is called with 1 as the param,
|
|
* raw_print, raw_print_bold, and wait_synch, and nhgetch
|
|
* are set to use C stdio routines via stdio_raw_print,
|
|
* stdio_raw_print_bold, stdio_wait_synch, and
|
|
* stdio_nhgetch.
|
|
*/
|
|
windowprocs = *get_safe_procs(0);
|
|
|
|
/*
|
|
* Now we are going to override a couple
|
|
* of the windowprocs functions so that
|
|
* error messages are handled in a suitable
|
|
* way for the graphical version.
|
|
*/
|
|
windowprocs.win_raw_print = mswin_raw_print;
|
|
windowprocs.win_raw_print_bold = mswin_raw_print_bold;
|
|
windowprocs.win_wait_synch = mswin_wait_synch;
|
|
|
|
win10_init();
|
|
sys_early_init();
|
|
|
|
/* init application structure */
|
|
_nethack_app.hApp = hInstance;
|
|
_nethack_app.hAccelTable =
|
|
LoadAccelerators(hInstance, (LPCTSTR) IDC_NETHACKW);
|
|
_nethack_app.hMainWnd = NULL;
|
|
_nethack_app.hPopupWnd = NULL;
|
|
_nethack_app.bmpTiles = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TILES));
|
|
if (_nethack_app.bmpTiles == NULL)
|
|
panic("cannot load tiles bitmap");
|
|
_nethack_app.bmpPetMark =
|
|
LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_PETMARK));
|
|
if (_nethack_app.bmpPetMark == NULL)
|
|
panic("cannot load pet mark bitmap");
|
|
#ifdef USE_PILEMARK
|
|
_nethack_app.bmpPileMark =
|
|
LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_PILEMARK));
|
|
if (_nethack_app.bmpPileMark == NULL)
|
|
panic("cannot load pile mark bitmap");
|
|
#endif
|
|
_nethack_app.bmpRip = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_RIP));
|
|
if (_nethack_app.bmpRip == NULL)
|
|
panic("cannot load rip bitmap");
|
|
_nethack_app.bmpSplash =
|
|
LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_SPLASH));
|
|
if (_nethack_app.bmpSplash == NULL)
|
|
panic("cannot load splash bitmap");
|
|
_nethack_app.bmpMapTiles = _nethack_app.bmpTiles;
|
|
_nethack_app.mapTile_X = TILE_X;
|
|
_nethack_app.mapTile_Y = TILE_Y;
|
|
_nethack_app.mapTilesPerLine = TILES_PER_LINE;
|
|
|
|
_nethack_app.bNoHScroll = FALSE;
|
|
_nethack_app.bNoVScroll = FALSE;
|
|
_nethack_app.saved_text = strdup("");
|
|
|
|
_nethack_app.bAutoLayout = TRUE;
|
|
_nethack_app.bWindowsLocked = TRUE;
|
|
|
|
_nethack_app.bNoSounds = FALSE;
|
|
|
|
#if 0 /* GdiTransparentBlt does not render spash bitmap for whatever reason */
|
|
/* use system-provided TransparentBlt for Win2k+ */
|
|
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
|
|
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
GetVersionEx(&osvi);
|
|
if (osvi.dwMajorVersion >= 5)
|
|
_nethack_app.lpfnTransparentBlt = GdiTransparentBlt;
|
|
else
|
|
#endif
|
|
_nethack_app.lpfnTransparentBlt = _nhapply_image_transparent;
|
|
|
|
// init controls
|
|
if (FAILED(GetComCtlVersion(&major, &minor))) {
|
|
char buf[TBUFSZ];
|
|
Sprintf(buf, "Cannot load common control library.\n%s\n%s",
|
|
"For further information, refer to the installation notes at",
|
|
INSTALL_NOTES);
|
|
panic(buf);
|
|
}
|
|
if (major < MIN_COMCTLMAJOR
|
|
|| (major == MIN_COMCTLMAJOR && minor < MIN_COMCTLMINOR)) {
|
|
char buf[TBUFSZ];
|
|
Sprintf(buf, "Common control library is outdated.\n%s %d.%d\n%s\n%s",
|
|
"NetHack requires at least version ", MIN_COMCTLMAJOR,
|
|
MIN_COMCTLMINOR,
|
|
"For further information, refer to the installation notes at",
|
|
INSTALL_NOTES);
|
|
panic(buf);
|
|
}
|
|
ZeroMemory(&InitCtrls, sizeof(InitCtrls));
|
|
InitCtrls.dwSize = sizeof(InitCtrls);
|
|
InitCtrls.dwICC = ICC_LISTVIEW_CLASSES;
|
|
InitCommonControlsEx(&InitCtrls);
|
|
|
|
/* get command line parameters */
|
|
p = _get_cmd_arg(GetCommandLine());
|
|
p = _get_cmd_arg(NULL); /* skip first paramter - command name */
|
|
for (argc = 1; p && argc < MAX_CMDLINE_PARAM; argc++) {
|
|
len = _tcslen(p);
|
|
if (len > 0) {
|
|
argv[argc] = _strdup(NH_W2A(p, buf, BUFSZ));
|
|
} else {
|
|
argv[argc] = "";
|
|
}
|
|
p = _get_cmd_arg(NULL);
|
|
}
|
|
GetModuleFileName(NULL, wbuf, BUFSZ);
|
|
argv[0] = _strdup(NH_W2A(wbuf, buf, BUFSZ));
|
|
|
|
if (argc == 2) {
|
|
TCHAR *savefile = strdup(argv[1]);
|
|
TCHAR *plname;
|
|
for (p = savefile; *p && *p != '-'; p++)
|
|
;
|
|
if (*p) {
|
|
/* we found a '-' */
|
|
plname = p + 1;
|
|
for (p = plname; *p && *p != '.'; p++)
|
|
;
|
|
if (*p) {
|
|
if (strcmp(p + 1, "NetHack-saved-game") == 0) {
|
|
*p = '\0';
|
|
argv[1] = "-u";
|
|
argv[2] = _strdup(plname);
|
|
argc = 3;
|
|
}
|
|
}
|
|
}
|
|
free(savefile);
|
|
}
|
|
|
|
/* let main do the argument processing */
|
|
(void) main(argc, argv);
|
|
return 0;
|
|
}
|
|
|
|
PNHWinApp
|
|
GetNHApp()
|
|
{
|
|
return &_nethack_app;
|
|
}
|
|
|
|
TCHAR *
|
|
_get_cmd_arg(TCHAR *pCmdLine)
|
|
{
|
|
static TCHAR *pArgs = NULL;
|
|
TCHAR *pRetArg;
|
|
BOOL bQuoted;
|
|
|
|
if (!pCmdLine && !pArgs)
|
|
return NULL;
|
|
if (!pArgs)
|
|
pArgs = pCmdLine;
|
|
|
|
/* skip whitespace */
|
|
for (pRetArg = pArgs; *pRetArg && _istspace(*pRetArg);
|
|
pRetArg = CharNext(pRetArg))
|
|
;
|
|
if (!*pRetArg) {
|
|
pArgs = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
/* check for quote */
|
|
if (*pRetArg == TEXT('"')) {
|
|
bQuoted = TRUE;
|
|
pRetArg = CharNext(pRetArg);
|
|
pArgs = _tcschr(pRetArg, TEXT('"'));
|
|
} else {
|
|
/* skip to whitespace */
|
|
for (pArgs = pRetArg; *pArgs && !_istspace(*pArgs);
|
|
pArgs = CharNext(pArgs))
|
|
;
|
|
}
|
|
|
|
if (pArgs && *pArgs) {
|
|
TCHAR *p;
|
|
p = pArgs;
|
|
pArgs = CharNext(pArgs);
|
|
*p = (TCHAR) 0;
|
|
} else {
|
|
pArgs = NULL;
|
|
}
|
|
|
|
return pRetArg;
|
|
}
|
|
|
|
/* Get the version of the Common Control library on this machine.
|
|
Copied from the Microsoft SDK
|
|
*/
|
|
HRESULT
|
|
GetComCtlVersion(LPDWORD pdwMajor, LPDWORD pdwMinor)
|
|
{
|
|
HINSTANCE hComCtl;
|
|
HRESULT hr = S_OK;
|
|
DLLGETVERSIONPROC pDllGetVersion;
|
|
|
|
if (IsBadWritePtr(pdwMajor, sizeof(DWORD))
|
|
|| IsBadWritePtr(pdwMinor, sizeof(DWORD)))
|
|
return E_INVALIDARG;
|
|
// load the DLL
|
|
hComCtl = LoadLibrary(TEXT("comctl32.dll"));
|
|
if (!hComCtl)
|
|
return E_FAIL;
|
|
|
|
/*
|
|
You must get this function explicitly because earlier versions of the DLL
|
|
don't implement this function. That makes the lack of implementation of
|
|
the
|
|
function a version marker in itself.
|
|
*/
|
|
pDllGetVersion =
|
|
(DLLGETVERSIONPROC) GetProcAddress(hComCtl, TEXT("DllGetVersion"));
|
|
if (pDllGetVersion) {
|
|
DLLVERSIONINFO dvi;
|
|
ZeroMemory(&dvi, sizeof(dvi));
|
|
dvi.cbSize = sizeof(dvi);
|
|
hr = (*pDllGetVersion)(&dvi);
|
|
if (SUCCEEDED(hr)) {
|
|
*pdwMajor = dvi.dwMajorVersion;
|
|
*pdwMinor = dvi.dwMinorVersion;
|
|
} else {
|
|
hr = E_FAIL;
|
|
}
|
|
} else {
|
|
/*
|
|
If GetProcAddress failed, then the DLL is a version previous to the
|
|
one
|
|
shipped with IE 3.x.
|
|
*/
|
|
*pdwMajor = 4;
|
|
*pdwMinor = 0;
|
|
}
|
|
FreeLibrary(hComCtl);
|
|
return hr;
|
|
}
|
|
|
|
/* apply bitmap pointed by sourceDc transparently over
|
|
bitmap pointed by hDC */
|
|
BOOL WINAPI
|
|
_nhapply_image_transparent(HDC hDC, int x, int y, int width, int height,
|
|
HDC sourceDC, int s_x, int s_y, int s_width,
|
|
int s_height, UINT cTransparent)
|
|
{
|
|
/* Don't use TransparentBlt; According to Microsoft, it contains a memory
|
|
* leak in Window 95/98. */
|
|
HDC hdcMem, hdcBack, hdcObject, hdcSave;
|
|
COLORREF cColor;
|
|
HBITMAP bmAndBack, bmAndObject, bmAndMem, bmSave;
|
|
HBITMAP bmBackOld, bmObjectOld, bmMemOld, bmSaveOld;
|
|
|
|
/* Create some DCs to hold temporary data. */
|
|
hdcBack = CreateCompatibleDC(hDC);
|
|
hdcObject = CreateCompatibleDC(hDC);
|
|
hdcMem = CreateCompatibleDC(hDC);
|
|
hdcSave = CreateCompatibleDC(hDC);
|
|
|
|
/* this is bitmap for our pet image */
|
|
bmSave = CreateCompatibleBitmap(hDC, width, height);
|
|
|
|
/* Monochrome DC */
|
|
bmAndBack = CreateBitmap(width, height, 1, 1, NULL);
|
|
bmAndObject = CreateBitmap(width, height, 1, 1, NULL);
|
|
|
|
/* resulting bitmap */
|
|
bmAndMem = CreateCompatibleBitmap(hDC, width, height);
|
|
|
|
/* Each DC must select a bitmap object to store pixel data. */
|
|
bmBackOld = SelectObject(hdcBack, bmAndBack);
|
|
bmObjectOld = SelectObject(hdcObject, bmAndObject);
|
|
bmMemOld = SelectObject(hdcMem, bmAndMem);
|
|
bmSaveOld = SelectObject(hdcSave, bmSave);
|
|
|
|
/* copy source image because it is going to be overwritten */
|
|
StretchBlt(hdcSave, 0, 0, width, height, sourceDC, s_x, s_y, s_width,
|
|
s_height, SRCCOPY);
|
|
|
|
/* Set the background color of the source DC to the color.
|
|
contained in the parts of the bitmap that should be transparent */
|
|
cColor = SetBkColor(hdcSave, cTransparent);
|
|
|
|
/* Create the object mask for the bitmap by performing a BitBlt
|
|
from the source bitmap to a monochrome bitmap. */
|
|
BitBlt(hdcObject, 0, 0, width, height, hdcSave, 0, 0, SRCCOPY);
|
|
|
|
/* Set the background color of the source DC back to the original
|
|
color. */
|
|
SetBkColor(hdcSave, cColor);
|
|
|
|
/* Create the inverse of the object mask. */
|
|
BitBlt(hdcBack, 0, 0, width, height, hdcObject, 0, 0, NOTSRCCOPY);
|
|
|
|
/* Copy background to the resulting image */
|
|
BitBlt(hdcMem, 0, 0, width, height, hDC, x, y, SRCCOPY);
|
|
|
|
/* Mask out the places where the source image will be placed. */
|
|
BitBlt(hdcMem, 0, 0, width, height, hdcObject, 0, 0, SRCAND);
|
|
|
|
/* Mask out the transparent colored pixels on the source image. */
|
|
BitBlt(hdcSave, 0, 0, width, height, hdcBack, 0, 0, SRCAND);
|
|
|
|
/* XOR the source image with the beckground. */
|
|
BitBlt(hdcMem, 0, 0, width, height, hdcSave, 0, 0, SRCPAINT);
|
|
|
|
/* blt resulting image to the screen */
|
|
BitBlt(hDC, x, y, width, height, hdcMem, 0, 0, SRCCOPY);
|
|
|
|
/* cleanup */
|
|
DeleteObject(SelectObject(hdcBack, bmBackOld));
|
|
DeleteObject(SelectObject(hdcObject, bmObjectOld));
|
|
DeleteObject(SelectObject(hdcMem, bmMemOld));
|
|
DeleteObject(SelectObject(hdcSave, bmSaveOld));
|
|
|
|
DeleteDC(hdcMem);
|
|
DeleteDC(hdcBack);
|
|
DeleteDC(hdcObject);
|
|
DeleteDC(hdcSave);
|
|
|
|
return TRUE;
|
|
}
|