-
-
Save Dove6/6d10d49d97bf523592d4b46a274e6be4 to your computer and use it in GitHub Desktop.
RiK3Wide v0.1.0 - kod źródłowy załączonych programów
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#undef UNICODE | |
#undef _UNICODE | |
#include <cmath> | |
#include <cstdio> | |
#include <cstdlib> | |
#include <memory> | |
#include <string> | |
#define WIN32_LEAN_AND_MEAN | |
#undef _WIN32_WINNT | |
#define _WIN32_WINNT 0x0600 | |
#include <comdef.h> | |
#include <dshow.h> | |
#include <tlhelp32.h> | |
#include <windows.h> | |
#define WM_MEDIAEVENT (WM_USER + 1337) | |
#define TIMER_ID 1337 | |
IGraphBuilder *graph = nullptr; | |
IMediaControl *media_control = nullptr; | |
IMediaEvent *media_event = nullptr; | |
IMediaEventEx *media_event_ex = nullptr; | |
IBaseFilter *video_renderer = nullptr; | |
IVMRAspectRatioControl *aspect_ratio_control = nullptr; | |
IVideoWindow *video_window = nullptr; | |
IBasicAudio *basic_audio = nullptr; | |
void print_error(const char *message, const char *details = nullptr) | |
{ | |
static const std::string base = "cutscenes.exe [ERROR] "; | |
std::string concated_str; | |
if (details != nullptr) | |
concated_str = (base + message + ": " + details).c_str(); | |
else | |
concated_str = (base + message).c_str(); | |
OutputDebugString(concated_str.c_str()); | |
fprintf(stderr, "%s\n", concated_str.c_str()); | |
} | |
wchar_t *to_wide(const char *str) | |
{ | |
int required_length = MultiByteToWideChar(CP_ACP, 0, str, -1, nullptr, 0); | |
wchar_t *wide_str = new wchar_t[required_length]; | |
int used_length = MultiByteToWideChar(CP_ACP, 0, str, -1, wide_str, required_length); | |
if (required_length == used_length) | |
return wide_str; | |
delete[] wide_str; | |
return nullptr; | |
} | |
char *from_wide(const wchar_t *wide_str) | |
{ | |
int required_length = WideCharToMultiByte(CP_ACP, 0, wide_str, -1, nullptr, 0, NULL, NULL); | |
char *str = new char[required_length]; | |
int used_length = WideCharToMultiByte(CP_ACP, 0, wide_str, -1, str, required_length, NULL, NULL); | |
if (required_length == used_length) | |
return str; | |
delete[] str; | |
return nullptr; | |
} | |
// source: https://stackoverflow.com/a/6218957 | |
bool is_file(const char *path) | |
{ | |
DWORD dwAttrib = GetFileAttributes(path); | |
return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); | |
} | |
void remove_border(HWND hwnd) | |
{ | |
long style = GetWindowLong(hwnd, GWL_STYLE); | |
style &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU); | |
SetWindowLong(hwnd, GWL_STYLE, style); | |
style = GetWindowLong(hwnd, GWL_EXSTYLE); | |
style &= ~(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE); | |
SetWindowLong(hwnd, GWL_EXSTYLE, style); | |
} | |
void remove_border(IVideoWindow *window) | |
{ | |
long style = 0; | |
window->get_WindowStyle(&style); | |
style &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU); | |
window->put_WindowStyle(style); | |
style = 0; | |
window->get_WindowStyleEx(&style); | |
style &= ~(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE); | |
window->put_WindowStyle(style); | |
} | |
// based on: https://stackoverflow.com/a/11912507 | |
DWORD get_parent_pid(DWORD pid) | |
{ | |
HANDLE snapshot = NULL; | |
PROCESSENTRY32 process_entry = {0}; | |
process_entry.dwSize = sizeof(PROCESSENTRY32); | |
BOOL result = true; | |
snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, pid); | |
if (snapshot == INVALID_HANDLE_VALUE) | |
return 0; | |
for (result = Process32First(snapshot, &process_entry); result; result = Process32Next(snapshot, &process_entry)) | |
if (process_entry.th32ProcessID == pid) | |
break; | |
CloseHandle(snapshot); | |
return result ? process_entry.th32ParentProcessID : 0; | |
} | |
std::string get_parent_pname(HWND hwnd) | |
{ | |
if (hwnd == NULL) | |
return ""; | |
DWORD console_pid = 0, console_parent_pid = 0; | |
GetWindowThreadProcessId(hwnd, &console_pid); | |
if ((console_parent_pid = get_parent_pid(console_pid)) == 0) | |
return ""; | |
HANDLE console_handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, console_parent_pid); | |
if (console_handle == NULL) | |
return ""; | |
char buffer[MAX_PATH + 1] = {0}; | |
DWORD buffer_size = MAX_PATH + 1; | |
BOOL result = QueryFullProcessImageName(console_handle, 0, buffer, &buffer_size); | |
CloseHandle(console_handle); | |
return result ? std::string(buffer) : ""; | |
} | |
bool initialize_objects(const char *movie_filename) | |
{ | |
std::unique_ptr<wchar_t[]> wide_filename(to_wide(movie_filename)); | |
if (!wide_filename) { | |
print_error("char -> wchar_t conversion failed"); | |
return false; | |
} | |
HRESULT result = S_OK; | |
result = CoInitialize(NULL); | |
if (result != S_OK && result != S_FALSE) { | |
print_error("COM initialization failed", _com_error(result).ErrorMessage()); | |
return false; | |
} | |
result = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&graph); | |
if (result != S_OK) { | |
print_error("Filter Graph creation failed", _com_error(result).ErrorMessage()); | |
return false; | |
} | |
result = graph->QueryInterface(IID_IMediaControl, (void **)&media_control); | |
if (result != S_OK) { | |
print_error("IMediaControl interface query failed", _com_error(result).ErrorMessage()); | |
return false; | |
} | |
result = graph->QueryInterface(IID_IMediaEvent, (void **)&media_event); | |
if (result != S_OK) { | |
print_error("IMediaEvent interface query failed", _com_error(result).ErrorMessage()); | |
return false; | |
} | |
result = graph->QueryInterface(IID_IMediaEventEx, (void **)&media_event_ex); | |
if (result != S_OK) { | |
print_error("IMediaEventEx interface query failed", _com_error(result).ErrorMessage()); | |
return false; | |
} | |
result = graph->RenderFile(wide_filename.get(), NULL); | |
if (result != S_OK && result != VFW_S_DUPLICATE_NAME) { | |
print_error("File rendering failed", _com_error(result).ErrorMessage()); | |
return false; | |
} | |
result = graph->FindFilterByName(L"Video Renderer", &video_renderer); | |
if (result != S_OK) { | |
print_error("Video Renderer query failed", _com_error(result).ErrorMessage()); | |
return false; | |
} | |
result = video_renderer->QueryInterface(IID_IVMRAspectRatioControl, (void**)&aspect_ratio_control); | |
if (result != S_OK) { | |
print_error("IVMRAspectRatioControl interface query failed", _com_error(result).ErrorMessage()); | |
return false; | |
} | |
result = graph->QueryInterface(IID_IVideoWindow, (void **)&video_window); | |
if (result != S_OK) { | |
print_error("IVideoWindow interface query failed", _com_error(result).ErrorMessage()); | |
return false; | |
} | |
result = graph->QueryInterface(IID_IBasicAudio, (void **)&basic_audio); | |
if (result != S_OK) { | |
print_error("IBasicAudio interface query failed", _com_error(result).ErrorMessage()); | |
return false; | |
} | |
return true; | |
} | |
void destroy_objects() | |
{ | |
if (basic_audio != nullptr) | |
basic_audio->Release(); | |
if (video_window != nullptr) | |
video_window->Release(); | |
if (aspect_ratio_control != nullptr) | |
aspect_ratio_control->Release(); | |
if (video_renderer != nullptr) | |
video_renderer->Release(); | |
if (media_event != nullptr) | |
media_event->Release(); | |
if (media_control != nullptr) | |
media_control->Release(); | |
if (graph != nullptr) | |
graph->Release(); | |
CoUninitialize(); | |
} | |
LRESULT CALLBACK window_proc(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam); | |
int main(int argc, const char **argv) | |
{ | |
HWND console_hwnd = GetConsoleWindow(); | |
std::string parent_pname = get_parent_pname(console_hwnd); | |
if (parent_pname == "ki.exe" || parent_pname.find("\\ki.exe") != std::string::npos || parent_pname.find("/ki.exe") != std::string::npos) | |
ShowWindow(console_hwnd, SW_HIDE); | |
/* Process arguments */ | |
if (argc != 2 && argc != 3) { | |
print_error(("Usage: " + std::string(argv[0]) + " filename [volume]\n").c_str()); | |
return EXIT_FAILURE; | |
} | |
if (!is_file(argv[1])) { | |
print_error((std::string(argv[1]) + " is not a file").c_str()); | |
return EXIT_FAILURE; | |
} | |
float volume = 1.0f; | |
if (argc == 3) | |
volume = std::strtof(argv[2], nullptr); | |
if (volume < 0.0f || volume > 1.0f) { | |
print_error("Volume out of range", "The value should be between 0.0 and 1.0"); | |
return EXIT_FAILURE; | |
} | |
/* Initialize required objects and set up the playback */ | |
HINSTANCE hinstance = GetModuleHandle(NULL); | |
HRESULT result = S_OK; | |
HWND hwnd = NULL; | |
if (!initialize_objects(argv[1])) | |
return EXIT_FAILURE; | |
aspect_ratio_control->SetAspectRatioMode(VMR_ARMODE_LETTER_BOX); | |
video_window->HideCursor(OATRUE); | |
remove_border(video_window); | |
basic_audio->put_Volume(std::round(10000 * (volume - 1.0f))); | |
WNDCLASS drain_class = {0}; | |
drain_class.lpfnWndProc = &window_proc; | |
drain_class.hInstance = hinstance; | |
drain_class.lpszClassName = "Message Drain"; | |
drain_class.hbrBackground = GetStockBrush(BLACK_BRUSH); | |
RegisterClass(&drain_class); | |
hwnd = CreateWindow(drain_class.lpszClassName, "Drain Window", 0, 0, 0, 0, 0, NULL, NULL, hinstance, NULL); | |
remove_border(hwnd); | |
result = video_window->put_Owner((OAHWND)hwnd); | |
if (result != S_OK) { | |
print_error("Failed to embed the video window", _com_error(result).ErrorMessage()); | |
PostMessage(hwnd, WM_CLOSE, 0, 0); | |
} | |
result = video_window->put_MessageDrain((OAHWND)hwnd); | |
if (result != S_OK) { | |
print_error("Could not set up message forwarding from video window to its parent", _com_error(result).ErrorMessage()); | |
PostMessage(hwnd, WM_CLOSE, 0, 0); | |
} | |
media_event_ex->SetNotifyWindow((OAHWND)hwnd, WM_MEDIAEVENT, (LONG_PTR)media_event); | |
/* Find game window and fit the player to its rect */ | |
HWND game_window = FindWindow("KI_WINDOW", "Rex3D"); | |
RECT game_rect = {0}; | |
if (game_window != NULL && GetWindowRect(game_window, &game_rect)) { | |
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)game_window); | |
long width = game_rect.right - game_rect.left; | |
long height = game_rect.bottom - game_rect.top; | |
MoveWindow(hwnd, game_rect.left, game_rect.top, width, height, true); | |
video_window->SetWindowPosition(0, 0, width, height); | |
} else { | |
int width = GetSystemMetrics(SM_CXSCREEN); | |
int height = GetSystemMetrics(SM_CYSCREEN); | |
MoveWindow(hwnd, 0, 0, width, height, true); | |
video_window->SetWindowPosition(0, 0, width, height); | |
} | |
/* Start the video */ | |
result = media_control->Run(); | |
if (result != S_OK && result != S_FALSE) { | |
print_error("Could not run the video", _com_error(result).ErrorMessage()); | |
PostMessage(hwnd, WM_CLOSE, 0, 0); | |
} | |
ShowWindow(hwnd, SW_SHOW); | |
/* Run the main loop */ | |
MSG msg = {0}; | |
while (GetMessage(&msg, NULL, 0, 0)) { | |
TranslateMessage(&msg); | |
DispatchMessage(&msg); | |
} | |
return EXIT_SUCCESS; | |
} | |
LRESULT CALLBACK window_proc(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam) | |
{ | |
switch (umsg) { | |
case WM_CLOSE: { | |
media_control->Stop(); | |
video_window->put_MessageDrain((OAHWND)NULL); | |
video_window->put_Owner((OAHWND)NULL); | |
break; | |
} | |
case WM_DESTROY: { | |
destroy_objects(); | |
KillTimer(hwnd, TIMER_ID); | |
PostQuitMessage(0); | |
return 0; | |
} | |
case WM_PAINT: { | |
PAINTSTRUCT ps; | |
HDC hdc = BeginPaint(hwnd, &ps); | |
FillRect(hdc, &ps.rcPaint, GetStockBrush(BLACK_BRUSH)); | |
EndPaint(hwnd, &ps); | |
return 0; | |
} | |
case WM_LBUTTONDOWN: { | |
PostMessage(hwnd, WM_CLOSE, 0, 0); | |
return 0; | |
} | |
case WM_KEYDOWN: { | |
if (wparam == VK_ESCAPE) { | |
PostMessage(hwnd, WM_CLOSE, 0, 0); | |
return 0; | |
} | |
break; | |
} | |
case WM_TIMER: { | |
if (wparam == TIMER_ID) { | |
SetTimer(hwnd, wparam, 1000, NULL); | |
HWND fg_hwnd = GetForegroundWindow(); | |
char fg_title[6] = {0}; | |
GetWindowText(fg_hwnd, fg_title, 6); | |
if (std::string(fg_title) != "Rex3D") | |
return 0; | |
KillTimer(hwnd, wparam); | |
// source: https://stackoverflow.com/a/34414846 | |
DWORD tid = GetCurrentThreadId(); | |
DWORD fg_tid = GetWindowThreadProcessId(fg_hwnd, NULL); | |
AttachThreadInput(fg_tid, tid, true); | |
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); | |
SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE); | |
SetForegroundWindow(hwnd); | |
SetFocus(hwnd); | |
SetActiveWindow(hwnd); | |
AttachThreadInput(fg_tid, tid, false); | |
return 0; | |
} | |
break; | |
} | |
case WM_ACTIVATE: { | |
if (wparam == WA_INACTIVE) { | |
SetTimer(hwnd, TIMER_ID, 100, NULL); | |
return 0; | |
} | |
break; | |
} | |
case WM_MEDIAEVENT: { | |
if ((void *)lparam == nullptr) | |
break; | |
IMediaEvent *media_event = (IMediaEvent *)lparam; | |
LONG_PTR param1 = 0, param2 = 0; | |
long event_code = 0; | |
while (media_event->GetEvent(&event_code, ¶m1, ¶m2, 0) == S_OK) | |
if (event_code == EC_COMPLETE || event_code == EC_ERRORABORT || event_code == EC_USERABORT) | |
PostMessage(hwnd, WM_CLOSE, 0, 0); | |
return 0; | |
} | |
} | |
return DefWindowProc(hwnd, umsg, wparam, lparam); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#undef UNICODE | |
#undef _UNICODE | |
#include <cstdio> | |
#include <string> | |
#define WIN32_LEAN_AND_MEAN | |
#undef _WIN32_WINNT | |
#define _WIN32_WINNT 0x0600 | |
#include <comdef.h> | |
#include <tlhelp32.h> | |
#include <windows.h> | |
// based on: https://stackoverflow.com/a/11912507 | |
DWORD get_parent_pid(DWORD pid) | |
{ | |
HANDLE snapshot = NULL; | |
PROCESSENTRY32 process_entry = {0}; | |
process_entry.dwSize = sizeof(PROCESSENTRY32); | |
BOOL result = true; | |
snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, pid); | |
if (snapshot == INVALID_HANDLE_VALUE) | |
return 0; | |
for (result = Process32First(snapshot, &process_entry); result; result = Process32Next(snapshot, &process_entry)) | |
if (process_entry.th32ProcessID == pid) | |
break; | |
CloseHandle(snapshot); | |
return result ? process_entry.th32ParentProcessID : 0; | |
} | |
std::string get_parent_pname(HWND hwnd) | |
{ | |
if (hwnd == NULL) | |
return ""; | |
DWORD console_pid = 0, console_parent_pid = 0; | |
GetWindowThreadProcessId(hwnd, &console_pid); | |
if ((console_parent_pid = get_parent_pid(console_pid)) == 0) | |
return ""; | |
HANDLE console_handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, console_parent_pid); | |
if (console_handle == NULL) | |
return ""; | |
char buffer[MAX_PATH + 1] = {0}; | |
DWORD buffer_size = MAX_PATH + 1; | |
BOOL result = QueryFullProcessImageName(console_handle, 0, buffer, &buffer_size); | |
CloseHandle(console_handle); | |
return result ? std::string(buffer) : ""; | |
} | |
int main() | |
{ | |
HWND console_hwnd = GetConsoleWindow(); | |
std::string parent_pname = get_parent_pname(console_hwnd); | |
if (parent_pname == "ki.exe" || parent_pname.find("\\ki.exe") != std::string::npos || parent_pname.find("/ki.exe") != std::string::npos) | |
ShowWindow(console_hwnd, SW_HIDE); | |
DEVMODEA display_mode = {0}; | |
display_mode.dmSize = sizeof(display_mode); | |
DWORD required_fields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY; | |
for (DWORD mode_index = 0; EnumDisplaySettings(NULL, mode_index, &display_mode) != 0; mode_index++) | |
if ((display_mode.dmFields & required_fields) == required_fields) | |
printf("%lux%lux%lu@%lu\n", display_mode.dmPelsWidth, display_mode.dmPelsHeight, display_mode.dmBitsPerPel, | |
display_mode.dmDisplayFrequency); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment