mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-13 17:47:12 -04:00
UWP changes
This commit is contained in:
parent
fc676d906d
commit
9ad3f97efb
797
misc/UWP/Platform_UWP.cpp
Normal file
797
misc/UWP/Platform_UWP.cpp
Normal file
@ -0,0 +1,797 @@
|
||||
#include "../../src/Core.h"
|
||||
#include "../../src/_PlatformBase.h"
|
||||
#include "../../src/Stream.h"
|
||||
#include "../../src/SystemFonts.h"
|
||||
#include "../../src/Funcs.h"
|
||||
#include "../../src/Utils.h"
|
||||
#include "../../src/Errors.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOSERVICE
|
||||
#define NOMCX
|
||||
#define NOIME
|
||||
#ifndef UNICODE
|
||||
#define UNICODE
|
||||
#define _UNICODE
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <shellapi.h>
|
||||
#include <wincrypt.h>
|
||||
|
||||
using namespace Windows::ApplicationModel;
|
||||
using namespace Windows::ApplicationModel::Core;
|
||||
using namespace Windows::ApplicationModel::Activation;
|
||||
using namespace Windows::Devices::Input;
|
||||
using namespace Windows::Graphics::Display;
|
||||
using namespace Windows::Foundation;
|
||||
using namespace Windows::System;
|
||||
using namespace Windows::UI::Core;
|
||||
using namespace Windows::UI::Input;
|
||||
using namespace Windows::Security::Cryptography;
|
||||
using namespace Windows::Security::Cryptography::DataProtection;
|
||||
using namespace Platform;
|
||||
|
||||
static HANDLE heap;
|
||||
const cc_result ReturnCode_FileShareViolation = ERROR_SHARING_VIOLATION;
|
||||
const cc_result ReturnCode_FileNotFound = ERROR_FILE_NOT_FOUND;
|
||||
const cc_result ReturnCode_DirectoryExists = ERROR_ALREADY_EXISTS;
|
||||
const cc_result ReturnCode_SocketInProgess = WSAEINPROGRESS;
|
||||
const cc_result ReturnCode_SocketWouldBlock = WSAEWOULDBLOCK;
|
||||
const cc_result ReturnCode_SocketDropped = WSAECONNRESET;
|
||||
|
||||
const char* Platform_AppNameSuffix = "";
|
||||
cc_bool Platform_ReadonlyFilesystem;
|
||||
cc_bool Platform_SingleProcess;
|
||||
#define UWP_STRING(str) ((wchar_t*)(str)->uni)
|
||||
|
||||
/*########################################################################################################################*
|
||||
*---------------------------------------------------------Memory----------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
void* Mem_Set(void* dst, cc_uint8 value, unsigned numBytes) { return memset( dst, value, numBytes); }
|
||||
void* Mem_Copy(void* dst, const void* src, unsigned numBytes) { return memcpy( dst, src, numBytes); }
|
||||
void* Mem_Move(void* dst, const void* src, unsigned numBytes) { return memmove(dst, src, numBytes); }
|
||||
|
||||
void* Mem_TryAlloc(cc_uint32 numElems, cc_uint32 elemsSize) {
|
||||
cc_uint32 size = CalcMemSize(numElems, elemsSize);
|
||||
return size ? HeapAlloc(heap, 0, size) : NULL;
|
||||
}
|
||||
|
||||
void* Mem_TryAllocCleared(cc_uint32 numElems, cc_uint32 elemsSize) {
|
||||
cc_uint32 size = CalcMemSize(numElems, elemsSize);
|
||||
return size ? HeapAlloc(heap, HEAP_ZERO_MEMORY, size) : NULL;
|
||||
}
|
||||
|
||||
void* Mem_TryRealloc(void* mem, cc_uint32 numElems, cc_uint32 elemsSize) {
|
||||
cc_uint32 size = CalcMemSize(numElems, elemsSize);
|
||||
return size ? HeapReAlloc(heap, 0, mem, size) : NULL;
|
||||
}
|
||||
|
||||
void Mem_Free(void* mem) {
|
||||
if (mem) HeapFree(heap, 0, mem);
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*------------------------------------------------------Logging/Time-------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
/* TODO: check this is actually accurate */
|
||||
static cc_uint64 sw_freqMul = 1, sw_freqDiv = 1;
|
||||
cc_uint64 Stopwatch_ElapsedMicroseconds(cc_uint64 beg, cc_uint64 end) {
|
||||
if (end < beg) return 0;
|
||||
return ((end - beg) * sw_freqMul) / sw_freqDiv;
|
||||
}
|
||||
|
||||
static HANDLE conHandle;
|
||||
static BOOL hasDebugger;
|
||||
|
||||
void Platform_Log(const char* msg, int len) {
|
||||
char tmp[2048 + 1];
|
||||
DWORD wrote;
|
||||
|
||||
if (conHandle) {
|
||||
WriteFile(conHandle, msg, len, &wrote, NULL);
|
||||
WriteFile(conHandle, "\n", 1, &wrote, NULL);
|
||||
}
|
||||
|
||||
if (!hasDebugger) return;
|
||||
len = min(len, 2048);
|
||||
Mem_Copy(tmp, msg, len); tmp[len] = '\0';
|
||||
|
||||
OutputDebugStringA(tmp);
|
||||
OutputDebugStringA("\n");
|
||||
}
|
||||
|
||||
#define FILETIME_EPOCH 50491123200ULL
|
||||
#define FILETIME_UNIX_EPOCH 11644473600ULL
|
||||
#define FileTime_TotalSecs(time) ((time / 10000000) + FILETIME_EPOCH)
|
||||
#define FileTime_UnixTime(time) ((time / 10000000) - FILETIME_UNIX_EPOCH)
|
||||
|
||||
TimeMS DateTime_CurrentUTC(void) {
|
||||
FILETIME ft;
|
||||
cc_uint64 raw;
|
||||
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
/* in 100 nanosecond units, since Jan 1 1601 */
|
||||
raw = ft.dwLowDateTime | ((cc_uint64)ft.dwHighDateTime << 32);
|
||||
return FileTime_TotalSecs(raw);
|
||||
}
|
||||
|
||||
void DateTime_CurrentLocal(struct cc_datetime* t) {
|
||||
SYSTEMTIME localTime;
|
||||
GetLocalTime(&localTime);
|
||||
|
||||
t->year = localTime.wYear;
|
||||
t->month = localTime.wMonth;
|
||||
t->day = localTime.wDay;
|
||||
t->hour = localTime.wHour;
|
||||
t->minute = localTime.wMinute;
|
||||
t->second = localTime.wSecond;
|
||||
}
|
||||
|
||||
static cc_bool sw_highRes;
|
||||
cc_uint64 Stopwatch_Measure(void) {
|
||||
LARGE_INTEGER t;
|
||||
FILETIME ft;
|
||||
|
||||
if (sw_highRes) {
|
||||
QueryPerformanceCounter(&t);
|
||||
return (cc_uint64)t.QuadPart;
|
||||
} else {
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
return (cc_uint64)ft.dwLowDateTime | ((cc_uint64)ft.dwHighDateTime << 32);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-----------------------------------------------------Directory/File------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
void Directory_GetCachePath(cc_string* path) { }
|
||||
|
||||
void Platform_EncodePath(cc_filepath* dst, const cc_string* src) {
|
||||
Platform_EncodeString(dst, src);
|
||||
}
|
||||
|
||||
cc_result Directory_Create(const cc_filepath* path) {
|
||||
if (CreateDirectoryW(UWP_STRING(path), NULL)) return 0;
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
int File_Exists(const cc_filepath* path) {
|
||||
DWORD attribs = GetFileAttributesW(UWP_STRING(path));
|
||||
|
||||
return attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY);
|
||||
}
|
||||
|
||||
static cc_result Directory_EnumCore(const cc_string* dirPath, const cc_string* file, DWORD attribs,
|
||||
void* obj, Directory_EnumCallback callback) {
|
||||
cc_string path; char pathBuffer[MAX_PATH + 10];
|
||||
int is_dir;
|
||||
|
||||
/* ignore . and .. entry */
|
||||
if (file->length == 1 && file->buffer[0] == '.') return 0;
|
||||
if (file->length == 2 && file->buffer[0] == '.' && file->buffer[1] == '.') return 0;
|
||||
|
||||
String_InitArray(path, pathBuffer);
|
||||
String_Format2(&path, "%s/%s", dirPath, file);
|
||||
|
||||
is_dir = attribs & FILE_ATTRIBUTE_DIRECTORY;
|
||||
callback(&path, obj, is_dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cc_result Directory_Enum(const cc_string* dirPath, void* obj, Directory_EnumCallback callback) {
|
||||
cc_string path; char pathBuffer[MAX_PATH + 10];
|
||||
WIN32_FIND_DATAW eW;
|
||||
int i, ansi = false;
|
||||
cc_filepath str;
|
||||
HANDLE find;
|
||||
cc_result res;
|
||||
|
||||
/* Need to append \* to search for files in directory */
|
||||
String_InitArray(path, pathBuffer);
|
||||
String_Format1(&path, "%s\\*", dirPath);
|
||||
Platform_EncodePath(&str, &path);
|
||||
|
||||
find = FindFirstFileW(UWP_STRING(&str), &eW);
|
||||
if (!find || find == INVALID_HANDLE_VALUE)
|
||||
return GetLastError();
|
||||
|
||||
do {
|
||||
path.length = 0;
|
||||
for (i = 0; i < MAX_PATH && eW.cFileName[i]; i++) {
|
||||
/* TODO: UTF16 to codepoint conversion */
|
||||
String_Append(&path, Convert_CodepointToCP437(eW.cFileName[i]));
|
||||
}
|
||||
if ((res = Directory_EnumCore(dirPath, &path, eW.dwFileAttributes, obj, callback))) return res;
|
||||
} while (FindNextFileW(find, &eW));
|
||||
|
||||
res = GetLastError(); /* return code from FindNextFile */
|
||||
FindClose(find);
|
||||
return res == ERROR_NO_MORE_FILES ? 0 : res;
|
||||
}
|
||||
|
||||
static cc_result DoFile(cc_file* file, const cc_filepath* path, DWORD access, DWORD createMode) {
|
||||
*file = CreateFile2(UWP_STRING(path), access, FILE_SHARE_READ, createMode, NULL);
|
||||
if (*file && *file != INVALID_HANDLE_VALUE) return 0;
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
cc_result File_Open(cc_file* file, const cc_filepath* path) {
|
||||
return DoFile(file, path, GENERIC_READ, OPEN_EXISTING);
|
||||
}
|
||||
cc_result File_Create(cc_file* file, const cc_filepath* path) {
|
||||
return DoFile(file, path, GENERIC_WRITE | GENERIC_READ, CREATE_ALWAYS);
|
||||
}
|
||||
cc_result File_OpenOrCreate(cc_file* file, const cc_filepath* path) {
|
||||
return DoFile(file, path, GENERIC_WRITE | GENERIC_READ, OPEN_ALWAYS);
|
||||
}
|
||||
|
||||
cc_result File_Read(cc_file file, void* data, cc_uint32 count, cc_uint32* bytesRead) {
|
||||
/* NOTE: the (DWORD*) cast assumes that sizeof(long) is 4 */
|
||||
BOOL success = ReadFile(file, data, count, (DWORD*)bytesRead, NULL);
|
||||
return success ? 0 : GetLastError();
|
||||
}
|
||||
|
||||
cc_result File_Write(cc_file file, const void* data, cc_uint32 count, cc_uint32* bytesWrote) {
|
||||
/* NOTE: the (DWORD*) cast assumes that sizeof(long) is 4 */
|
||||
BOOL success = WriteFile(file, data, count, (DWORD*)bytesWrote, NULL);
|
||||
return success ? 0 : GetLastError();
|
||||
}
|
||||
|
||||
cc_result File_Close(cc_file file) {
|
||||
return CloseHandle(file) ? 0 : GetLastError();
|
||||
}
|
||||
|
||||
cc_result File_Seek(cc_file file, int offset, int seekType) {
|
||||
static cc_uint8 modes[] = { FILE_BEGIN, FILE_CURRENT, FILE_END };
|
||||
DWORD pos = SetFilePointer(file, offset, NULL, modes[seekType]);
|
||||
return pos != INVALID_SET_FILE_POINTER ? 0 : GetLastError();
|
||||
}
|
||||
|
||||
cc_result File_Position(cc_file file, cc_uint32* pos) {
|
||||
*pos = SetFilePointer(file, 0, NULL, FILE_CURRENT);
|
||||
return *pos != INVALID_SET_FILE_POINTER ? 0 : GetLastError();
|
||||
}
|
||||
|
||||
cc_result File_Length(cc_file file, cc_uint32* len) {
|
||||
LARGE_INTEGER raw;
|
||||
if (!GetFileSizeEx(file, &raw)) return GetLastError();
|
||||
|
||||
*len = raw.QuadPart;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*--------------------------------------------------------Threading--------------------------------------------------------*
|
||||
*#############################################################################################################p############*/
|
||||
void Thread_Sleep(cc_uint32 milliseconds) { Sleep(milliseconds); }
|
||||
static DWORD WINAPI ExecThread(void* param) {
|
||||
Thread_StartFunc func = (Thread_StartFunc)param;
|
||||
func();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Thread_Run(void** handle, Thread_StartFunc func, int stackSize, const char* name) {
|
||||
DWORD threadID;
|
||||
HANDLE thread = CreateThread(NULL, 0, ExecThread, (void*)func, CREATE_SUSPENDED, &threadID);
|
||||
if (!thread) Logger_Abort2(GetLastError(), "Creating thread");
|
||||
|
||||
*handle = thread;
|
||||
ResumeThread(thread);
|
||||
}
|
||||
|
||||
void Thread_Detach(void* handle) {
|
||||
if (!CloseHandle((HANDLE)handle)) {
|
||||
Logger_Abort2(GetLastError(), "Freeing thread handle");
|
||||
}
|
||||
}
|
||||
|
||||
void Thread_Join(void* handle) {
|
||||
WaitForSingleObject((HANDLE)handle, INFINITE);
|
||||
Thread_Detach(handle);
|
||||
}
|
||||
|
||||
void* Mutex_Create(const char* name) {
|
||||
CRITICAL_SECTION* ptr = (CRITICAL_SECTION*)Mem_Alloc(1, sizeof(CRITICAL_SECTION), "mutex");
|
||||
InitializeCriticalSection(ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void Mutex_Free(void* handle) {
|
||||
DeleteCriticalSection((CRITICAL_SECTION*)handle);
|
||||
Mem_Free(handle);
|
||||
}
|
||||
void Mutex_Lock(void* handle) { EnterCriticalSection((CRITICAL_SECTION*)handle); }
|
||||
void Mutex_Unlock(void* handle) { LeaveCriticalSection((CRITICAL_SECTION*)handle); }
|
||||
|
||||
void* Waitable_Create(const char* name) {
|
||||
void* handle = CreateEventA(NULL, false, false, NULL);
|
||||
if (!handle) {
|
||||
Logger_Abort2(GetLastError(), "Creating waitable");
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
void Waitable_Free(void* handle) {
|
||||
if (!CloseHandle((HANDLE)handle)) {
|
||||
Logger_Abort2(GetLastError(), "Freeing waitable");
|
||||
}
|
||||
}
|
||||
|
||||
void Waitable_Signal(void* handle) { SetEvent((HANDLE)handle); }
|
||||
void Waitable_Wait(void* handle) {
|
||||
WaitForSingleObject((HANDLE)handle, INFINITE);
|
||||
}
|
||||
|
||||
void Waitable_WaitFor(void* handle, cc_uint32 milliseconds) {
|
||||
WaitForSingleObject((HANDLE)handle, milliseconds);
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*---------------------------------------------------------Socket----------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
/* Sanity check to ensure cc_sockaddr struct is large enough to contain all socket addresses supported by this platform */
|
||||
static char sockaddr_size_check[sizeof(SOCKADDR_STORAGE) < CC_SOCKETADDR_MAXSIZE ? 1 : -1];
|
||||
|
||||
static cc_result ParseHostNew(char* host, int port, cc_sockaddr* addrs, int* numValidAddrs) {
|
||||
char portRaw[32]; cc_string portStr;
|
||||
struct addrinfo hints = { 0 };
|
||||
struct addrinfo* result;
|
||||
struct addrinfo* cur;
|
||||
int res, i = 0;
|
||||
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
String_InitArray(portStr, portRaw);
|
||||
String_AppendInt(&portStr, port);
|
||||
portRaw[portStr.length] = '\0';
|
||||
|
||||
res = getaddrinfo(host, portRaw, &hints, &result);
|
||||
if (res == WSAHOST_NOT_FOUND) return SOCK_ERR_UNKNOWN_HOST;
|
||||
if (res) return res;
|
||||
|
||||
/* Prefer IPv4 addresses first */
|
||||
for (cur = result; cur && i < SOCKET_MAX_ADDRS; cur = cur->ai_next)
|
||||
{
|
||||
if (cur->ai_family != AF_INET) continue;
|
||||
SocketAddr_Set(&addrs[i], cur->ai_addr, cur->ai_addrlen); i++;
|
||||
}
|
||||
|
||||
for (cur = result; cur && i < SOCKET_MAX_ADDRS; cur = cur->ai_next)
|
||||
{
|
||||
if (cur->ai_family == AF_INET) continue;
|
||||
SocketAddr_Set(&addrs[i], cur->ai_addr, cur->ai_addrlen); i++;
|
||||
}
|
||||
|
||||
freeaddrinfo(result);
|
||||
*numValidAddrs = i;
|
||||
return i == 0 ? ERR_INVALID_ARGUMENT : 0;
|
||||
}
|
||||
|
||||
cc_result Socket_ParseAddress(const cc_string* address, int port, cc_sockaddr* addrs, int* numValidAddrs) {
|
||||
SOCKADDR_IN* addr4 = (SOCKADDR_IN* )addrs[0].data;
|
||||
SOCKADDR_IN6* addr6 = (SOCKADDR_IN6*)addrs[0].data;
|
||||
cc_winstring str;
|
||||
INT size;
|
||||
|
||||
*numValidAddrs = 0;
|
||||
Platform_EncodeString(&str, address);
|
||||
|
||||
size = sizeof(*addr4);
|
||||
if (!WSAStringToAddressW(UWP_STRING(&str), AF_INET, NULL, (SOCKADDR*)addr4, &size)) {
|
||||
addr4->sin_port = htons(port);
|
||||
|
||||
addrs[0].size = size;
|
||||
*numValidAddrs = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size = sizeof(*addr6);
|
||||
if (!WSAStringToAddressW(UWP_STRING(&str), AF_INET6, NULL, (SOCKADDR*)addr6, &size)) {
|
||||
addr6->sin6_port = htons(port);
|
||||
|
||||
addrs[0].size = size;
|
||||
*numValidAddrs = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ParseHostNew(str.ansi, port, addrs, numValidAddrs);
|
||||
}
|
||||
|
||||
cc_result Socket_Create(cc_socket* s, cc_sockaddr* addr, cc_bool nonblocking) {
|
||||
SOCKADDR* raw_addr = (SOCKADDR*)addr->data;
|
||||
|
||||
*s = socket(raw_addr->sa_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (*s == -1) return WSAGetLastError();
|
||||
|
||||
if (nonblocking) {
|
||||
u_long blockingMode = -1; /* non-blocking mode */
|
||||
ioctlsocket(*s, FIONBIO, &blockingMode);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
cc_result Socket_Connect(cc_socket s, cc_sockaddr* addr) {
|
||||
SOCKADDR* raw_addr = (SOCKADDR*)addr->data;
|
||||
|
||||
int res = connect(s, raw_addr, addr->size);
|
||||
return res == -1 ? WSAGetLastError() : 0;
|
||||
}
|
||||
|
||||
cc_result Socket_Read(cc_socket s, cc_uint8* data, cc_uint32 count, cc_uint32* modified) {
|
||||
int recvCount = recv(s, (char*)data, count, 0);
|
||||
if (recvCount != -1) { *modified = recvCount; return 0; }
|
||||
*modified = 0; return WSAGetLastError();
|
||||
}
|
||||
|
||||
cc_result Socket_Write(cc_socket s, const cc_uint8* data, cc_uint32 count, cc_uint32* modified) {
|
||||
int sentCount = send(s, (const char*)data, count, 0);
|
||||
if (sentCount != -1) { *modified = sentCount; return 0; }
|
||||
*modified = 0; return WSAGetLastError();
|
||||
}
|
||||
|
||||
void Socket_Close(cc_socket s) {
|
||||
shutdown(s, SD_BOTH);
|
||||
closesocket(s);
|
||||
}
|
||||
|
||||
static cc_result Socket_Poll(cc_socket s, int mode, cc_bool* success) {
|
||||
fd_set set;
|
||||
struct timeval time = { 0 };
|
||||
int selectCount;
|
||||
|
||||
set.fd_count = 1;
|
||||
set.fd_array[0] = s;
|
||||
|
||||
if (mode == SOCKET_POLL_READ) {
|
||||
selectCount = select(1, &set, NULL, NULL, &time);
|
||||
} else {
|
||||
selectCount = select(1, NULL, &set, NULL, &time);
|
||||
}
|
||||
|
||||
if (selectCount == -1) { *success = false; return WSAGetLastError(); }
|
||||
|
||||
*success = set.fd_count != 0; return 0;
|
||||
}
|
||||
|
||||
cc_result Socket_CheckReadable(cc_socket s, cc_bool* readable) {
|
||||
return Socket_Poll(s, SOCKET_POLL_READ, readable);
|
||||
}
|
||||
|
||||
cc_result Socket_CheckWritable(cc_socket s, cc_bool* writable) {
|
||||
int resultSize = sizeof(cc_result);
|
||||
cc_result res = Socket_Poll(s, SOCKET_POLL_WRITE, writable);
|
||||
if (res || *writable) return res;
|
||||
|
||||
/* https://stackoverflow.com/questions/29479953/so-error-value-after-successful-socket-operation */
|
||||
getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&res, &resultSize);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-----------------------------------------------------Process/Module------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
cc_bool Process_OpenSupported = true;
|
||||
|
||||
static cc_result Process_RawGetExePath(cc_winstring* path, int* len) {
|
||||
*len = GetModuleFileNameW(NULL, UWP_STRING(path), NATIVE_STR_LEN);
|
||||
path->uni[*len] = '\0';
|
||||
if (*len) return 0;
|
||||
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
cc_result Process_StartGame2(const cc_string* args, int numArgs) {
|
||||
union STARTUPINFO_union {
|
||||
STARTUPINFOW wide;
|
||||
STARTUPINFOA ansi;
|
||||
} si = { 0 }; // less compiler warnings this way
|
||||
|
||||
cc_winstring path;
|
||||
cc_string argv; char argvBuffer[NATIVE_STR_LEN];
|
||||
PROCESS_INFORMATION pi = { 0 };
|
||||
cc_winstring raw;
|
||||
cc_result res;
|
||||
int len, i;
|
||||
|
||||
if (Platform_SingleProcess) return SetGameArgs(args, numArgs);
|
||||
if ((res = Process_RawGetExePath(&path, &len))) return res;
|
||||
si.wide.cb = sizeof(STARTUPINFOW);
|
||||
|
||||
String_InitArray(argv, argvBuffer);
|
||||
/* Game doesn't actually care about argv[0] */
|
||||
String_AppendConst(&argv, "cc");
|
||||
for (i = 0; i < numArgs; i++)
|
||||
{
|
||||
if (String_IndexOf(&args[i], ' ') >= 0) {
|
||||
String_Format1(&argv, " \"%s\"", &args[i]);
|
||||
} else {
|
||||
String_Format1(&argv, " %s", &args[i]);
|
||||
}
|
||||
}
|
||||
Platform_EncodeString(&raw, &argv);
|
||||
|
||||
if (!CreateProcessW(UWP_STRING(&path), UWP_STRING(&raw), NULL, NULL,
|
||||
false, 0, NULL, NULL, &si.wide, &pi)) return GetLastError();
|
||||
|
||||
/* Don't leak memory for process return code */
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Process_Exit(cc_result code) { ExitProcess(code); }
|
||||
cc_result Process_StartOpen(const cc_string* args) {
|
||||
cc_winstring raw;
|
||||
Platform_EncodeString(&raw, args);
|
||||
|
||||
auto str = ref new String(UWP_STRING(&raw));
|
||||
auto uri = ref new Uri(str);
|
||||
|
||||
auto options = ref new Windows::System::LauncherOptions();
|
||||
options->TreatAsUntrusted = true;
|
||||
Windows::System::Launcher::LaunchUriAsync(uri, options);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*--------------------------------------------------------Updater----------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
#define UPDATE_TMP TEXT("CC_prev.exe")
|
||||
#define UPDATE_SRC TEXT(UPDATE_FILE)
|
||||
cc_bool Updater_Supported = true;
|
||||
|
||||
#if defined _M_IX86
|
||||
const struct UpdaterInfo Updater_Info = {
|
||||
"&eDirect3D 9 is recommended", 2,
|
||||
{
|
||||
{ "Direct3D9", "ClassiCube.exe" },
|
||||
{ "OpenGL", "ClassiCube.opengl.exe" }
|
||||
}
|
||||
};
|
||||
#elif defined _M_X64
|
||||
const struct UpdaterInfo Updater_Info = {
|
||||
"&eDirect3D 9 is recommended", 2,
|
||||
{
|
||||
{ "Direct3D9", "ClassiCube.64.exe" },
|
||||
{ "OpenGL", "ClassiCube.64-opengl.exe" }
|
||||
}
|
||||
};
|
||||
#elif defined _M_ARM64
|
||||
const struct UpdaterInfo Updater_Info = { "", 1, { { "Direct3D11", "cc-arm64-d3d11.exe" } } };
|
||||
#elif defined _M_ARM
|
||||
const struct UpdaterInfo Updater_Info = { "", 1, { { "Direct3D11", "cc-arm32-d3d11.exe" } } };
|
||||
#else
|
||||
const struct UpdaterInfo Updater_Info = { "&eCompile latest source code to update", 0 };
|
||||
#endif
|
||||
|
||||
cc_bool Updater_Clean(void) {
|
||||
return DeleteFile(UPDATE_TMP) || GetLastError() == ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
cc_result Updater_Start(const char** action) {
|
||||
cc_winstring path;
|
||||
cc_result res;
|
||||
int len;
|
||||
|
||||
*action = "Getting executable path";
|
||||
if ((res = Process_RawGetExePath(&path, &len))) return res;
|
||||
|
||||
*action = "Moving executable to CC_prev.exe";
|
||||
if (!path.uni[0]) return ERR_NOT_SUPPORTED; /* MoveFileA returns ERROR_ACCESS_DENIED on Win 9x anyways */
|
||||
if (!MoveFileExW(UWP_STRING(&path), UPDATE_TMP, MOVEFILE_REPLACE_EXISTING)) return GetLastError();
|
||||
|
||||
*action = "Replacing executable";
|
||||
if (!MoveFileExW(UPDATE_SRC, UWP_STRING(&path), MOVEFILE_REPLACE_EXISTING)) return GetLastError();
|
||||
|
||||
*action = "Restarting game";
|
||||
return Process_StartGame2(NULL, 0);
|
||||
}
|
||||
|
||||
cc_result Updater_GetBuildTime(cc_uint64* timestamp) {
|
||||
cc_winstring path;
|
||||
cc_file file;
|
||||
FILETIME ft;
|
||||
cc_uint64 raw;
|
||||
cc_result res;
|
||||
int len;
|
||||
|
||||
if ((res = Process_RawGetExePath(&path, &len))) return res;
|
||||
if ((res = File_Open(&file, &path))) return res;
|
||||
|
||||
if (GetFileTime(file, NULL, NULL, &ft)) {
|
||||
raw = ft.dwLowDateTime | ((cc_uint64)ft.dwHighDateTime << 32);
|
||||
*timestamp = FileTime_UnixTime(raw);
|
||||
} else {
|
||||
res = GetLastError();
|
||||
}
|
||||
|
||||
File_Close(file);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Don't need special execute permission on windows */
|
||||
cc_result Updater_MarkExecutable(void) { return 0; }
|
||||
cc_result Updater_SetNewBuildTime(cc_uint64 timestamp) {
|
||||
static const cc_string path = String_FromConst(UPDATE_FILE);
|
||||
cc_filepath str;
|
||||
cc_file file;
|
||||
FILETIME ft;
|
||||
cc_uint64 raw;
|
||||
cc_result res;
|
||||
|
||||
Platform_EncodePath(&str, &path);
|
||||
res = File_OpenOrCreate(&file, &str);
|
||||
if (res) return res;
|
||||
|
||||
raw = 10000000 * (timestamp + FILETIME_UNIX_EPOCH);
|
||||
ft.dwLowDateTime = (cc_uint32)raw;
|
||||
ft.dwHighDateTime = (cc_uint32)(raw >> 32);
|
||||
|
||||
if (!SetFileTime(file, NULL, NULL, &ft)) res = GetLastError();
|
||||
File_Close(file);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-------------------------------------------------------Dynamic lib-------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
const cc_string DynamicLib_Ext = String_FromConst(".dll");
|
||||
static cc_result dynamicErr;
|
||||
static cc_bool loadingPlugin;
|
||||
|
||||
void* DynamicLib_Load2(const cc_string* path) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* DynamicLib_Get2(void* lib, const char* name) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cc_bool DynamicLib_DescribeError(cc_string* dst) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*--------------------------------------------------------Platform---------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
void Platform_EncodeString(cc_winstring* dst, const cc_string* src) {
|
||||
cc_unichar* uni;
|
||||
char* ansi;
|
||||
int i;
|
||||
if (src->length > FILENAME_SIZE) Logger_Abort("String too long to expand");
|
||||
|
||||
uni = dst->uni;
|
||||
for (i = 0; i < src->length; i++)
|
||||
{
|
||||
*uni++ = Convert_CP437ToUnicode(src->buffer[i]);
|
||||
}
|
||||
*uni = '\0';
|
||||
|
||||
ansi = dst->ansi;
|
||||
for (i = 0; i < src->length; i++)
|
||||
{
|
||||
*ansi++ = (char)dst->uni[i];
|
||||
}
|
||||
*ansi = '\0';
|
||||
}
|
||||
|
||||
static void Platform_InitStopwatch(void) {
|
||||
LARGE_INTEGER freq;
|
||||
sw_highRes = QueryPerformanceFrequency(&freq);
|
||||
|
||||
if (sw_highRes) {
|
||||
sw_freqMul = 1000 * 1000;
|
||||
sw_freqDiv = freq.QuadPart;
|
||||
} else { sw_freqDiv = 10; }
|
||||
}
|
||||
|
||||
void Platform_Init(void) {
|
||||
WSADATA wsaData;
|
||||
cc_result res;
|
||||
|
||||
Platform_InitStopwatch();
|
||||
heap = GetProcessHeap();
|
||||
|
||||
hasDebugger = IsDebuggerPresent();
|
||||
AttachConsole(-1); /* ATTACH_PARENT_PROCESS */
|
||||
|
||||
conHandle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (conHandle == INVALID_HANDLE_VALUE) conHandle = NULL;
|
||||
|
||||
res = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||
if (res) Logger_SysWarn(res, "starting WSA");
|
||||
}
|
||||
|
||||
void Platform_Free(void) {
|
||||
WSACleanup();
|
||||
HeapDestroy(heap);
|
||||
}
|
||||
|
||||
cc_bool Platform_DescribeError(cc_result res, cc_string* dst) {
|
||||
WCHAR chars[NATIVE_STR_LEN];
|
||||
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
|
||||
|
||||
res = FormatMessageW(flags, NULL, res, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
chars, NATIVE_STR_LEN, NULL);
|
||||
if (!res) return false;
|
||||
|
||||
String_AppendUtf16(dst, chars, res * 2);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-------------------------------------------------------Encryption--------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
cc_result Platform_Encrypt(const void* data, int len, cc_string* dst) {
|
||||
return 200;
|
||||
}
|
||||
|
||||
cc_result Platform_Decrypt(const void* data, int len, cc_string* dst) {
|
||||
return 200;
|
||||
}
|
||||
|
||||
cc_result Platform_GetEntropy(void* data, int len) {
|
||||
return ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-----------------------------------------------------Configuration-------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
static cc_string Platform_NextArg(STRING_REF cc_string* args) {
|
||||
cc_string arg;
|
||||
int end;
|
||||
|
||||
/* get rid of leading spaces before arg */
|
||||
while (args->length && args->buffer[0] == ' ') {
|
||||
*args = String_UNSAFE_SubstringAt(args, 1);
|
||||
}
|
||||
|
||||
if (args->length && args->buffer[0] == '"') {
|
||||
/* "xy za" is used for arg with spaces */
|
||||
*args = String_UNSAFE_SubstringAt(args, 1);
|
||||
end = String_IndexOf(args, '"');
|
||||
} else {
|
||||
end = String_IndexOf(args, ' ');
|
||||
}
|
||||
|
||||
if (end == -1) {
|
||||
arg = *args;
|
||||
args->length = 0;
|
||||
} else {
|
||||
arg = String_UNSAFE_Substring(args, 0, end);
|
||||
*args = String_UNSAFE_SubstringAt(args, end + 1);
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
int Platform_GetCommandLineArgs(int argc, STRING_REF char** argv, cc_string* args) {
|
||||
cc_string cmdArgs = String_FromReadonly(GetCommandLineA());
|
||||
int i;
|
||||
Platform_NextArg(&cmdArgs); /* skip exe path */
|
||||
if (gameHasArgs) return GetGameArgs(args);
|
||||
|
||||
for (i = 0; i < GAME_MAX_CMDARGS; i++)
|
||||
{
|
||||
args[i] = Platform_NextArg(&cmdArgs);
|
||||
|
||||
if (!args[i].length) break;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
cc_result Platform_SetDefaultCurrentDirectory(int argc, char** argv) {
|
||||
return 0;
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
using namespace Windows::ApplicationModel;
|
||||
using namespace Windows::ApplicationModel::Core;
|
||||
using namespace Windows::ApplicationModel::Activation;
|
||||
using namespace Windows::Devices::Input;
|
||||
using namespace Windows::Graphics::Display;
|
||||
using namespace Windows::Foundation;
|
||||
using namespace Windows::System;
|
||||
using namespace Windows::UI::Core;
|
||||
using namespace Windows::UI::Input;
|
||||
using namespace Platform;
|
||||
|
||||
void Launch_Browser(void) {
|
||||
wchar_t* tmp = L"https://google.com";
|
||||
auto str = ref new String(tmp);
|
||||
auto uri = ref new Uri(str);
|
||||
|
||||
auto options = ref new Windows::System::LauncherOptions();
|
||||
options->TreatAsUntrusted = true;
|
||||
Windows::System::Launcher::LaunchUriAsync(uri, options);
|
||||
}
|
||||
|
||||
void OpenFileDialog(void) {
|
||||
auto picker = ref new Windows::Storage::Pickers::FileOpenPicker();
|
||||
picker->FileTypeFilter->Append(ref new String(L".jpg"));
|
||||
picker->FileTypeFilter->Append(ref new String(L".jpeg"));
|
||||
picker->FileTypeFilter->Append(ref new String(L".png"));
|
||||
|
||||
//Windows::Storage::StorageFile file = picker->PickSingleFileAsync();
|
||||
}
|
||||
|
||||
ref class CCApp sealed : IFrameworkView
|
||||
{
|
||||
public:
|
||||
virtual void Initialize(CoreApplicationView^ view)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Load(String^ EntryPoint)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Uninitialize()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Run()
|
||||
{
|
||||
CoreWindow^ window = CoreWindow::GetForCurrentThread();
|
||||
window->Activate();
|
||||
Launch_Browser();
|
||||
|
||||
CoreDispatcher^ dispatcher = window->Dispatcher;
|
||||
dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessUntilQuit);
|
||||
}
|
||||
|
||||
virtual void SetWindow(CoreWindow^ win)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
ref class CCAppSource sealed : IFrameworkViewSource
|
||||
{
|
||||
public:
|
||||
virtual IFrameworkView^ CreateView()
|
||||
{
|
||||
return ref new CCApp();
|
||||
}
|
||||
};
|
||||
|
||||
[MTAThread]
|
||||
int main(Array<String^>^ args)
|
||||
{
|
||||
//init_apartment();
|
||||
auto source = ref new CCAppSource();
|
||||
CoreApplication::Run(source);
|
||||
}
|
247
misc/UWP/Window_UWP.cpp
Normal file
247
misc/UWP/Window_UWP.cpp
Normal file
@ -0,0 +1,247 @@
|
||||
#include "../../src/Core.h"
|
||||
using namespace Windows::ApplicationModel;
|
||||
using namespace Windows::ApplicationModel::Core;
|
||||
using namespace Windows::ApplicationModel::Activation;
|
||||
using namespace Windows::Devices::Input;
|
||||
using namespace Windows::Graphics::Display;
|
||||
using namespace Windows::Foundation;
|
||||
using namespace Windows::System;
|
||||
using namespace Windows::UI::Core;
|
||||
using namespace Windows::UI::Input;
|
||||
using namespace Platform;
|
||||
|
||||
#include "../../src/_WindowBase.h"
|
||||
#include "../../src/String.h"
|
||||
#include "../../src/Funcs.h"
|
||||
#include "../../src/Bitmap.h"
|
||||
#include "../../src/Options.h"
|
||||
#include "../../src/Errors.h"
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*--------------------------------------------------Public implementation--------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
void Window_PreInit(void) {
|
||||
DisplayInfo.CursorVisible = true;
|
||||
}
|
||||
|
||||
void Window_Init(void) {
|
||||
Input.Sources = INPUT_SOURCE_NORMAL;
|
||||
|
||||
DisplayInfo.Width = 640;
|
||||
DisplayInfo.Height = 480;
|
||||
DisplayInfo.Depth = 32;
|
||||
DisplayInfo.ScaleX = 1.0f;
|
||||
DisplayInfo.ScaleY = 1.0f;
|
||||
}
|
||||
|
||||
void Window_Free(void) { }
|
||||
|
||||
void Window_Create2D(int width, int height) { }
|
||||
void Window_Create3D(int width, int height) { }
|
||||
|
||||
void Window_Destroy(void) {
|
||||
}
|
||||
|
||||
void Window_SetTitle(const cc_string* title) {
|
||||
}
|
||||
|
||||
void Clipboard_GetText(cc_string* value) {
|
||||
}
|
||||
|
||||
void Clipboard_SetText(const cc_string* value) {
|
||||
}
|
||||
|
||||
int Window_GetWindowState(void) {
|
||||
return WINDOW_STATE_NORMAL;
|
||||
}
|
||||
|
||||
cc_result Window_EnterFullscreen(void) {
|
||||
return ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
cc_result Window_ExitFullscreen(void) {
|
||||
return ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
int Window_IsObscured(void) { return 0; }
|
||||
|
||||
void Window_Show(void) {
|
||||
}
|
||||
|
||||
void Window_SetSize(int width, int height) {
|
||||
}
|
||||
|
||||
void Window_RequestClose(void) {
|
||||
Event_RaiseVoid(&WindowEvents.Closing);
|
||||
}
|
||||
|
||||
void Window_ProcessEvents(float delta) {
|
||||
}
|
||||
|
||||
void Gamepads_Init(void) {
|
||||
|
||||
}
|
||||
|
||||
void Gamepads_Process(float delta) { }
|
||||
|
||||
static void Cursor_GetRawPos(int* x, int* y) {
|
||||
*x = 0;
|
||||
*y = 0;
|
||||
}
|
||||
|
||||
void Cursor_SetPosition(int x, int y) {
|
||||
}
|
||||
|
||||
static void Cursor_DoSetVisible(cc_bool visible) {
|
||||
}
|
||||
|
||||
static void ShowDialogCore(const char* title, const char* msg) {
|
||||
}
|
||||
|
||||
static cc_result OpenSaveFileDialog(const cc_string* filters, FileDialogCallback callback, cc_bool load,
|
||||
const char* const* fileExts, const cc_string* defaultName) {
|
||||
return ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
cc_result Window_OpenFileDialog(const struct OpenFileDialogArgs* args) {
|
||||
const char* const* fileExts = args->filters;
|
||||
cc_string filters; char buffer[NATIVE_STR_LEN];
|
||||
int i;
|
||||
|
||||
/* Filter tokens are \0 separated - e.g. "Maps (*.cw;*.dat)\0*.cw;*.dat\0 */
|
||||
String_InitArray(filters, buffer);
|
||||
String_Format1(&filters, "%c (", args->description);
|
||||
for (i = 0; fileExts[i]; i++)
|
||||
{
|
||||
if (i) String_Append(&filters, ';');
|
||||
String_Format1(&filters, "*%c", fileExts[i]);
|
||||
}
|
||||
String_Append(&filters, ')');
|
||||
String_Append(&filters, '\0');
|
||||
|
||||
for (i = 0; fileExts[i]; i++)
|
||||
{
|
||||
if (i) String_Append(&filters, ';');
|
||||
String_Format1(&filters, "*%c", fileExts[i]);
|
||||
}
|
||||
String_Append(&filters, '\0');
|
||||
|
||||
return OpenSaveFileDialog(&filters, args->Callback, true, fileExts, &String_Empty);
|
||||
}
|
||||
|
||||
cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) {
|
||||
const char* const* titles = args->titles;
|
||||
const char* const* fileExts = args->filters;
|
||||
cc_string filters; char buffer[NATIVE_STR_LEN];
|
||||
int i;
|
||||
|
||||
/* Filter tokens are \0 separated - e.g. "Map (*.cw)\0*.cw\0 */
|
||||
String_InitArray(filters, buffer);
|
||||
for (i = 0; fileExts[i]; i++)
|
||||
{
|
||||
String_Format2(&filters, "%c (*%c)", titles[i], fileExts[i]);
|
||||
String_Append(&filters, '\0');
|
||||
String_Format1(&filters, "*%c", fileExts[i]);
|
||||
String_Append(&filters, '\0');
|
||||
}
|
||||
return OpenSaveFileDialog(&filters, args->Callback, false, fileExts, &args->defaultName);
|
||||
}
|
||||
|
||||
void Window_AllocFramebuffer(struct Bitmap* bmp, int width, int height) {
|
||||
bmp->scan0 = (BitmapCol*)Mem_Alloc(width * height, BITMAPCOLOR_SIZE, "bitmap");
|
||||
bmp->width = width;
|
||||
bmp->height = height;
|
||||
}
|
||||
|
||||
void Window_DrawFramebuffer(Rect2D r, struct Bitmap* bmp) {
|
||||
}
|
||||
|
||||
void Window_FreeFramebuffer(struct Bitmap* bmp) {
|
||||
Mem_Free(bmp->scan0);
|
||||
}
|
||||
|
||||
static cc_bool rawMouseInited, rawMouseSupported;
|
||||
static void InitRawMouse(void) {
|
||||
|
||||
}
|
||||
|
||||
void OnscreenKeyboard_Open(struct OpenKeyboardArgs* args) { }
|
||||
void OnscreenKeyboard_SetText(const cc_string* text) { }
|
||||
void OnscreenKeyboard_Close(void) { }
|
||||
|
||||
void Window_EnableRawMouse(void) {
|
||||
DefaultEnableRawMouse();
|
||||
if (!rawMouseInited) InitRawMouse();
|
||||
|
||||
rawMouseInited = true;
|
||||
}
|
||||
|
||||
void Window_UpdateRawMouse(void) {
|
||||
if (rawMouseSupported) {
|
||||
/* handled in WM_INPUT messages */
|
||||
CentreMousePosition();
|
||||
} else {
|
||||
DefaultUpdateRawMouse();
|
||||
}
|
||||
}
|
||||
|
||||
void Window_DisableRawMouse(void) {
|
||||
DefaultDisableRawMouse();
|
||||
}
|
||||
|
||||
|
||||
void OpenFileDialog(void) {
|
||||
auto picker = ref new Windows::Storage::Pickers::FileOpenPicker();
|
||||
picker->FileTypeFilter->Append(ref new String(L".jpg"));
|
||||
picker->FileTypeFilter->Append(ref new String(L".jpeg"));
|
||||
picker->FileTypeFilter->Append(ref new String(L".png"));
|
||||
|
||||
//Windows::Storage::StorageFile file = picker->PickSingleFileAsync();
|
||||
}
|
||||
|
||||
ref class CCApp sealed : IFrameworkView
|
||||
{
|
||||
public:
|
||||
virtual void Initialize(CoreApplicationView^ view)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Load(String^ EntryPoint)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Uninitialize()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Run()
|
||||
{
|
||||
CoreWindow^ window = CoreWindow::GetForCurrentThread();
|
||||
window->Activate();
|
||||
|
||||
CoreDispatcher^ dispatcher = window->Dispatcher;
|
||||
dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessUntilQuit);
|
||||
}
|
||||
|
||||
virtual void SetWindow(CoreWindow^ win)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
ref class CCAppSource sealed : IFrameworkViewSource
|
||||
{
|
||||
public:
|
||||
virtual IFrameworkView^ CreateView()
|
||||
{
|
||||
return ref new CCApp();
|
||||
}
|
||||
};
|
||||
|
||||
[MTAThread]
|
||||
int main(Array<String^>^ args)
|
||||
{
|
||||
//init_apartment();
|
||||
auto source = ref new CCAppSource();
|
||||
CoreApplication::Run(source);
|
||||
}
|
@ -121,7 +121,7 @@ static cc_bool CreateLogsDirectory(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static void OpenChatLog(struct DateTime* now) {
|
||||
static void OpenChatLog(struct cc_datetime* now) {
|
||||
cc_result res;
|
||||
int i;
|
||||
if (Platform_ReadonlyFilesystem || !CreateLogsDirectory()) return;
|
||||
@ -154,7 +154,7 @@ static void OpenChatLog(struct DateTime* now) {
|
||||
|
||||
static void AppendChatLog(const cc_string* text) {
|
||||
cc_string str; char strBuffer[DRAWER2D_MAX_TEXT_LENGTH];
|
||||
struct DateTime now;
|
||||
struct cc_datetime now;
|
||||
cc_result res;
|
||||
|
||||
if (!logName.length || !Chat_Logging) return;
|
||||
|
@ -183,6 +183,14 @@ typedef cc_uint8 cc_bool;
|
||||
#define CC_BUILD_NOSOUNDS
|
||||
#define DEFAULT_NET_BACKEND CC_NET_BACKEND_BUILTIN
|
||||
#define DEFAULT_SSL_BACKEND CC_SSL_BACKEND_BEARSSL
|
||||
#elif defined __WRL_NO_DEFAULT_LIB__
|
||||
#undef CC_BUILD_FREETYPE
|
||||
#define CC_BUILD_WIN
|
||||
#define CC_BUILD_UWP
|
||||
#define CC_BUILD_NOMUSIC
|
||||
#define CC_BUILD_NOSOUNDS
|
||||
#define DEFAULT_NET_BACKEND CC_NET_BACKEND_BUILTIN
|
||||
#define DEFAULT_GFX_BACKEND CC_GFX_BACKEND_SOFTGPU
|
||||
#elif defined _WIN32
|
||||
#define CC_BUILD_WIN
|
||||
#define DEFAULT_NET_BACKEND CC_NET_BACKEND_BUILTIN
|
||||
|
@ -586,7 +586,7 @@ static void PerformScheduledTasks(double time) {
|
||||
void Game_TakeScreenshot(void) {
|
||||
cc_string filename; char fileBuffer[STRING_SIZE];
|
||||
cc_string path; char pathBuffer[FILENAME_SIZE];
|
||||
struct DateTime now;
|
||||
struct cc_datetime now;
|
||||
cc_result res;
|
||||
#ifdef CC_BUILD_WEB
|
||||
cc_filepath str;
|
||||
|
@ -1659,11 +1659,10 @@ static void UpdatesScreen_FormatBoth(struct UpdatesScreen* s) {
|
||||
}
|
||||
|
||||
static void UpdatesScreen_UpdateHeader(struct UpdatesScreen* s, cc_string* str) {
|
||||
const char* message;
|
||||
if ( s->release) message = "&eFetching latest release ";
|
||||
if (!s->release) message = "&eFetching latest dev build ";
|
||||
const char* message = s->release ? "release " : "dev build ";
|
||||
|
||||
String_Format2(str, "%c%c", message, Updater_Info.builds[s->buildIndex].name);
|
||||
String_Format2(str, "&eFetching latest %c%c",
|
||||
message, Updater_Info.builds[s->buildIndex].name);
|
||||
}
|
||||
|
||||
static void UpdatesScreen_DoFetch(struct UpdatesScreen* s) {
|
||||
|
33
src/Logger.c
33
src/Logger.c
@ -18,11 +18,15 @@
|
||||
|
||||
#include <windows.h>
|
||||
#include <imagehlp.h>
|
||||
#ifndef CC_BUILD_UWP
|
||||
/* Compatibility version so compiling works on older Windows SDKs */
|
||||
#include "../misc/windows/min-imagehlp.h"
|
||||
#define CC_KERN32_FUNC extern /* main use is Platform_Windows.c */
|
||||
#include "../misc/windows/min-kernel32.h"
|
||||
#endif
|
||||
|
||||
static HANDLE curProcess = CUR_PROCESS_HANDLE;
|
||||
static cc_uintptr spRegister;
|
||||
#elif defined CC_BUILD_OPENBSD || defined CC_BUILD_HAIKU || defined CC_BUILD_SERENITY
|
||||
#include <signal.h>
|
||||
/* These operating systems don't provide sys/ucontext.h */
|
||||
@ -205,7 +209,12 @@ static void PrintFrame(cc_string* str, cc_uintptr addr, cc_uintptr symAddr, cons
|
||||
}
|
||||
}
|
||||
|
||||
#if defined CC_BUILD_WIN
|
||||
#if defined CC_BUILD_UWP
|
||||
static void DumpFrame(cc_string* trace, void* addr) {
|
||||
cc_uintptr addr_ = (cc_uintptr)addr;
|
||||
String_Format1(trace, "%x", &addr_);
|
||||
}
|
||||
#elif defined CC_BUILD_WIN
|
||||
struct SymbolAndName { IMAGEHLP_SYMBOL symbol; char name[256]; };
|
||||
|
||||
static void DumpFrame(HANDLE process, cc_string* trace, cc_uintptr addr) {
|
||||
@ -291,7 +300,11 @@ static void DumpFrame(cc_string* trace, void* addr) {
|
||||
/*########################################################################################################################*
|
||||
*-------------------------------------------------------Backtracing-------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
#if defined CC_BUILD_WIN
|
||||
#if defined CC_BUILD_UWP
|
||||
void Logger_Backtrace(cc_string* trace, void* ctx) {
|
||||
String_AppendConst(trace, "-- backtrace unimplemented --");
|
||||
}
|
||||
#elif defined CC_BUILD_WIN
|
||||
|
||||
static PVOID WINAPI FunctionTableAccessCallback(HANDLE process, _DWORD_PTR addr) {
|
||||
if (!_SymFunctionTableAccess) return NULL;
|
||||
@ -316,7 +329,6 @@ static BOOL WINAPI ReadMemCallback(HANDLE process, _DWORD_PTR baseAddress, PVOID
|
||||
*numBytesRead = (DWORD)numRead; /* DWORD always 32 bits */
|
||||
return ok;
|
||||
}
|
||||
static cc_uintptr spRegister;
|
||||
|
||||
static int GetFrames(CONTEXT* ctx, cc_uintptr* addrs, int max) {
|
||||
STACKFRAME frame = { 0 };
|
||||
@ -923,7 +935,10 @@ static void DumpRegisters(void* ctx) {
|
||||
/*########################################################################################################################*
|
||||
*------------------------------------------------Module/Memory map handling-----------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
#if defined CC_BUILD_WIN
|
||||
#if defined CC_BUILD_UWP
|
||||
static void DumpMisc(void) { }
|
||||
|
||||
#elif defined CC_BUILD_WIN
|
||||
static void DumpStack(void) {
|
||||
static const cc_string stack = String_FromConst("-- stack --\r\n");
|
||||
cc_string str; char strBuffer[128];
|
||||
@ -1121,6 +1136,7 @@ static LONG WINAPI UnhandledFilter(struct _EXCEPTION_POINTERS* info) {
|
||||
void Logger_Hook(void) {
|
||||
OSVERSIONINFOA osInfo;
|
||||
SetUnhandledExceptionFilter(UnhandledFilter);
|
||||
#if !defined CC_BUILD_UWP
|
||||
ImageHlp_LoadDynamicFuncs();
|
||||
|
||||
/* Windows 9x requires process IDs instead - see old DBGHELP docs */
|
||||
@ -1132,6 +1148,7 @@ void Logger_Hook(void) {
|
||||
if (osInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
|
||||
curProcess = (HANDLE)((cc_uintptr)GetCurrentProcessId());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#elif defined CC_BUILD_POSIX
|
||||
static const char* SignalDescribe(int type) {
|
||||
@ -1200,7 +1217,11 @@ void Logger_Hook(void) {
|
||||
/*########################################################################################################################*
|
||||
*-------------------------------------------------Deliberate crash logging------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
#if defined CC_BUILD_WIN
|
||||
#if defined CC_BUILD_UWP
|
||||
void Logger_Abort2(cc_result result, const char* raw_msg) {
|
||||
AbortCommon(result, raw_msg, NULL);
|
||||
}
|
||||
#elif defined CC_BUILD_WIN
|
||||
#if __GNUC__
|
||||
/* Don't want compiler doing anything fancy with registers */
|
||||
void __attribute__((optimize("O0"))) Logger_Abort2(cc_result result, const char* raw_msg) {
|
||||
@ -1270,7 +1291,7 @@ void Logger_Log(const cc_string* msg) {
|
||||
|
||||
static void LogCrashHeader(void) {
|
||||
cc_string msg; char msgBuffer[96];
|
||||
struct DateTime now;
|
||||
struct cc_datetime now;
|
||||
|
||||
String_InitArray(msg, msgBuffer);
|
||||
String_AppendConst(&msg, _NL "----------------------------------------" _NL);
|
||||
|
@ -19,15 +19,14 @@ Copyright 2014-2023 ClassiCube | Licensed under BSD-3
|
||||
/* Suffix added to app name sent to the server */
|
||||
extern const char* Platform_AppNameSuffix;
|
||||
|
||||
#ifdef CC_BUILD_WIN
|
||||
#if defined CC_BUILD_WIN
|
||||
typedef struct cc_winstring_ {
|
||||
cc_unichar uni[NATIVE_STR_LEN]; /* String represented using UTF16 format */
|
||||
char ansi[NATIVE_STR_LEN]; /* String lossily represented using ANSI format */
|
||||
} cc_winstring;
|
||||
|
||||
/* Encodes a string into the platform native string format */
|
||||
void Platform_EncodeString(cc_winstring* dst, const cc_string* src);
|
||||
|
||||
cc_bool Platform_DescribeErrorExt(cc_result res, cc_string* dst, void* lib);
|
||||
#endif
|
||||
|
||||
#ifdef CC_BUILD_WIN
|
||||
@ -200,12 +199,12 @@ cc_bool Platform_DescribeError(cc_result res, cc_string* dst);
|
||||
*#########################################################################################################################*/
|
||||
/* Number of seconds since 01/01/0001 to start of unix time. */
|
||||
#define UNIX_EPOCH_SECONDS 62135596800ULL
|
||||
struct DateTime;
|
||||
struct cc_datetime;
|
||||
|
||||
/* Returns the current UTC time, as number of seconds since 1/1/0001 */
|
||||
CC_API TimeMS DateTime_CurrentUTC(void);
|
||||
/* Returns the current local Time. */
|
||||
CC_API void DateTime_CurrentLocal(struct DateTime* t);
|
||||
CC_API void DateTime_CurrentLocal(struct cc_datetime* t);
|
||||
/* Takes a platform-specific stopwatch measurement. */
|
||||
/* NOTE: The value returned is platform-specific - do NOT try to interpret the value. */
|
||||
CC_API cc_uint64 Stopwatch_Measure(void);
|
||||
|
@ -77,8 +77,8 @@ TimeMS DateTime_CurrentUTC(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DateTime_CurrentLocal(struct DateTime* t) {
|
||||
Mem_Set(t, 0, sizeof(struct DateTime));
|
||||
void DateTime_CurrentLocal(struct cc_datetime* t) {
|
||||
Mem_Set(t, 0, sizeof(struct cc_datetime));
|
||||
}
|
||||
|
||||
|
||||
|
@ -61,7 +61,7 @@ TimeMS DateTime_CurrentUTC(void) {
|
||||
return (cc_uint64)cur.tv_sec + UNIX_EPOCH_SECONDS;
|
||||
}
|
||||
|
||||
void DateTime_CurrentLocal(struct DateTime* t) {
|
||||
void DateTime_CurrentLocal(struct cc_datetime* t) {
|
||||
struct timeval cur;
|
||||
struct tm loc_time;
|
||||
gettimeofday(&cur, NULL);
|
||||
|
@ -99,7 +99,7 @@ TimeMS DateTime_CurrentUTC(void) {
|
||||
return curSecs + UNIX_EPOCH_SECONDS;
|
||||
}
|
||||
|
||||
void DateTime_CurrentLocal(struct DateTime* t) {
|
||||
void DateTime_CurrentLocal(struct cc_datetime* t) {
|
||||
uint32 secs, ms;
|
||||
time_t total_secs;
|
||||
struct tm loc_time;
|
||||
|
@ -85,7 +85,7 @@ TimeMS DateTime_CurrentUTC(void) {
|
||||
return secs + UNIX_EPOCH_SECONDS + GCWII_EPOCH_ADJUST;
|
||||
}
|
||||
|
||||
void DateTime_CurrentLocal(struct DateTime* t) {
|
||||
void DateTime_CurrentLocal(struct cc_datetime* t) {
|
||||
struct timeval cur;
|
||||
struct tm loc_time;
|
||||
gettimeofday(&cur, NULL);
|
||||
|
@ -79,7 +79,7 @@ TimeMS DateTime_CurrentUTC(void) {
|
||||
return (cc_uint64)cur.tv_sec + UNIX_EPOCH_SECONDS;
|
||||
}
|
||||
|
||||
void DateTime_CurrentLocal(struct DateTime* t) {
|
||||
void DateTime_CurrentLocal(struct cc_datetime* t) {
|
||||
struct timeval cur;
|
||||
struct tm loc_time;
|
||||
gettimeofday(&cur, NULL);
|
||||
|
@ -125,7 +125,7 @@ TimeMS DateTime_CurrentUTC(void) {
|
||||
return (cc_uint64)secs + UNIX_EPOCH_SECONDS;
|
||||
}
|
||||
|
||||
void DateTime_CurrentLocal(struct DateTime* t) {
|
||||
void DateTime_CurrentLocal(struct cc_datetime* t) {
|
||||
struct tm loc_time;
|
||||
time_t secs = gettod();
|
||||
localtime_r(&secs, &loc_time);
|
||||
|
@ -55,7 +55,7 @@ TimeMS DateTime_CurrentUTC(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DateTime_CurrentLocal(struct DateTime* t) {
|
||||
void DateTime_CurrentLocal(struct cc_datetime* t) {
|
||||
rtc_time_t curTime = { 0 };
|
||||
rtc_get(&curTime);
|
||||
|
||||
|
@ -95,7 +95,7 @@ TimeMS DateTime_CurrentUTC(void) {
|
||||
return (cc_uint64)cur.tv_sec + UNIX_EPOCH_SECONDS;
|
||||
}
|
||||
|
||||
void DateTime_CurrentLocal(struct DateTime* t) {
|
||||
void DateTime_CurrentLocal(struct cc_datetime* t) {
|
||||
struct timeval cur;
|
||||
struct tm loc_time;
|
||||
gettimeofday(&cur, NULL);
|
||||
|
@ -54,8 +54,8 @@ TimeMS DateTime_CurrentUTC(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DateTime_CurrentLocal(struct DateTime* t) {
|
||||
Mem_Set(t, 0, sizeof(struct DateTime));
|
||||
void DateTime_CurrentLocal(struct cc_datetime* t) {
|
||||
Mem_Set(t, 0, sizeof(struct cc_datetime));
|
||||
}
|
||||
|
||||
|
||||
|
@ -100,7 +100,7 @@ TimeMS DateTime_CurrentUTC(void) {
|
||||
return (cc_uint64)rtc_sec + UNIX_EPOCH_SECONDS;
|
||||
}
|
||||
|
||||
void DateTime_CurrentLocal(struct DateTime* t) {
|
||||
void DateTime_CurrentLocal(struct cc_datetime* t) {
|
||||
time_t rtc_sec = CurrentUnixTime();
|
||||
struct tm loc_time;
|
||||
localtime_r(&rtc_sec, &loc_time);
|
||||
|
@ -60,7 +60,7 @@ TimeMS DateTime_CurrentUTC(void) {
|
||||
return sec + UNIX_EPOCH_SECONDS;
|
||||
}
|
||||
|
||||
void DateTime_CurrentLocal(struct DateTime* t) {
|
||||
void DateTime_CurrentLocal(struct cc_datetime* t) {
|
||||
struct timeval cur;
|
||||
struct tm loc_time;
|
||||
gettimeofday(&cur, NULL);
|
||||
|
@ -63,7 +63,7 @@ TimeMS DateTime_CurrentUTC(void) {
|
||||
return (cc_uint64)cur.tv_sec + UNIX_EPOCH_SECONDS;
|
||||
}
|
||||
|
||||
void DateTime_CurrentLocal(struct DateTime* t) {
|
||||
void DateTime_CurrentLocal(struct cc_datetime* t) {
|
||||
ScePspDateTime curTime;
|
||||
sceRtcGetCurrentClockLocalTime(&curTime);
|
||||
|
||||
|
@ -46,7 +46,7 @@ TimeMS DateTime_CurrentUTC(void) {
|
||||
return (cc_uint64)cur.sec + UNIX_EPOCH_SECONDS;
|
||||
}
|
||||
|
||||
void DateTime_CurrentLocal(struct DateTime* t) {
|
||||
void DateTime_CurrentLocal(struct cc_datetime* t) {
|
||||
SceDateTime curTime;
|
||||
sceRtcGetCurrentClockLocalTime(&curTime);
|
||||
|
||||
|
@ -121,7 +121,7 @@ TimeMS DateTime_CurrentUTC(void) {
|
||||
return (cc_uint64)cur.tv_sec + UNIX_EPOCH_SECONDS;
|
||||
}
|
||||
|
||||
void DateTime_CurrentLocal(struct DateTime* t) {
|
||||
void DateTime_CurrentLocal(struct cc_datetime* t) {
|
||||
struct timeval cur;
|
||||
struct tm loc_time;
|
||||
gettimeofday(&cur, NULL);
|
||||
|
@ -84,8 +84,8 @@ TimeMS DateTime_CurrentUTC(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DateTime_CurrentLocal(struct DateTime* t) {
|
||||
Mem_Set(t, 0, sizeof(struct DateTime));
|
||||
void DateTime_CurrentLocal(struct cc_datetime* t) {
|
||||
Mem_Set(t, 0, sizeof(struct cc_datetime));
|
||||
}
|
||||
|
||||
|
||||
|
@ -92,7 +92,7 @@ TimeMS DateTime_CurrentUTC(void) {
|
||||
return timestamp + UNIX_EPOCH_SECONDS;
|
||||
}
|
||||
|
||||
void DateTime_CurrentLocal(struct DateTime* t) {
|
||||
void DateTime_CurrentLocal(struct cc_datetime* t) {
|
||||
u64 timestamp = 0;
|
||||
TimeCalendarTime calTime = { 0 };
|
||||
timeGetCurrentTime(TimeType_Default, ×tamp);
|
||||
|
@ -93,8 +93,8 @@ TimeMS DateTime_CurrentUTC(void) {
|
||||
return (cc_uint64)cur.tv_sec + UNIX_EPOCH_SECONDS;
|
||||
}
|
||||
|
||||
extern void interop_GetLocalTime(struct DateTime* t);
|
||||
void DateTime_CurrentLocal(struct DateTime* t) {
|
||||
extern void interop_GetLocalTime(struct cc_datetime* t);
|
||||
void DateTime_CurrentLocal(struct cc_datetime* t) {
|
||||
interop_GetLocalTime(t);
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ TimeMS DateTime_CurrentUTC(void) {
|
||||
return secs + UNIX_EPOCH_SECONDS + WIIU_EPOCH_ADJUST;
|
||||
}
|
||||
|
||||
void DateTime_CurrentLocal(struct DateTime* t) {
|
||||
void DateTime_CurrentLocal(struct cc_datetime* t) {
|
||||
struct OSCalendarTime loc_time;
|
||||
OSTicksToCalendarTime(OSGetTime(), &loc_time);
|
||||
|
||||
|
@ -147,7 +147,7 @@ TimeMS DateTime_CurrentUTC(void) {
|
||||
return FileTime_TotalSecs(raw);
|
||||
}
|
||||
|
||||
void DateTime_CurrentLocal(struct DateTime* t) {
|
||||
void DateTime_CurrentLocal(struct cc_datetime* t) {
|
||||
SYSTEMTIME localTime;
|
||||
GetLocalTime(&localTime);
|
||||
|
||||
@ -943,12 +943,11 @@ void Platform_Free(void) {
|
||||
HeapDestroy(heap);
|
||||
}
|
||||
|
||||
cc_bool Platform_DescribeErrorExt(cc_result res, cc_string* dst, void* lib) {
|
||||
cc_bool Platform_DescribeError(cc_result res, cc_string* dst) {
|
||||
WCHAR chars[NATIVE_STR_LEN];
|
||||
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
|
||||
if (lib) flags |= FORMAT_MESSAGE_FROM_HMODULE;
|
||||
|
||||
res = FormatMessageW(flags, lib, res, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
res = FormatMessageW(flags, NULL, res, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
chars, NATIVE_STR_LEN, NULL);
|
||||
if (!res) return false;
|
||||
|
||||
@ -956,10 +955,6 @@ cc_bool Platform_DescribeErrorExt(cc_result res, cc_string* dst, void* lib) {
|
||||
return true;
|
||||
}
|
||||
|
||||
cc_bool Platform_DescribeError(cc_result res, cc_string* dst) {
|
||||
return Platform_DescribeErrorExt(res, dst, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-------------------------------------------------------Encryption--------------------------------------------------------*
|
||||
|
@ -54,7 +54,7 @@ TimeMS DateTime_CurrentUTC(void) {
|
||||
return FileTime_TotalSecs(ft.QuadPart);
|
||||
}
|
||||
|
||||
void DateTime_CurrentLocal(struct DateTime* t) {
|
||||
void DateTime_CurrentLocal(struct cc_datetime* t) {
|
||||
SYSTEMTIME localTime;
|
||||
GetLocalTime(&localTime);
|
||||
|
||||
|
@ -52,7 +52,7 @@ TimeMS DateTime_CurrentUTC(void) {
|
||||
return (cc_uint64)cur.tv_sec + UNIX_EPOCH_SECONDS;
|
||||
}
|
||||
|
||||
void DateTime_CurrentLocal(struct DateTime* t) {
|
||||
void DateTime_CurrentLocal(struct cc_datetime* t) {
|
||||
struct timeval cur;
|
||||
struct tm loc_time;
|
||||
gettimeofday(&cur, NULL);
|
||||
|
@ -92,7 +92,7 @@ static cc_result ZipEntry_ExtractData(struct ResourceZipEntry* e, struct Stream*
|
||||
*------------------------------------------------------Zip entry writer---------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
static void GetCurrentZipDate(int* modTime, int* modDate) {
|
||||
struct DateTime now;
|
||||
struct cc_datetime now;
|
||||
DateTime_CurrentLocal(&now);
|
||||
|
||||
*modTime = (now.second / 2) | (now.minute << 5) | (now.hour << 11);
|
||||
|
@ -13,7 +13,7 @@ struct StringsBuffer;
|
||||
/* Represents a particular instance in time in some timezone. Not necessarily UTC time. */
|
||||
/* NOTE: TimeMS and DateTime_CurrentUTC() should almost always be used instead. */
|
||||
/* This struct should only be used when actually needed. (e.g. log message time) */
|
||||
struct DateTime {
|
||||
struct cc_datetime {
|
||||
int year; /* Year, ranges from 0 to 65535 */
|
||||
int month; /* Month, ranges from 1 to 12 */
|
||||
int day; /* Day, ranges from 1 to 31 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user