#define _WIN32_WINNT 0x0501 #include #include #include #include #include #include #define ID_USERNAME 101 #define ID_PASSWORD 102 #define ID_LOGIN 103 #define ID_REFRESH 104 #define ID_OUTPUT 105 #define ID_STATUS 106 #define ID_DATE 107 #define ID_ROUTES 108 #define ID_STOPS 109 #define MAX_BUF 65535 #define API_HOST "192.168.68.66" #define AUTH_PORT 5000 #define TRANSIT_PORT 5001 typedef struct { HWND hwnd; char token[512]; char lastText[8192]; int routeCount; int routeLineIds[32]; char routeLabels[32][256]; } APPSTATE; static void SetStatusText(HWND hwnd, const char *text) { SetWindowTextA(GetDlgItem(hwnd, ID_STATUS), text); } static void SetOutputText(HWND hwnd, const char *text) { SetWindowTextA(GetDlgItem(hwnd, ID_OUTPUT), text); } static void TrimNewlines(char *text) { size_t len = strlen(text); while (len > 0 && (text[len - 1] == '\n' || text[len - 1] == '\r' || text[len - 1] == ' ')) { text[len - 1] = '\0'; len--; } } static void ExtractJsonFieldString(const char *json, const char *field, char *out, size_t outSize) { char pattern[128]; const char *key; const char *colon; const char *value; const char *end; out[0] = '\0'; if (!json || !field || outSize == 0) { return; } snprintf(pattern, sizeof(pattern), "\"%s\"", field); key = strstr(json, pattern); if (!key) { return; } colon = strchr(key + strlen(pattern), ':'); if (!colon) { return; } value = colon + 1; while (*value == ' ' || *value == '\t' || *value == '\n' || *value == '\r') { value++; } if (*value == '"') { const char *q1 = value + 1; const char *q2 = strchr(q1, '"'); size_t len; if (!q2) { return; } len = (size_t)(q2 - q1); if (len >= outSize) { len = outSize - 1; } memcpy(out, q1, len); out[len] = '\0'; return; } end = value; while (*end && *end != ',' && *end != '}' && *end != '\n' && *end != '\r') { end++; } if (end == value) { return; } size_t len = (size_t)(end - value); while (len > 0 && (value[len - 1] == ' ' || value[len - 1] == '\t' || value[len - 1] == '\r' || value[len - 1] == '\n')) { len--; } if (len >= outSize) { len = outSize - 1; } memcpy(out, value, len); out[len] = '\0'; } static char *FindObjectEnd(char *start) { int depth = 0; char *p = start; while (*p) { if (*p == '{') { depth++; } else if (*p == '}') { depth--; if (depth == 0) { return p; } } p++; } return NULL; } static void ExtractScheduleSummary(const char *json, APPSTATE *state, char *out, size_t outSize) { const char *routesKey; const char *p; char routeSummary[2048]; char summary[8192]; int routeCount = 0; out[0] = '\0'; summary[0] = '\0'; routeSummary[0] = '\0'; state->routeCount = 0; SendMessage(GetDlgItem(state->hwnd, ID_ROUTES), LB_RESETCONTENT, 0, 0); routesKey = strstr(json, "\"routes\""); if (!routesKey) { snprintf(out, outSize, "No routes found for this date."); return; } p = strchr(routesKey, '['); if (!p) { snprintf(out, outSize, "No routes found for this date."); return; } p++; while (*p) { char *objStart = strchr((char *)p, '{'); char *objEnd; char routeText[2048]; char routeLine[128]; char routeStatus[128]; char routeStart[128]; char routeEnd[128]; char routeStartStop[128]; char routeEndStop[128]; char routeLineId[32]; char routeStartTime[128]; if (!objStart) { break; } objEnd = FindObjectEnd(objStart); if (!objEnd) { break; } if ((size_t)(objEnd - objStart + 1) >= sizeof(routeText)) { break; } memcpy(routeText, objStart, objEnd - objStart + 1); routeText[objEnd - objStart + 1] = '\0'; routeLine[0] = '\0'; routeStatus[0] = '\0'; routeStart[0] = '\0'; routeEnd[0] = '\0'; routeStartStop[0] = '\0'; routeEndStop[0] = '\0'; routeLineId[0] = '\0'; routeStartTime[0] = '\0'; ExtractJsonFieldString(routeText, "lineNumber", routeLine, sizeof(routeLine)); ExtractJsonFieldString(routeText, "startTime", routeStartTime, sizeof(routeStartTime)); ExtractJsonFieldString(routeText, "id", routeLineId, sizeof(routeLineId)); if (routeLine[0] == '\0') { char busLine[1024]; const char *busKey = strstr(routeText, "\"busLine\""); if (busKey) { const char *busStart = strchr(busKey, '{'); if (busStart) { char *busEnd = FindObjectEnd((char *)busStart); if (busEnd) { size_t busLen = (size_t)(busEnd - busStart + 1); if (busLen < sizeof(busLine)) { memcpy(busLine, busStart, busLen); busLine[busLen] = '\0'; ExtractJsonFieldString(busLine, "lineNumber", routeLine, sizeof(routeLine)); ExtractJsonFieldString(busLine, "id", routeLineId, sizeof(routeLineId)); ExtractJsonFieldString(busLine, "startStop", routeStartStop, sizeof(routeStartStop)); ExtractJsonFieldString(busLine, "endStop", routeEndStop, sizeof(routeEndStop)); } } } } } ExtractJsonFieldString(routeText, "status", routeStatus, sizeof(routeStatus)); ExtractJsonFieldString(routeText, "startTime", routeStart, sizeof(routeStart)); ExtractJsonFieldString(routeText, "endTime", routeEnd, sizeof(routeEnd)); if (routeStartStop[0] == '\0') { ExtractJsonFieldString(routeText, "startStop", routeStartStop, sizeof(routeStartStop)); } if (routeEndStop[0] == '\0') { ExtractJsonFieldString(routeText, "endStop", routeEndStop, sizeof(routeEndStop)); } if (routeLine[0] == '\0') { snprintf(routeLine, sizeof(routeLine), "R%d", routeCount + 1); } if (routeStatus[0] == '\0') { snprintf(routeStatus, sizeof(routeStatus), "planned"); } if (routeStartStop[0] == '\0') { snprintf(routeStartStop, sizeof(routeStartStop), "N/A"); } if (routeEndStop[0] == '\0') { snprintf(routeEndStop, sizeof(routeEndStop), "N/A"); } routeCount++; if (state->routeCount < 32) { state->routeLineIds[state->routeCount] = atoi(routeLineId); snprintf(state->routeLabels[state->routeCount], sizeof(state->routeLabels[state->routeCount]), "Line %s %s %s", routeLine, routeStart, routeStatus); SendMessageA(GetDlgItem(state->hwnd, ID_ROUTES), LB_ADDSTRING, 0, (LPARAM)state->routeLabels[state->routeCount]); state->routeCount++; } snprintf(routeSummary + strlen(routeSummary), sizeof(routeSummary) - strlen(routeSummary), "Route %s: %s -> %s | %s | %s\r\n", routeLine, routeStartStop, routeEndStop, routeStart, routeStatus); p = objEnd + 1; while (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t' || *p == ',') { p++; } if (*p == ']' || *p == '\0') { break; } } if (routeCount == 0) { snprintf(out, outSize, "No routes found for this date."); return; } snprintf(summary, sizeof(summary), "Daily schedule (%d route%s)\r\n\r\n%s", routeCount, routeCount == 1 ? "" : "s", routeSummary); TrimNewlines(summary); snprintf(out, outSize, "%s", summary); } static void ExtractStopsSummary(const char *json, char *out, size_t outSize) { const char *stopsKey = strstr(json, "\"stops\""); const char *p; char summary[4096]; int count = 0; summary[0] = '\0'; if (!stopsKey || !(p = strchr(stopsKey, '['))) { snprintf(out, outSize, "No stop details were returned for this route."); return; } p++; while (*p && *p != ']') { char *start = strchr((char *)p, '{'); char *end; char item[1024]; char order[32]; char name[128]; char eta[32]; if (!start || !(end = FindObjectEnd(start))) { break; } if ((size_t)(end - start + 1) >= sizeof(item)) { break; } memcpy(item, start, end - start + 1); item[end - start + 1] = '\0'; ExtractJsonFieldString(item, "order", order, sizeof(order)); ExtractJsonFieldString(item, "name", name, sizeof(name)); ExtractJsonFieldString(item, "estimatedArrivalMinutes", eta, sizeof(eta)); if (name[0] == '\0') { snprintf(name, sizeof(name), "Unnamed stop"); } if (eta[0] == '\0') { snprintf(eta, sizeof(eta), "-"); } snprintf(summary + strlen(summary), sizeof(summary) - strlen(summary), "%s. %s (arrival +%s min)\r\n", order, name, eta); count++; p = end + 1; while (*p == ' ' || *p == '\r' || *p == '\n' || *p == '\t' || *p == ',') { p++; } } if (count == 0) { snprintf(out, outSize, "No stop details were returned for this route."); return; } snprintf(out, outSize, "Stop-by-stop timetable (%d stops)\r\n\r\n%s", count, summary); } static void ExtractTokenFromJson(const char *json, char *outToken, size_t outSize) { const char *tokenKey = strstr(json, "\"token\""); const char *q1; const char *q2; outToken[0] = '\0'; if (!tokenKey) { return; } q1 = strchr(tokenKey, ':'); if (!q1) { return; } q1 = strchr(q1 + 1, '"'); if (!q1) { return; } q2 = strchr(q1 + 1, '"'); if (!q2) { return; } q1++; if ((size_t)(q2 - q1) >= outSize) { strncpy(outToken, q1, outSize - 1); outToken[outSize - 1] = '\0'; return; } memcpy(outToken, q1, q2 - q1); outToken[q2 - q1] = '\0'; } static void HttpErrorMessage(const char *context, DWORD error) { char text[256]; snprintf(text, sizeof(text), "%s (WinHTTP error %lu)", context, error); MessageBoxA(NULL, text, "Driver app error", MB_ICONERROR | MB_OK); } static int HttpRequestText(const char *method, const char *url, const char *body, const char *authHeader, char *response, size_t responseSize) { HINTERNET hSession = NULL; HINTERNET hConnect = NULL; HINTERNET hRequest = NULL; wchar_t hostW[256]; wchar_t pathW[512]; wchar_t methodW[32]; char host[256]; char path[512]; const char *src; const char *slash; const char *colon; int port = 80; DWORD flags = 0; DWORD status = 0; DWORD statusLen = sizeof(status); DWORD bytesRead = 0; DWORD totalRead = 0; char buffer[MAX_BUF]; int ok = 0; response[0] = '\0'; src = url; if (strncmp(src, "http://", 7) == 0) { src += 7; } else if (strncmp(src, "https://", 8) == 0) { src += 8; } host[0] = '\0'; path[0] = '/'; path[1] = '\0'; slash = strchr(src, '/'); colon = strchr(src, ':'); if (slash) { size_t hostLen = (size_t)(slash - src); if (hostLen >= sizeof(host)) { hostLen = sizeof(host) - 1; } memcpy(host, src, hostLen); host[hostLen] = '\0'; snprintf(path, sizeof(path), "%.*s", (int)(strlen(slash)), slash); } else if (colon) { size_t hostLen = (size_t)(colon - src); if (hostLen >= sizeof(host)) { hostLen = sizeof(host) - 1; } memcpy(host, src, hostLen); host[hostLen] = '\0'; port = atoi(colon + 1); snprintf(path, sizeof(path), "/"); } else { snprintf(host, sizeof(host), "%s", src); snprintf(path, sizeof(path), "/"); } if (colon && slash) { size_t hostLen = (size_t)(colon - src); if (hostLen >= sizeof(host)) { hostLen = sizeof(host) - 1; } memcpy(host, src, hostLen); host[hostLen] = '\0'; port = atoi(colon + 1); } if (host[0] == '\0') { snprintf(host, sizeof(host), "192.168.68.66"); } if (port == 0) { port = 80; } MultiByteToWideChar(CP_UTF8, 0, host, -1, hostW, 256); MultiByteToWideChar(CP_UTF8, 0, path, -1, pathW, 512); MultiByteToWideChar(CP_UTF8, 0, method, -1, methodW, 32); hSession = WinHttpOpen(L"TransitDriverXP/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); if (!hSession) { HttpErrorMessage("Unable to open WinHTTP session", GetLastError()); return 0; } hConnect = WinHttpConnect(hSession, hostW, port, 0); if (!hConnect) { char hostText[256]; char errorText[512]; WideCharToMultiByte(CP_UTF8, 0, hostW, -1, hostText, sizeof(hostText), NULL, NULL); snprintf(errorText, sizeof(errorText), "Unable to connect to %s:%d", hostText, port); HttpErrorMessage(errorText, GetLastError()); goto cleanup; } hRequest = WinHttpOpenRequest(hConnect, methodW, pathW, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0); if (!hRequest) { HttpErrorMessage("Unable to open request", GetLastError()); goto cleanup; } if (body != NULL && body[0] != '\0') { if (!WinHttpAddRequestHeaders(hRequest, L"Content-Type: application/json\r\n", -1, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE)) { HttpErrorMessage("Unable to add JSON content type", GetLastError()); goto cleanup; } } if (authHeader && authHeader[0] != '\0') { wchar_t wHeader[512]; MultiByteToWideChar(CP_UTF8, 0, authHeader, -1, wHeader, 512); if (!WinHttpAddRequestHeaders(hRequest, wHeader, -1, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE)) { HttpErrorMessage("Unable to add authorization header", GetLastError()); goto cleanup; } } if (!WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, (LPVOID)body, body ? (DWORD)strlen(body) : 0, body ? (DWORD)strlen(body) : 0, 0)) { HttpErrorMessage("WinHTTP send request failed", GetLastError()); goto cleanup; } if (!WinHttpReceiveResponse(hRequest, NULL)) { HttpErrorMessage("WinHTTP receive response failed", GetLastError()); goto cleanup; } if (!WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &status, &statusLen, WINHTTP_NO_HEADER_INDEX)) { HttpErrorMessage("Unable to query HTTP status", GetLastError()); goto cleanup; } if (status >= 400) { snprintf(response, responseSize, "HTTP error %lu", status); ok = 0; goto cleanup; } while (WinHttpQueryDataAvailable(hRequest, &bytesRead) && bytesRead > 0) { DWORD actual = 0; if (!WinHttpReadData(hRequest, buffer, sizeof(buffer) - 1, &actual)) { HttpErrorMessage("Unable to read response data", GetLastError()); goto cleanup; } if (actual == 0) { break; } buffer[actual] = '\0'; if (totalRead + actual + 1 < responseSize) { memcpy(response + totalRead, buffer, actual); totalRead += actual; response[totalRead] = '\0'; } } ok = 1; cleanup: if (hRequest) { WinHttpCloseHandle(hRequest); } if (hConnect) { WinHttpCloseHandle(hConnect); } if (hSession) { WinHttpCloseHandle(hSession); } return ok; } static void PerformLogin(HWND hwnd, APPSTATE *state) { char userCode[128]; char password[128]; char payload[512]; char response[MAX_BUF]; char token[256]; GetWindowTextA(GetDlgItem(hwnd, ID_USERNAME), userCode, sizeof(userCode)); GetWindowTextA(GetDlgItem(hwnd, ID_PASSWORD), password, sizeof(password)); if (userCode[0] == '\0' || password[0] == '\0') { SetStatusText(hwnd, "Enter user code and password."); return; } snprintf(payload, sizeof(payload), "{\"userCode\":\"%s\",\"password\":\"%s\"}", userCode, password); SetStatusText(hwnd, "Logging in..."); if (!HttpRequestText("POST", "http://192.168.68.66:5000/login", payload, NULL, response, sizeof(response))) { SetOutputText(hwnd, "Login failed. Check that auth_api is running on 192.168.68.66:5000."); SetStatusText(hwnd, "Login failed"); return; } ExtractTokenFromJson(response, token, sizeof(token)); if (token[0] == '\0') { SetOutputText(hwnd, response); SetStatusText(hwnd, "No token returned"); return; } strncpy(state->token, token, sizeof(state->token) - 1); state->token[sizeof(state->token) - 1] = '\0'; snprintf(state->lastText, sizeof(state->lastText), "Login succeeded. Driver session ready.\r\nUse Refresh schedule to load the route list."); SetOutputText(hwnd, state->lastText); SetStatusText(hwnd, "Connected"); } static void PerformRefresh(HWND hwnd, APPSTATE *state) { char response[MAX_BUF]; char authHeader[512]; char date[32]; char scheduleUrl[256]; if (state->token[0] == '\0') { SetStatusText(hwnd, "Login first."); return; } snprintf(authHeader, sizeof(authHeader), "Authorization: Bearer %s\r\n", state->token); GetWindowTextA(GetDlgItem(hwnd, ID_DATE), date, sizeof(date)); if (date[0] == '\0') { snprintf(date, sizeof(date), "2026-09-17"); } snprintf(scheduleUrl, sizeof(scheduleUrl), "http://192.168.68.66:5001/schedule/daily?date=%s", date); SetStatusText(hwnd, "Loading schedule..."); if (!HttpRequestText("GET", scheduleUrl, NULL, authHeader, response, sizeof(response))) { SetOutputText(hwnd, "Unable to load daily schedule. Check that transit_api is running on 192.168.68.66:5001."); SetStatusText(hwnd, "Schedule load failed"); return; } ExtractScheduleSummary(response, state, state->lastText, sizeof(state->lastText)); SetOutputText(hwnd, state->lastText); SetStatusText(hwnd, "Schedule loaded"); } static void PerformLoadStops(HWND hwnd, APPSTATE *state) { char response[MAX_BUF]; char authHeader[512]; char stopsUrl[256]; LRESULT selected; int lineId; if (state->token[0] == '\0') { SetStatusText(hwnd, "Login first."); return; } selected = SendMessage(GetDlgItem(hwnd, ID_ROUTES), LB_GETCURSEL, 0, 0); if (selected == LB_ERR || selected >= state->routeCount) { SetStatusText(hwnd, "Select a route first."); return; } lineId = state->routeLineIds[selected]; if (lineId <= 0) { SetOutputText(hwnd, "This schedule does not contain a valid bus line ID."); SetStatusText(hwnd, "Stop details unavailable"); return; } snprintf(authHeader, sizeof(authHeader), "Authorization: Bearer %s\r\n", state->token); snprintf(stopsUrl, sizeof(stopsUrl), "http://192.168.68.66:5001/bus-lines/%d/stops", lineId); SetStatusText(hwnd, "Loading stop details..."); if (!HttpRequestText("GET", stopsUrl, NULL, authHeader, response, sizeof(response))) { SetOutputText(hwnd, "Unable to load stops for this route. Check the transit API connection."); SetStatusText(hwnd, "Stop details failed"); return; } ExtractStopsSummary(response, state->lastText, sizeof(state->lastText)); SetOutputText(hwnd, state->lastText); SetStatusText(hwnd, "Stop details loaded"); } static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { static APPSTATE *state = NULL; HWND hUser, hPassword, hLogin, hRefresh, hOutput, hStatus; switch (msg) { case WM_CREATE: { LPCREATESTRUCT cs = (LPCREATESTRUCT)lParam; state = (APPSTATE *)calloc(1, sizeof(APPSTATE)); state->hwnd = hwnd; cs->lpCreateParams = state; SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)state); CreateWindowExA(0, "STATIC", "TRANSIT DRIVER CONSOLE", WS_CHILD | WS_VISIBLE, 20, 10, 330, 24, hwnd, NULL, ((LPCREATESTRUCT)lParam)->hInstance, NULL); CreateWindowExA(0, "STATIC", "Schedule date (YYYY-MM-DD)", WS_CHILD | WS_VISIBLE, 20, 38, 150, 20, hwnd, NULL, ((LPCREATESTRUCT)lParam)->hInstance, NULL); CreateWindowExA(0, "EDIT", "2026-09-17", WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL, 175, 36, 130, 24, hwnd, (HMENU)ID_DATE, ((LPCREATESTRUCT)lParam)->hInstance, NULL); CreateWindowExA(0, "STATIC", "User code", WS_CHILD | WS_VISIBLE, 20, 72, 90, 20, hwnd, NULL, ((LPCREATESTRUCT)lParam)->hInstance, NULL); hUser = CreateWindowExA(0, "EDIT", "", WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL, 120, 70, 180, 24, hwnd, (HMENU)ID_USERNAME, ((LPCREATESTRUCT)lParam)->hInstance, NULL); SetFocus(hUser); CreateWindowExA(0, "STATIC", "Password", WS_CHILD | WS_VISIBLE, 20, 104, 90, 20, hwnd, NULL, ((LPCREATESTRUCT)lParam)->hInstance, NULL); hPassword = CreateWindowExA(0, "EDIT", "", WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_PASSWORD | ES_AUTOHSCROLL, 120, 102, 180, 24, hwnd, (HMENU)ID_PASSWORD, ((LPCREATESTRUCT)lParam)->hInstance, NULL); hLogin = CreateWindowExA(0, "BUTTON", "Login", WS_CHILD | WS_VISIBLE | WS_TABSTOP, 120, 138, 90, 30, hwnd, (HMENU)ID_LOGIN, ((LPCREATESTRUCT)lParam)->hInstance, NULL); hRefresh = CreateWindowExA(0, "BUTTON", "Refresh schedule", WS_CHILD | WS_VISIBLE | WS_TABSTOP, 220, 138, 130, 30, hwnd, (HMENU)ID_REFRESH, ((LPCREATESTRUCT)lParam)->hInstance, NULL); hStatus = CreateWindowExA(0, "STATIC", "Idle", WS_CHILD | WS_VISIBLE, 20, 178, 500, 22, hwnd, (HMENU)ID_STATUS, ((LPCREATESTRUCT)lParam)->hInstance, NULL); CreateWindowExA(0, "STATIC", "TODAY'S ROUTES", WS_CHILD | WS_VISIBLE, 20, 208, 200, 20, hwnd, NULL, ((LPCREATESTRUCT)lParam)->hInstance, NULL); CreateWindowExA(WS_EX_CLIENTEDGE, "LISTBOX", "", WS_CHILD | WS_VISIBLE | WS_TABSTOP | LBS_NOTIFY | WS_VSCROLL, 20, 230, 500, 105, hwnd, (HMENU)ID_ROUTES, ((LPCREATESTRUCT)lParam)->hInstance, NULL); hOutput = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_MULTILINE | ES_READONLY, 20, 345, 500, 190, hwnd, (HMENU)ID_OUTPUT, ((LPCREATESTRUCT)lParam)->hInstance, NULL); CreateWindowExA(0, "BUTTON", "Show selected route stops", WS_CHILD | WS_VISIBLE | WS_TABSTOP, 20, 545, 190, 30, hwnd, (HMENU)ID_STOPS, ((LPCREATESTRUCT)lParam)->hInstance, NULL); SetWindowTextA(hOutput, "Driver console ready.\r\nLog in, choose a date, and refresh the schedule."); return 0; } case WM_COMMAND: if (LOWORD(wParam) == ID_LOGIN && HIWORD(wParam) == BN_CLICKED) { state = (APPSTATE *)GetWindowLongPtr(hwnd, GWLP_USERDATA); PerformLogin(hwnd, state); return 0; } if (LOWORD(wParam) == ID_REFRESH && HIWORD(wParam) == BN_CLICKED) { state = (APPSTATE *)GetWindowLongPtr(hwnd, GWLP_USERDATA); PerformRefresh(hwnd, state); return 0; } if (LOWORD(wParam) == ID_STOPS && HIWORD(wParam) == BN_CLICKED) { state = (APPSTATE *)GetWindowLongPtr(hwnd, GWLP_USERDATA); PerformLoadStops(hwnd, state); return 0; } break; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, msg, wParam, lParam); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSA wc; HWND hwnd; MSG msg; memset(&wc, 0, sizeof(wc)); wc.lpfnWndProc = WndProc; wc.hInstance = hInstance; wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); wc.lpszClassName = "TransitDriverXPClass"; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.style = CS_HREDRAW | CS_VREDRAW; if (!RegisterClassA(&wc)) { MessageBoxA(NULL, "Failed to register window class.", "XP Driver App", MB_ICONERROR | MB_OK); return 1; } hwnd = CreateWindowExA(0, "TransitDriverXPClass", "Transit Driver XP", WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, 560, 640, NULL, NULL, hInstance, NULL); if (!hwnd) { MessageBoxA(NULL, "Failed to create window.", "XP Driver App", MB_ICONERROR | MB_OK); return 1; } ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; }