-
Notifications
You must be signed in to change notification settings - Fork 0
/
ga-win32.cpp
235 lines (215 loc) · 6.43 KB
/
ga-win32.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
/*
* Copyright (c) 2013 Chun-Ying Huang
* Modification Copyright (c) 2021 me(github.com/am009)
*
* This file is part of GamingAnywhere (GA).
*
* GA is free software; you can redistribute it and/or modify it
* under the terms of the 3-clause BSD License as published by the
* Free Software Foundation: http://directory.fsf.org/wiki/License:BSD_3Clause
*
* GA 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.
*
* You should have received a copy of the 3-clause BSD License along with GA;
* if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/**
* @file
* GamingAnywhere's common functions for Windows
*
* This includes Windows specific functions and
* common UNIX function implementations for Windows.
*/
#include <cstdio>
#include "ga-common.h"
#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) || defined(__WATCOMC__)
#define DELTA_EPOCH_IN_USEC 11644473600000000Ui64
#else
#define DELTA_EPOCH_IN_USEC 11644473600000000ULL
#endif
typedef unsigned __int64 u_int64_t;
// https://docs.microsoft.com/en-us/windows/win32/winsock/ipv6-enabled-server-code-2
LPSTR PrintError(int ErrorCode)
{
static char Message[1024];
// If this program was multithreaded, we'd want to use
// FORMAT_MESSAGE_ALLOCATE_BUFFER instead of a static buffer here.
// (And of course, free the buffer when we were done with it)
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, ErrorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)Message, 1024, NULL);
return Message;
}
/**
* Convert Windows FILETIME to UNIX timestamp. This is an internal function.
*
* @param ft [in] Pointer to a FILETIME.
* @return UNIX timestamp time in microsecond unit.
*/
static u_int64_t
filetime_to_unix_epoch(const FILETIME *ft) {
u_int64_t res = (u_int64_t) ft->dwHighDateTime << 32;
res |= ft->dwLowDateTime;
res /= 10; /* from 100 nano-sec periods to usec */
res -= DELTA_EPOCH_IN_USEC; /* from Win epoch to Unix epoch */
return (res);
}
/**
* gettimeofday() implementation
*
* @param tv [in] \a timeval to store the timestamp.
* @param tz [in] timezone: unused.
*/
int
gettimeofday(struct timeval *tv, void *tz) {
FILETIME ft;
u_int64_t tim;
if (!tv) {
//errno = EINVAL;
return (-1);
}
GetSystemTimeAsFileTime(&ft);
tim = filetime_to_unix_epoch (&ft);
tv->tv_sec = (long) (tim / 1000000L);
tv->tv_usec = (long) (tim % 1000000L);
return (0);
}
long long tvdiff_us(struct timeval *tv1, struct timeval *tv2);
/**
* usleep() function: sleep in microsecond scale.
*
* @param waitTime [in] time to sleep (in microseconds).
* @return Always return 0.
*/
int
usleep(long long waitTime) {
struct timeval t1, t2;
long long ms, elapsed;
if(waitTime <= 0)
return 0;
gettimeofday(&t1, NULL);
// Sleep() may be fine
ms = waitTime / 1000;
waitTime %= 1000;
if(ms > 0) {
Sleep(ms);
}
// Sleep for the rest
if(waitTime > 0) do {
gettimeofday(&t2, NULL);
elapsed = tvdiff_us(&t2, &t1);
} while(elapsed < waitTime);
//
return 0;
}
/**
* read() function to read from a socket.
*
* @param fd [in] The SOCKET identifier.
* @param buf [in] Buffer to receive data.
* @param count [in] Size limit of the \a buf.
* @return Number of bytes received, see MSDN recv() function.
*/
int
read(SOCKET fd, void *buf, int count) {
return recv(fd, (char *) buf, count, 0);
}
/**
* write() function to write to a socket.
*
* @param fd [in] The SOCKET identifier.
* @param buf [in] Buffer to be sent.
* @param count [in] Number of bytes in the \a buf.
* @return Number of bytes sent, see MSDN send() function.
*/
int
write(SOCKET fd, const void *buf, int count) {
return send(fd, (const char*) buf, count, 0);
}
/**
* close() function to close a socket.
*
* @param fd [in] The SOCKET identifier.
* @return Zero on success, otherwise see MSDN closesocket() function.
*/
int
close(SOCKET fd) {
return closesocket(fd);
}
/**
* dlerror() to report error message of dl* functions
*
* Not supported on Windows.
*/
char *
dlerror() {
static char notsupported[] = "dlerror() on Windows is not supported.";
return notsupported;
}
/**
* Fill BITMAPINFO data structure
*
* @param pinfo [in,out] The BITMAPINFO structure to be filled.
* @param w [in] The width of the bitmap image.
* @param h [in] The height of the bitmap image.
* @param bitsPerPixel [in] The bits-per-pixel of the bitmap image.
*/
void
ga_win32_fill_bitmap_info(BITMAPINFO *pinfo, int w, int h, int bitsPerPixel) {
ZeroMemory(pinfo, sizeof(BITMAPINFO));
pinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pinfo->bmiHeader.biBitCount = bitsPerPixel;
pinfo->bmiHeader.biCompression = BI_RGB;
pinfo->bmiHeader.biWidth = w;
pinfo->bmiHeader.biHeight = h;
pinfo->bmiHeader.biPlanes = 1; // must be 1
pinfo->bmiHeader.biSizeImage = pinfo->bmiHeader.biHeight
* pinfo->bmiHeader.biWidth
* pinfo->bmiHeader.biBitCount/8;
return;
}
/**
* Compute time differece based on Windows performance counter.
*
* @param t1 [in] The first counter.
* @param t2 [in] The second counter.
* @param freq [in] The performance frequency obtained by \em QueryPerformanceFrequency().
* @return Time differece in microsecond unit, e.g., \a t1 - \a t2.
*/
long long
pcdiff_us(LARGE_INTEGER t1, LARGE_INTEGER t2, LARGE_INTEGER freq) {
return 1000000LL * (t1.QuadPart - t2.QuadPart) / freq.QuadPart;
}
typedef enum GA_PROCESS_DPI_AWARENESS {
GA_PROCESS_DPI_UNAWARE = 0,
GA_PROCESS_SYSTEM_DPI_AWARE = 1,
GA_PROCESS_PER_MONITOR_DPI_AWARE = 2
} GA_PROCESS_DPI_AWARENESS;
typedef BOOL (WINAPI * setProcessDpiAware_t)(void);
typedef HRESULT (WINAPI * setProcessDpiAwareness_t)(GA_PROCESS_DPI_AWARENESS);
/**
* Platform dependent call to SetProcessDpiAware(PROCESS_PER_MONITOR_DPI_AWARE)
*/
int
ga_set_process_dpi_aware() {
HMODULE shcore, user32;
setProcessDpiAware_t aw = NULL;
setProcessDpiAwareness_t awness = NULL;
int ret = 0;
if((shcore = LoadLibraryA("shcore.dll")))
awness = (setProcessDpiAwareness_t) GetProcAddress(shcore, "SetProcessDpiAwareness");
if((user32 = LoadLibraryA("user32.dll")))
aw = (setProcessDpiAware_t) GetProcAddress(user32, "SetProcessDPIAware");
if(awness) {
ret = (int) (awness(GA_PROCESS_PER_MONITOR_DPI_AWARE) == S_OK);
} else if(aw) {
ret = (int) (aw() != 0);
}
if(user32) FreeLibrary(user32);
if(shcore) FreeLibrary(shcore);
return ret;
}