This repository has been archived on 2025-05-24. You can view files and clone it, but cannot push or open issues or pull requests.
Files
VARCem/src/win/win.c
waltje d393e95f8f Fixed bug in XTA driver.
Fixed string-loading issue.
Fixes for handling file dialog, filters, etc.
Changed the return value of dlg_file so we can use its RO flag.
Removed the additional _WP statusbar menu items (no longer needed with new RO handling.)
2018-05-11 21:31:52 -04:00

611 lines
11 KiB
C

/*
* VARCem Virtual ARchaeological Computer EMulator.
* An emulator of (mostly) x86-based PC systems and devices,
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
* spanning the era between 1981 and 1995.
*
* This file is part of the VARCem Project.
*
* Platform main support module for Windows.
*
* Version: @(#)win.c 1.0.13 2018/05/11
*
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
* Miran Grca, <mgrca8@gmail.com>
* Sarah Walker, <tommowalker@tommowalker.co.uk>
*
* Copyright 2017,2018 Fred N. van Kempen.
* Copyright 2016-2018 Miran Grca.
* Copyright 2008-2018 Sarah Walker.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the:
*
* Free Software Foundation, Inc.
* 59 Temple Place - Suite 330
* Boston, MA 02111-1307
* USA.
*/
#define UNICODE
#define _WIN32_WINNT 0x0501
#include <windows.h>
#ifdef _MSC_VER
# include <io.h> /* for _open_osfhandle() */
#endif
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <wchar.h>
#include "../emu.h"
#include "../version.h"
#include "../config.h"
#include "../device.h"
#include "../ui/ui.h"
#define GLOBAL
#include "../plat.h"
#ifdef USE_SDL
# include "win_sdl.h"
#endif
#ifdef USE_VNC
# include "../vnc.h"
#endif
#ifdef USE_RDP
# include <rdp.h>
#endif
#include "../devices/input/mouse.h"
#include "../devices/video/video.h"
#ifdef USE_WX
# include "../wx/wx_ui.h"
#endif
#include "win.h"
/* Platform Public data, specific. */
HINSTANCE hInstance; /* application instance */
LCID lang_id; /* current language ID used */
DWORD dwSubLangID;
const string_t *plat_strings;
/* Local data. */
static HANDLE hBlitMutex, /* video mutex */
thMain; /* main thread */
/* The list with supported VidAPI modules. */
const vidapi_t *plat_vidapis[] = {
#ifdef USE_WX
&wx_vidapi,
#else
&ddraw_vidapi,
&d3d_vidapi,
#endif
#ifdef USE_SDL
&sdl_vidapi,
#endif
#ifdef USE_VNC
&vnc_vidapi,
#endif
#ifdef USE_RDP
&rdp_vidapi,
#endif
NULL
};
/* Pre-load the strings from our resource file. */
static void
LoadCommonStrings(void)
{
wchar_t temp[512], *str;
string_t *array, *tbl;
int c = 0, i;
/*
* First, we need to know how many strings are in the table.
* Sadly, there is no other way to determine this but to try
* to load all possible ID's...
*/
for (i = IDS_BEGIN; i < IDS_END; i++)
if (LoadString(hInstance, i, temp, sizeof_w(temp)) > 0) c++;
/*
* Now that we know how many strings exist, we can allocate
* our string_table array.
*/
i = (c + 1) * sizeof(string_t);
array = (string_t *)malloc(i);
memset(array, 0x00, i);
/* Now load the actual strings into our string table. */
tbl = array;
for (i = IDS_BEGIN; i < IDS_END; i++) {
c = LoadString(hInstance, i, temp, sizeof_w(temp));
if (c == 0) continue;
tbl->id = i;
str = (wchar_t *)malloc((c + 1) * sizeof(wchar_t));
memset(str, 0x00, (c + 1) * sizeof(wchar_t));
memcpy(str, temp, c * sizeof(wchar_t));
tbl->str = str;
tbl++;
}
/* Terminate the table. */
tbl->str = NULL;
/* Consider this table const. */
plat_strings = array;
}
/* Process the commandline, and create standard argc/argv array. */
static int
ProcessCommandLine(wchar_t ***argw)
{
WCHAR *cmdline;
wchar_t *argbuf;
wchar_t **args;
int argc_max;
int i, q, argc;
cmdline = GetCommandLine();
i = wcslen(cmdline) + 1;
argbuf = (wchar_t *)malloc(sizeof(wchar_t)*i);
wcscpy(argbuf, cmdline);
argc = 0;
argc_max = 64;
args = (wchar_t **)malloc(sizeof(wchar_t *) * argc_max);
if (args == NULL) {
free(argbuf);
return(0);
}
/* parse commandline into argc/argv format */
i = 0;
while (argbuf[i]) {
while (argbuf[i] == L' ')
i++;
if (argbuf[i]) {
if ((argbuf[i] == L'\'') || (argbuf[i] == L'"')) {
q = argbuf[i++];
if (!argbuf[i])
break;
} else
q = 0;
args[argc++] = &argbuf[i];
if (argc >= argc_max) {
argc_max += 64;
args = realloc(args, sizeof(wchar_t *)*argc_max);
if (args == NULL) {
free(argbuf);
return(0);
}
}
while ((argbuf[i]) && ((q)
? (argbuf[i]!=q) : (argbuf[i]!=L' '))) i++;
if (argbuf[i]) {
argbuf[i] = 0;
i++;
}
}
}
args[argc] = NULL;
*argw = args;
return(argc);
}
/* Load an icon from the resources. */
HICON
LoadIconEx(PCTSTR name)
{
return((HICON)LoadImage(hInstance, name, IMAGE_ICON, 16, 16, LR_SHARED));
}
/* For the Windows platform, this is the start of the application. */
int WINAPI
WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszArg, int nCmdShow)
{
wchar_t **argw = NULL;
int argc, i;
/* Set this to the default value (windowed mode). */
vid_fullscreen = 0;
/* We need this later. */
hInstance = hInst;
/* Initialize the version data. CrashDump needs it early. */
pc_version("Windows");
#ifdef USE_CRASHDUMP
/* Enable crash dump services. */
InitCrashDump();
#endif
/* First, set our (default) language. */
plat_set_language(0x0409);
/* Create console window. */
if (force_debug)
plat_console(1);
/* Process the command line for options. */
argc = ProcessCommandLine(&argw);
/* Pre-initialize the system, this loads the config file. */
if (! pc_setup(argc, argw)) {
/* Detach from console. */
plat_console(0);
return(1);
}
/* Cleanup: we may no longer need the console. */
if (! force_debug)
plat_console(0);
/* Create a mutex for the video handler. */
hBlitMutex = CreateMutex(NULL, FALSE, MUTEX_NAME);
/* Handle our GUI. */
i = ui_init(nCmdShow);
return(i);
}
/*
* We do this here since there is platform-specific stuff
* going on here, and we do it in a function separate from
* main() so we can call it from the UI module as well.
*/
void
plat_start(void)
{
LARGE_INTEGER qpc;
/* We have not stopped yet. */
quited = 0;
/* Initialize the high-precision timer. */
timeBeginPeriod(1);
QueryPerformanceFrequency(&qpc);
timer_freq = qpc.QuadPart;
pclog("Main timer precision: %llu\n", timer_freq);
/* Start the emulator, really. */
thMain = thread_create(pc_thread, &quited);
SetThreadPriority(thMain, THREAD_PRIORITY_HIGHEST);
}
/* Cleanly stop the emulator. */
void
plat_stop(void)
{
quited = 1;
plat_delay_ms(100);
pc_close(thMain);
thMain = NULL;
}
/* Set (or re-set) the language for the application. */
void
plat_set_language(int id)
{
LCID lcidNew = MAKELCID(id, dwSubLangID);
if (lang_id != lcidNew) {
/* Set our new language ID. */
lang_id = lcidNew;
SetThreadLocale(lang_id);
/* Load the strings table for this ID. */
LoadCommonStrings();
#if 0
/* Update the menus for this ID. */
MenuUpdate();
#endif
}
}
#ifndef USE_WX
/* Create a console if we don't already have one. */
void
plat_console(int init)
{
HANDLE h;
FILE *fp;
fpos_t p;
int i;
if (! init) {
FreeConsole();
return;
}
/* Are we logging to a file? */
p = 0;
(void)fgetpos(stdout, &p);
if (p != -1) return;
/* Not logging to file, attach to console. */
if (! AttachConsole(ATTACH_PARENT_PROCESS)) {
/* Parent has no console, create one. */
if (! AllocConsole()) {
/* Cannot create console, just give up. */
return;
}
}
fp = NULL;
if ((h = GetStdHandle(STD_OUTPUT_HANDLE)) != NULL) {
/* We got the handle, now open a file descriptor. */
if ((i = _open_osfhandle((intptr_t)h, _O_TEXT)) != -1) {
/* We got a file descriptor, now allocate a new stream. */
if ((fp = _fdopen(i, "w")) != NULL) {
/* Got the stream, re-initialize stdout with it. */
(void)freopen("CONOUT$", "w", stdout);
setvbuf(stdout, NULL, _IONBF, 0);
fflush(stdout);
}
}
}
}
#endif /*USE_WX*/
/* Return icon number based on drive type. */
int
plat_fdd_icon(int type)
{
int ret = 512;
switch(type) {
case 0:
break;
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
ret = 128;
break;
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
ret = 144;
break;
default:
break;
}
return(ret);
}
void
plat_get_exe_name(wchar_t *bufp, int size)
{
GetModuleFileName(hInstance, bufp, size);
}
int
plat_getcwd(wchar_t *bufp, int max)
{
(void)_wgetcwd(bufp, max);
return(0);
}
int
plat_chdir(const wchar_t *path)
{
return(_wchdir(path));
}
FILE *
plat_fopen(const wchar_t *path, wchar_t *mode)
{
return(_wfopen(path, mode));
}
void
plat_remove(const wchar_t *path)
{
_wremove(path);
}
/* Make sure a path ends with a trailing (back)slash. */
void
plat_append_slash(wchar_t *path)
{
if ((path[wcslen(path)-1] != L'\\') &&
(path[wcslen(path)-1] != L'/')) {
wcscat(path, L"\\");
}
}
/* Check if the given path is absolute or not. */
int
plat_path_abs(const wchar_t *path)
{
if ((path[1] == L':') || (path[0] == L'\\') || (path[0] == L'/'))
return(1);
return(0);
}
/* Return the last element of a pathname. */
wchar_t *
plat_get_basename(const wchar_t *path)
{
int c = wcslen(path);
while (c > 0) {
if (path[c] == L'/' || path[c] == L'\\')
return((wchar_t *)&path[c]);
c--;
}
return((wchar_t *)path);
}
wchar_t *
plat_get_filename(const wchar_t *path)
{
int c = wcslen(path) - 1;
while (c > 0) {
if (path[c] == L'/' || path[c] == L'\\')
return((wchar_t *)&path[c+1]);
c--;
}
return((wchar_t *)path);
}
wchar_t *
plat_get_extension(const wchar_t *path)
{
int c = wcslen(path) - 1;
if (c <= 0)
return((wchar_t *)path);
while (c && path[c] != L'.')
c--;
if (!c)
return((wchar_t *)&path[wcslen(path)]);
return((wchar_t *)&path[c+1]);
}
void
plat_append_filename(wchar_t *dest, const wchar_t *s1, const wchar_t *s2)
{
wcscat(dest, s1);
wcscat(dest, s2);
}
int
plat_dir_check(const wchar_t *path)
{
DWORD dwAttrib = GetFileAttributes(path);
return(((dwAttrib != INVALID_FILE_ATTRIBUTES &&
(dwAttrib & FILE_ATTRIBUTE_DIRECTORY))) ? 1 : 0);
}
int
plat_dir_create(const wchar_t *path)
{
return((int)CreateDirectory(path, NULL));
}
uint64_t
plat_timer_read(void)
{
LARGE_INTEGER li;
QueryPerformanceCounter(&li);
return(li.QuadPart);
}
uint32_t
plat_get_ticks(void)
{
return(GetTickCount());
}
void
plat_delay_ms(uint32_t count)
{
Sleep(count);
}
/*
* Get number of VidApi entries.
*
* This has to be in this module because only we know
* the actual size of the plat_vidapis[] array. Not a
* nice way to do it, but so it is...
*/
int
vidapi_count(void)
{
return((sizeof(plat_vidapis)/sizeof(vidapi_t *)) - 1);
}
void
plat_startblit(void)
{
WaitForSingleObject(hBlitMutex, INFINITE);
}
void
plat_endblit(void)
{
ReleaseMutex(hBlitMutex);
}