Skip to content

Instantly share code, notes, and snippets.

@Dove6
Created February 20, 2022 22:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Dove6/6d10d49d97bf523592d4b46a274e6be4 to your computer and use it in GitHub Desktop.
Save Dove6/6d10d49d97bf523592d4b46a274e6be4 to your computer and use it in GitHub Desktop.
RiK3Wide v0.1.0 - kod źródłowy załączonych programów
#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, &param1, &param2, 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);
}
#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