2012-11-25 04:26:37 +00:00
|
|
|
// Windows layer-independent code
|
|
|
|
|
2019-11-15 19:51:02 +00:00
|
|
|
#define NOMINMAX
|
2019-10-05 17:28:05 +00:00
|
|
|
#include <Windows.h>
|
2014-07-06 00:11:58 +00:00
|
|
|
#include "compat.h"
|
2012-11-25 04:26:37 +00:00
|
|
|
#include "build.h"
|
|
|
|
#include "baselayer.h"
|
2013-01-04 23:42:43 +00:00
|
|
|
#include "osd.h"
|
2019-12-17 22:25:07 +00:00
|
|
|
|
2019-09-25 20:38:47 +00:00
|
|
|
#include "zstring.h"
|
2012-11-25 04:26:37 +00:00
|
|
|
#include "winbits.h"
|
|
|
|
|
2019-10-04 21:29:00 +00:00
|
|
|
FString progdir;
|
2012-11-25 04:26:37 +00:00
|
|
|
//
|
2019-09-25 20:38:47 +00:00
|
|
|
// CheckWinVersion() -- check to see what version of Windows we happen to be running under (stripped down to what is actually still supported.)
|
2012-11-25 04:26:37 +00:00
|
|
|
//
|
|
|
|
|
2019-09-25 20:38:47 +00:00
|
|
|
//==========================================================================
|
2013-10-07 10:05:41 +00:00
|
|
|
//
|
2019-09-25 20:38:47 +00:00
|
|
|
// win_buildargs
|
2013-10-07 10:05:41 +00:00
|
|
|
//
|
2019-09-25 20:38:47 +00:00
|
|
|
// This should be removed once everything can use the FArgs list.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
2013-10-07 10:05:41 +00:00
|
|
|
|
2013-10-06 07:49:26 +00:00
|
|
|
|
2015-02-11 05:21:50 +00:00
|
|
|
int32_t win_buildargs(char **argvbuf)
|
|
|
|
{
|
|
|
|
int32_t buildargc = 0;
|
2019-09-25 20:38:47 +00:00
|
|
|
|
|
|
|
FString cmdline_utf8 = FString(GetCommandLineW());
|
2015-02-11 05:21:50 +00:00
|
|
|
|
2019-09-25 20:38:47 +00:00
|
|
|
*argvbuf = Xstrdup(cmdline_utf8.GetChars());
|
2015-02-11 05:21:50 +00:00
|
|
|
|
|
|
|
if (*argvbuf)
|
|
|
|
{
|
|
|
|
char quoted = 0, instring = 0, swallownext = 0;
|
|
|
|
char *wp;
|
|
|
|
for (const char *p = wp = *argvbuf; *p; p++)
|
|
|
|
{
|
|
|
|
if (*p == ' ')
|
|
|
|
{
|
|
|
|
if (instring)
|
|
|
|
{
|
|
|
|
if (!quoted)
|
|
|
|
{
|
|
|
|
// end of a string
|
|
|
|
*(wp++) = 0;
|
|
|
|
instring = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*(wp++) = *p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (*p == '"' && !swallownext)
|
|
|
|
{
|
|
|
|
if (instring)
|
|
|
|
{
|
|
|
|
if (quoted && p[1] == ' ')
|
|
|
|
{
|
|
|
|
// end of a string
|
|
|
|
*(wp++) = 0;
|
|
|
|
instring = 0;
|
|
|
|
}
|
|
|
|
quoted = !quoted;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
instring = 1;
|
|
|
|
quoted = 1;
|
|
|
|
buildargc++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (*p == '\\' && p[1] == '"' && !swallownext)
|
|
|
|
swallownext = 1;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!instring)
|
|
|
|
buildargc++;
|
|
|
|
|
|
|
|
instring = 1;
|
|
|
|
*(wp++) = *p;
|
|
|
|
swallownext = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*wp = 0;
|
|
|
|
}
|
|
|
|
|
2019-10-04 21:29:00 +00:00
|
|
|
// Figure out what directory the program resides in.
|
2019-11-03 12:39:42 +00:00
|
|
|
|
|
|
|
wchar_t buffer[256];
|
|
|
|
GetModuleFileNameW(0, buffer, 256);
|
|
|
|
progdir = buffer;
|
2019-10-19 17:22:23 +00:00
|
|
|
progdir.Substitute("\\", "/");
|
2019-10-04 21:29:00 +00:00
|
|
|
auto lastsep = progdir.LastIndexOf('/');
|
|
|
|
if (lastsep != -1)
|
|
|
|
progdir.Truncate(lastsep + 1);
|
|
|
|
|
|
|
|
return buildargc;
|
2015-02-11 05:21:50 +00:00
|
|
|
}
|
|
|
|
|
2013-10-06 07:49:26 +00:00
|
|
|
|
2019-09-13 19:43:05 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// CalculateCPUSpeed
|
|
|
|
//
|
|
|
|
// Make a decent guess at how much time elapses between TSC steps. This can
|
|
|
|
// vary over runtime depending on power management settings, so should not
|
|
|
|
// be used anywhere that truely accurate timing actually matters.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
double PerfToSec, PerfToMillisec;
|
|
|
|
#include "stats.h"
|
|
|
|
|
|
|
|
static void CalculateCPUSpeed()
|
|
|
|
{
|
|
|
|
LARGE_INTEGER freq;
|
|
|
|
|
|
|
|
QueryPerformanceFrequency(&freq);
|
|
|
|
|
|
|
|
if (freq.QuadPart != 0)
|
|
|
|
{
|
|
|
|
LARGE_INTEGER count1, count2;
|
|
|
|
cycle_t ClockCalibration;
|
|
|
|
DWORD min_diff;
|
|
|
|
|
|
|
|
ClockCalibration.Reset();
|
|
|
|
|
|
|
|
// Count cycles for at least 55 milliseconds.
|
|
|
|
// The performance counter may be very low resolution compared to CPU
|
|
|
|
// speeds today, so the longer we count, the more accurate our estimate.
|
|
|
|
// On the other hand, we don't want to count too long, because we don't
|
|
|
|
// want the user to notice us spend time here, since most users will
|
|
|
|
// probably never use the performance statistics.
|
|
|
|
min_diff = freq.LowPart * 11 / 200;
|
|
|
|
|
|
|
|
// Minimize the chance of task switching during the testing by going very
|
|
|
|
// high priority. This is another reason to avoid timing for too long.
|
|
|
|
SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
|
|
|
|
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
|
|
|
|
|
|
|
|
// Make sure we start timing on a counter boundary.
|
|
|
|
QueryPerformanceCounter(&count1);
|
|
|
|
do
|
|
|
|
{
|
|
|
|
QueryPerformanceCounter(&count2);
|
|
|
|
} while (count1.QuadPart == count2.QuadPart);
|
|
|
|
|
|
|
|
// Do the timing loop.
|
|
|
|
ClockCalibration.Clock();
|
|
|
|
do
|
|
|
|
{
|
|
|
|
QueryPerformanceCounter(&count1);
|
|
|
|
} while ((count1.QuadPart - count2.QuadPart) < min_diff);
|
|
|
|
ClockCalibration.Unclock();
|
|
|
|
|
|
|
|
SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
|
|
|
|
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
|
|
|
|
|
|
|
|
PerfToSec = double(count1.QuadPart - count2.QuadPart) / (double(ClockCalibration.GetRawCounter()) * freq.QuadPart);
|
|
|
|
PerfToMillisec = PerfToSec * 1000.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class Initer
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Initer() { CalculateCPUSpeed(); }
|
|
|
|
};
|
|
|
|
|
|
|
|
static Initer initer;
|
|
|
|
|