From 05b5298718ace22d203ca1d66a071d9e1ee81250 Mon Sep 17 00:00:00 2001 From: nyfrk Date: Sat, 4 Jul 2020 06:22:39 +0200 Subject: [PATCH] Initial Commit --- .gitignore | 25 ++ LICENSE.md | 21 ++ README.md | 75 ++++ README_DE.md | 75 ++++ S4_ASI_Loader.sln | 25 ++ S4_ASI_Loader/S4_ASI_Loader.rc | Bin 0 -> 4748 bytes S4_ASI_Loader/S4_ASI_Loader.vcxproj | 102 ++++++ S4_ASI_Loader/S4_ASI_Loader.vcxproj.filters | 32 ++ S4_ASI_Loader/S4_ASI_Loader.vcxproj.user | 4 + S4_ASI_Loader/binkw32.def | 85 +++++ S4_ASI_Loader/dllmain.cpp | 377 ++++++++++++++++++++ S4_ASI_Loader/resource.h | 14 + installation.png | Bin 0 -> 13657 bytes 13 files changed, 835 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 README_DE.md create mode 100644 S4_ASI_Loader.sln create mode 100644 S4_ASI_Loader/S4_ASI_Loader.rc create mode 100644 S4_ASI_Loader/S4_ASI_Loader.vcxproj create mode 100644 S4_ASI_Loader/S4_ASI_Loader.vcxproj.filters create mode 100644 S4_ASI_Loader/S4_ASI_Loader.vcxproj.user create mode 100644 S4_ASI_Loader/binkw32.def create mode 100644 S4_ASI_Loader/dllmain.cpp create mode 100644 S4_ASI_Loader/resource.h create mode 100644 installation.png diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f6e3c2d --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +# gitignore for C++ +# Compiled Object files +*.slo +*.lo +*.o + +# Compiled Dynamic libraries +*.so +*.dylib + +# Compiled Static libraries +*.lai +*.la +*.a + +# Visual Studio Files +Debug +Release +*.suo +*.csproj.user +*.vbproj.user +ipch +*sdf +.vs +*.aps diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..f5e778e --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 nyfrk + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..f9de468 --- /dev/null +++ b/README.md @@ -0,0 +1,75 @@ +# The Settlers 4: ASI Loader + +This is a tool which adds ASI plugin loading functionality to The Settlers 4 or any other game that uses the same binkw32.dll. You need it to install mods to your game as the game does not come with modding support by default. + +There is a [German translation for this README](README_DE.md). Please note that it may be outdated. + + + +## Features + +* Works with Gold Edition as well as with the History Edition of The Settlers 4. +* Compatible with Windows XP or newer. + + + +## Installation + +1. Navigate to your installation directory of your game. +2. Find a file named `binkw32.dll` and rename it to `binkw32Hooked.dll`. (For the Gold Edition it is in a subdirectory named `Exe`) +3. Download a [release](https://github.com/nyfrk/Settlers4-ASI-Loader/releases) and unpack the `binkw32.dll` to the very same directory. +4. Create a `plugins` directory next to your `S4_Main.exe` +5. Move your ASI plugins into the `plugins` directory to enable them. The loader will only pick up plugins with the .asi ending. + + + +After these steps your installation directory should look like this: + +![installation](installation.png) + +Note that if windows does not show the file endings (like .dll) then you can just ignore them. For example in that case the file should be named just `binkw32Hooked` + + + +## Issues and Questions + +The project uses the Github Issue tracker. Please open a ticket [here](https://github.com/nyfrk/Settlers4-ASI-Loader/issues). + + + +## Plugins + +Here is a list of plugins that you can install to The Settlers 4. You can add your plugin to this list. However, the only requirement is, that it is compatible with the latest Gold Edition AND the History Edition of the game. + +* [Unlimited Selections Mod](https://github.com/nyfrk/Settlers4-UnlimitedSelectionMod) by [nyfrk](https://github.com/nyfrk): Remove the selection limit of your units and add additional selection filtering means. + + + +## Contribute + +The official repository of this project is available at https://github.com/nyfrk/Settlers4-ASI-Loader. You can contribute in the following ways: + +* Answer questions +* Submit bugs or help to verify them +* Review code and test the proposed fixes +* Submit pull requests +* Create or submit plugins + +#### Compile it yourself + +Download Visual Studio 2017 or 2019 with the C++ toolchain. The project is configured to build it with the Windows XP compatible **v141_xp** toolchain. However, you should be able to change the toolchain to whatever you like. No additional libraries are required so it should compile out of the box. + +#### Developers + +The loader is a proxy dll of the binkw32.dll. It is well suited as a proxy target as the Gold Edition and the History Edition use the very same binkw32.dll and because it only epxorts just a few stdcall functions. Note that ASI Plugins are just regular DLLs with the .asi file ending. These DLLs however usually apply their mods within their DllMain function. When creating a plugin do not assume any loading state when the loader loads your plugin. If you depend on a module (DLL) use LoadLibrary to load it yourself. + +#### Future work + +* Add improved crash dumps like [Ultimate ASI Loader](https://github.com/ThirteenAG/Ultimate-ASI-Loader) does. (The regular fatal error boxes are useless) +* Order files by name before loading (thus loading plugins in a predictable order) + + + +## License + +The project is licensed under the [MIT](LICENSE.md) License. diff --git a/README_DE.md b/README_DE.md new file mode 100644 index 0000000..63ef22c --- /dev/null +++ b/README_DE.md @@ -0,0 +1,75 @@ +# Die Siedler 4: ASI-Loader + +Dieses Tool ermöglicht es ASI-Plugins in Die Siedler 4 oder jedem anderen Spiel, das die gleiche binkw32.dll verwendet, zu laden. + +Für dieses README gibt es eine [englische Version](README.md). Bitte beachte, dass die deutsche Ãœbersetzung ggf. veraltet sein kann. + + + +## Features + +* Funktioniert sowohl mit der Gold Edition als auch mit der History Edition von Die Siedler 4. +* Kompatibel mit Windows XP oder neuer. + + + +## Installation + +1. Navigiere zum Installationsverzeichnis des Spiels. +2. Suche eine Datei namens `binkw32.dll` und benennen sie in `binkw32Hooked.dll` um. (Bei der Gold Edition befindet sie sich in einem Unterverzeichnis namens `Exe`) +3. Lade ein [Release](https://github.com/nyfrk/Settlers4-ASI-Loader/releases) herunter und entpacke die `binkw32.dll` in dasselbe Verzeichnis. +4. Erstellen ein Verzeichnis namens `plugins` neben der `S4_Main.exe`. +5. Verschiebe Deine ASI-Plugins in das Verzeichnis `plugins`, um sie zu aktivieren. Der Loader wird nur Plugins mit der Endung .asi beim Starten des Spiels laden. + + + +Nach diesen Schritten sollte Dein Installationsverzeichnis wie folgt aussehen: + +![installation](installation.png) + +Beachte, dass wenn Windows die Dateiendungen (wie .dll) nicht anzeigt, Du diese einfach ignorieren kannst. In diesem Fall sollte die Datei zum Beispiel einfach `binkw32Hooked` genannt werden. + + + +## Probleme und Fragen + +Das Projekt verwendet den Github Issue Tracker. Bitte öffne [hier](https://github.com/nyfrk/Settlers4-ASI-Loader/issues) ein Ticket für dein Anliegen. + + + +## Plugins + +Hier ist eine Liste von bekannten Plugins, die Du für Die Siedler 4 installieren kannst. Du kannst ein Plugin zu dieser Liste hinzufügen. Die einzige Voraussetzung ist jedoch, dass es mit der neuesten Gold Edition UND der History Edition des Spiels kompatibel ist. + +* [Unbegrenzte Auswahllimit Mod](https://github.com/nyfrk/Settlers4-UnlimitedSelectionMod) von [nyfrk](https://github.com/nyfrk): Entferne das Auswahllimit Deiner Einheiten und füge zusätzliche Auswahlfilteroptionen hinzu. + + + +## Beitragen + +Das offizielle Repository dieses Projekts ist unter https://github.com/nyfrk/Settlers4-ASI-Loader verfügbar. Du kannst auf die folgenden Arten einen Beitrag leisten: + +* Beantworte Fragen +* Fehler melden oder bei der Verifizierung dieser helfen +* Code sichten und die vorgeschlagenen Korrekturen testen +* Pull Requests einreichen +* Plugins erstellen oder einreichen (um sie der Liste hinzuzufügen) + +##### Kompilieren + +Lade Visual Studio 2017 oder 2019 mit der C++-Toolchain herunter. Das Projekt ist so konfiguriert, dass es mit der Windows XP-kompatiblen **v141_xp**-Toolchain gebaut wird. Du solltest jedoch die Toolchain nach Belieben ändern können. Es sind keine zusätzlichen Bibliotheken erforderlich, sodass das Projekt ohne weiteres gebaut werden kann. + +##### Entwickler + +Der Loader ist eine Proxy-Dll der binkw32.dll. Sie eignet sich gut als Proxy-Ziel, da die Gold Edition und die History Edition die gleiche binkw32.dll verwenden und weil sie nur einige wenige stdcall-Funktionen epxortiert. Beachte, dass ASI-Plugins im Grunde nur reguläre DLLs mit der Dateiendung .asi sind. Diese speziellen DLLs wenden jedoch normalerweise ihre Mods innerhalb ihrer DllMain-Funktion an. Nimm beim Erstellen eines Plugins keinen bestimmten Ladezustand an. Wenn Du auf ein Modul (DLL) angewiesen bist, verwenden LoadLibrary, um es selbst zu laden. + +##### Zukünftige Arbeit + +* Verbesserte Crash-Dumps, wie es [Ultimate ASI Loader](https://github.com/ThirteenAG/Ultimate-ASI-Loader) tut. (Die üblichen Fatal Error Meldungen sind nutzlos) +* Sortieren der Plugins nach Dateinamen vor dem Laden (Damit die Plugins in vorhersehbarer Reihenfolge geladen werden) + + + +## Lizenz + +Das Projekt ist unter der [MIT](https://github.com/nyfrk/Settlers4-UnlimitedSelectionMod/blob/master/LICENSE.md)-Lizenz lizenziert. diff --git a/S4_ASI_Loader.sln b/S4_ASI_Loader.sln new file mode 100644 index 0000000..20ebd15 --- /dev/null +++ b/S4_ASI_Loader.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29503.13 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "S4_ASI_Loader", "S4_ASI_Loader\S4_ASI_Loader.vcxproj", "{34E0C349-50AF-490C-BBE8-5DBD4286DD3E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {34E0C349-50AF-490C-BBE8-5DBD4286DD3E}.Debug|x86.ActiveCfg = Debug|Win32 + {34E0C349-50AF-490C-BBE8-5DBD4286DD3E}.Debug|x86.Build.0 = Debug|Win32 + {34E0C349-50AF-490C-BBE8-5DBD4286DD3E}.Release|x86.ActiveCfg = Release|Win32 + {34E0C349-50AF-490C-BBE8-5DBD4286DD3E}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {EE089082-1B2A-4348-83B6-70C7AEB605ED} + EndGlobalSection +EndGlobal diff --git a/S4_ASI_Loader/S4_ASI_Loader.rc b/S4_ASI_Loader/S4_ASI_Loader.rc new file mode 100644 index 0000000000000000000000000000000000000000..602ee914bee788655fe677eab475bb8caca871d7 GIT binary patch literal 4748 zcmdUz-%k@k5Xa})#Q$L}FB%QB;EO&fP%5#~hL%PX62gyC2$hodh?@AftDo;~m%Hm- zQOZlr=DK%tJF_$2`LT2T{cFwE%-JWqv{M_~$R=FpmO$%4o7k-#+mNR%d&zJ%u)bY$ zjiD#ZXVAvX;=ASUlzYdMq+Qw#YgX;4Jzdb}tqi z5&0;0x#p;y!@qs9Ch^&Ifwj+PC_{2mSiC5SfJr8wE=VD@sKful@7jdA2lart;bSyXj{NgJxvCYfklbO_CVK^r z{Cgo0d@c*-`&=2(L;sKLwf)~^e|cWVD2N!;z^Z(u^A>Mnd&AcTak%LyueFC(oz~kr z$OXj2rAo5M9%VJYV#Nwmu|q1=Au$`OeX8X=jW!n4=%M?p_zHYRO;lA0Lsg-y!W5$| z`e?c8NLCwZsOLEAwAYzF!Qv7Ai1cVlkGwo$O`YuS_)~X}XIZ{Oo{2mACep?2Sg}h! z*Jsu^tC8>3yDO}1Bfmui9#D6>|HKic@A#V0Ks(iv4!Q4;{@ph4VAI>9s7$Lys8E~i z)bMXpJyS_RLhX*fPuDU5r@URW>#Ldds>a$i&(T7^Ap12sYP_EEq*`?8VA`M-)~y%b zhdP;G6?ZPreO1*KxC)sH8YK8zz1RQ`U1C`uKV75iXeJxWrNyksOAXe%@fMx%o6qZ% zr>r)`w{h;_M|CyApn~4&es25;_k*}Q=BW=|XGR6Rf1vr;uIB7mE;HJ#b2Zzsh8&2p zyVHKF!>WWKq?9QRuc;m=9~_#F&`D>~n2y&G$LisNmTAv6@|X`i?xC+v;B$83DOc3U z4XW-3Xd`S7 z8v9o7u5urjBd!S3SHsw2Gc5QqkHbSGH<3C3jiHZ}8!%FI5Aa=b7bS|J{2TR9TfVPZ z$0A)0&0;LQga0cvWEGlx{}6pzGoFsI7Gok}nYTE4`yo5E*-5^?<*ODmv7>L=Z1(E}dE;wL%|}OdTFHa1 zsix_jD*gQK;qe`O_7q>Pds&{n!g;F`aNf6Bv2$83i?Z6tGCjxnv0v%xWbgk + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + + + + 16.0 + {34E0C349-50AF-490C-BBE8-5DBD4286DD3E} + Win32Proj + S4ASILoader + 7.0 + + + + DynamicLibrary + true + v141_xp + Unicode + + + DynamicLibrary + false + v141_xp + true + Unicode + + + + + + + + + + + + + + + true + binkw32 + + + false + binkw32 + + + + Level3 + Disabled + true + WIN32;_DEBUG;S4ASILOADER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Windows + true + false + binkw32.def + Shlwapi.lib;%(AdditionalDependencies) + + + + + Level3 + MaxSpeed + true + true + true + WIN32;NDEBUG;S4ASILOADER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + MultiThreaded + + + Windows + true + true + true + false + binkw32.def + Shlwapi.lib;%(AdditionalDependencies) + + + + + + \ No newline at end of file diff --git a/S4_ASI_Loader/S4_ASI_Loader.vcxproj.filters b/S4_ASI_Loader/S4_ASI_Loader.vcxproj.filters new file mode 100644 index 0000000..43cdc15 --- /dev/null +++ b/S4_ASI_Loader/S4_ASI_Loader.vcxproj.filters @@ -0,0 +1,32 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Quelldateien + + + + + Headerdateien + + + + + Ressourcendateien + + + \ No newline at end of file diff --git a/S4_ASI_Loader/S4_ASI_Loader.vcxproj.user b/S4_ASI_Loader/S4_ASI_Loader.vcxproj.user new file mode 100644 index 0000000..88a5509 --- /dev/null +++ b/S4_ASI_Loader/S4_ASI_Loader.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/S4_ASI_Loader/binkw32.def b/S4_ASI_Loader/binkw32.def new file mode 100644 index 0000000..b32be5b --- /dev/null +++ b/S4_ASI_Loader/binkw32.def @@ -0,0 +1,85 @@ +LIBRARY binkw32 +EXPORTS + _BinkBufferBlit@12 @1 + _BinkBufferCheckWinPos@12 @2 + _BinkBufferClear@8 @3 + _BinkBufferClose@4 @4 + _BinkBufferGetDescription@4 @5 + _BinkBufferGetError@0 @6 + _BinkBufferLock@4 @7 + _BinkBufferOpen@16 @8 + _BinkBufferSetDirectDraw@8 @9 + _BinkBufferSetHWND@8 @10 + _BinkBufferSetOffset@12 @11 + _BinkBufferSetResolution@12 @12 + _BinkBufferSetScale@12 @13 + _BinkBufferUnlock@4 @14 + _BinkCheckCursor@20 @15 + _BinkClose@4 @16 + _BinkCloseTrack@4 @17 + _BinkCopyToBuffer@28 @18 + _BinkDDSurfaceType@4 @19 + _BinkDX8SurfaceType@4 @20 + _BinkDoFrame@4 @21 + _BinkGetError@0 @22 + _BinkGetKeyFrame@12 @23 + _BinkGetRealtime@12 @24 + _BinkGetRects@8 @25 + _BinkGetSummary@8 @26 + _BinkGetTrackData@8 @27 + _BinkGetTrackID@8 @28 + _BinkGetTrackMaxSize@8 @29 + _BinkGetTrackType@8 @30 + _BinkGoto@12 @31 + _BinkIsSoftwareCursor@8 @32 + _BinkLogoAddress@0 @33 + _BinkNextFrame@4 @34 + _BinkOpen@8 @35 + _BinkOpenDirectSound@4 @36 + _BinkOpenMiles@4 @37 + _BinkOpenTrack@8 @38 + _BinkOpenWaveOut@4 @39 + _BinkPause@8 @40 + _BinkRestoreCursor@4 @41 + _BinkService@4 @42 + _BinkSetError@4 @43 + _BinkSetFrameRate@8 @44 + _BinkSetIO@4 @45 + _BinkSetIOSize@4 @46 + _BinkSetMixBins@8 @47 + _BinkSetPan@8 @48 + _BinkSetSimulate@4 @49 + _BinkSetSoundOnOff@8 @50 + _BinkSetSoundSystem@8 @51 + _BinkSetSoundTrack@4 @52 + _BinkSetVideoOnOff@8 @53 + _BinkSetVolume@8 @54 + _BinkWait@4 @55 + _RADSetMemory@8 @56 + _RADTimerRead@0 @57 + _YUV_blit_16a1bpp@52 @58 + _YUV_blit_16a1bpp_mask@52 @59 + _YUV_blit_16a4bpp@52 @60 + _YUV_blit_16a4bpp_mask@52 @61 + _YUV_blit_16bpp@48 @62 + _YUV_blit_16bpp_mask@48 @63 + _YUV_blit_24bpp@48 @64 + _YUV_blit_24bpp_mask@48 @65 + _YUV_blit_24rbpp@48 @66 + _YUV_blit_24rbpp_mask@48 @67 + _YUV_blit_32abpp@52 @68 + _YUV_blit_32abpp_mask@52 @69 + _YUV_blit_32bpp@48 @70 + _YUV_blit_32bpp_mask@48 @71 + _YUV_blit_32rabpp@52 @72 + _YUV_blit_32rabpp_mask@52 @73 + _YUV_blit_32rbpp@48 @74 + _YUV_blit_32rbpp_mask@48 @75 + _YUV_blit_UYVY@48 @76 + _YUV_blit_UYVY_mask@48 @77 + _YUV_blit_YUY2@48 @78 + _YUV_blit_YUY2_mask@48 @79 + _YUV_blit_YV12@52 @80 + _YUV_init@4 @81 + _radfree@4 @82 + _radmalloc@4 @83 diff --git a/S4_ASI_Loader/dllmain.cpp b/S4_ASI_Loader/dllmain.cpp new file mode 100644 index 0000000..46b8f0c --- /dev/null +++ b/S4_ASI_Loader/dllmain.cpp @@ -0,0 +1,377 @@ +/////////////////////////////////////////////////////////////////////////////// +// MIT License +// +// Copyright (c) 2020 nyfrk +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +/////////////////////////////////////////////////////////////////////////////// + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include + +#define PLUGINFILTER L"*.asi" +#define PLUGINDIR L"plugins\\" + +#define ERROR_BOX(err) {\ + const TCHAR fmt[] = err"\n\nError Code %d.";\ + TCHAR buf[sizeof(fmt) + 32];\ + swprintf_s(buf, fmt, (DWORD)GetLastError());\ + MessageBox(NULL, buf, L"ASI LOADER ERROR", MB_ICONERROR);\ + ExitProcess(0);\ +} + +#define STDCALL_DECORATION __declspec(dllexport) __declspec(naked) void* __stdcall +#define STDCALL_PROXY_0(name) STDCALL_DECORATION name() +#define STDCALL_PROXY_4(name) STDCALL_DECORATION name(void *a) +#define STDCALL_PROXY_8(name) STDCALL_DECORATION name(void *a, void *b) +#define STDCALL_PROXY_12(name) STDCALL_DECORATION name(void *a, void *b, void *c) +#define STDCALL_PROXY_16(name) STDCALL_DECORATION name(void *a, void *b, void *c, void *d) +#define STDCALL_PROXY_20(name) STDCALL_DECORATION name(void *a, void *b, void *c, void *d, void *e) +#define STDCALL_PROXY_24(name) STDCALL_DECORATION name(void *a, void *b, void *c, void *d, void *e, void* f) +#define STDCALL_PROXY_28(name) STDCALL_DECORATION name(void *a, void *b, void *c, void *d, void *e, void* f, void *g) +#define STDCALL_PROXY_32(name) STDCALL_DECORATION name(void *a, void *b, void *c, void *d, void *e, void* f, void *g, void *h) +#define STDCALL_PROXY_36(name) STDCALL_DECORATION name(void *a, void *b, void *c, void *d, void *e, void* f, void *g, void *h, void *i) +#define STDCALL_PROXY_48(name) STDCALL_DECORATION name(void *a, void *b, void *c, void *d, void *e, void* f, void *g, void *h, void *i, void *j, void *k, void *l) +#define STDCALL_PROXY_52(name) STDCALL_DECORATION name(void *a, void *b, void *c, void *d, void *e, void* f, void *g, void *h, void *i, void *j, void *k, void *l, void *m) + +static std::vector plugins; // handles to all the plugins we loaded + +struct binkw32_t { + HMODULE hDll; + FARPROC Orig_BinkBufferBlit_12; + FARPROC Orig_BinkBufferCheckWinPos_12; + FARPROC Orig_BinkBufferClear_8; + FARPROC Orig_BinkBufferClose_4; + FARPROC Orig_BinkBufferGetDescription_4; + FARPROC Orig_BinkBufferGetError_0; + FARPROC Orig_BinkBufferLock_4; + FARPROC Orig_BinkBufferOpen_16; + FARPROC Orig_BinkBufferSetDirectDraw_8; + FARPROC Orig_BinkBufferSetHWND_8; + FARPROC Orig_BinkBufferSetOffset_12; + FARPROC Orig_BinkBufferSetResolution_12; + FARPROC Orig_BinkBufferSetScale_12; + FARPROC Orig_BinkBufferUnlock_4; + FARPROC Orig_BinkCheckCursor_20; + FARPROC Orig_BinkClose_4; + FARPROC Orig_BinkCloseTrack_4; + FARPROC Orig_BinkCopyToBuffer_28; + FARPROC Orig_BinkDDSurfaceType_4; + FARPROC Orig_BinkDX8SurfaceType_4; + FARPROC Orig_BinkDoFrame_4; + FARPROC Orig_BinkGetError_0; + FARPROC Orig_BinkGetKeyFrame_12; + FARPROC Orig_BinkGetRealtime_12; + FARPROC Orig_BinkGetRects_8; + FARPROC Orig_BinkGetSummary_8; + FARPROC Orig_BinkGetTrackData_8; + FARPROC Orig_BinkGetTrackID_8; + FARPROC Orig_BinkGetTrackMaxSize_8; + FARPROC Orig_BinkGetTrackType_8; + FARPROC Orig_BinkGoto_12; + FARPROC Orig_BinkIsSoftwareCursor_8; + FARPROC Orig_BinkLogoAddress_0; + FARPROC Orig_BinkNextFrame_4; + FARPROC Orig_BinkOpen_8; + FARPROC Orig_BinkOpenDirectSound_4; + FARPROC Orig_BinkOpenMiles_4; + FARPROC Orig_BinkOpenTrack_8; + FARPROC Orig_BinkOpenWaveOut_4; + FARPROC Orig_BinkPause_8; + FARPROC Orig_BinkRestoreCursor_4; + FARPROC Orig_BinkService_4; + FARPROC Orig_BinkSetError_4; + FARPROC Orig_BinkSetFrameRate_8; + FARPROC Orig_BinkSetIO_4; + FARPROC Orig_BinkSetIOSize_4; + FARPROC Orig_BinkSetMixBins_8; + FARPROC Orig_BinkSetPan_8; + FARPROC Orig_BinkSetSimulate_4; + FARPROC Orig_BinkSetSoundOnOff_8; + FARPROC Orig_BinkSetSoundSystem_8; + FARPROC Orig_BinkSetSoundTrack_4; + FARPROC Orig_BinkSetVideoOnOff_8; + FARPROC Orig_BinkSetVolume_8; + FARPROC Orig_BinkWait_4; + FARPROC Orig_RADSetMemory_8; + FARPROC Orig_RADTimerRead_0; + FARPROC Orig_YUV_blit_16a1bpp_52; + FARPROC Orig_YUV_blit_16a1bpp_mask_52; + FARPROC Orig_YUV_blit_16a4bpp_52; + FARPROC Orig_YUV_blit_16a4bpp_mask_52; + FARPROC Orig_YUV_blit_16bpp_48; + FARPROC Orig_YUV_blit_16bpp_mask_48; + FARPROC Orig_YUV_blit_24bpp_48; + FARPROC Orig_YUV_blit_24bpp_mask_48; + FARPROC Orig_YUV_blit_24rbpp_48; + FARPROC Orig_YUV_blit_24rbpp_mask_48; + FARPROC Orig_YUV_blit_32abpp_52; + FARPROC Orig_YUV_blit_32abpp_mask_52; + FARPROC Orig_YUV_blit_32bpp_48; + FARPROC Orig_YUV_blit_32bpp_mask_48; + FARPROC Orig_YUV_blit_32rabpp_52; + FARPROC Orig_YUV_blit_32rabpp_mask_52; + FARPROC Orig_YUV_blit_32rbpp_48; + FARPROC Orig_YUV_blit_32rbpp_mask_48; + FARPROC Orig_YUV_blit_UYVY_48; + FARPROC Orig_YUV_blit_UYVY_mask_48; + FARPROC Orig_YUV_blit_YUY2_48; + FARPROC Orig_YUV_blit_YUY2_mask_48; + FARPROC Orig_YUV_blit_YV12_52; + FARPROC Orig_YUV_init_4; + FARPROC Orig_radfree_4; + FARPROC Orig_radmalloc_4; +} binkw32; + +extern "C" { + STDCALL_PROXY_12(BinkBufferBlit) { _asm { jmp[binkw32.Orig_BinkBufferBlit_12] } } + STDCALL_PROXY_12(BinkBufferCheckWinPos) { _asm { jmp[binkw32.Orig_BinkBufferCheckWinPos_12] } } + STDCALL_PROXY_8(BinkBufferClear) { _asm { jmp[binkw32.Orig_BinkBufferClear_8] } } + STDCALL_PROXY_4(BinkBufferClose) { _asm { jmp[binkw32.Orig_BinkBufferClose_4] } } + STDCALL_PROXY_4(BinkBufferGetDescription) { _asm { jmp[binkw32.Orig_BinkBufferGetDescription_4] } } + STDCALL_PROXY_0(BinkBufferGetError) { _asm { jmp[binkw32.Orig_BinkBufferGetError_0] } } + STDCALL_PROXY_4(BinkBufferLock) { _asm { jmp[binkw32.Orig_BinkBufferLock_4] } } + STDCALL_PROXY_16(BinkBufferOpen) { _asm { jmp[binkw32.Orig_BinkBufferOpen_16] } } + STDCALL_PROXY_8(BinkBufferSetDirectDraw) { _asm { jmp[binkw32.Orig_BinkBufferSetDirectDraw_8] } } + STDCALL_PROXY_8(BinkBufferSetHWND) { _asm { jmp[binkw32.Orig_BinkBufferSetHWND_8] } } + STDCALL_PROXY_12(BinkBufferSetOffset) { _asm { jmp[binkw32.Orig_BinkBufferSetOffset_12] } } + STDCALL_PROXY_12(BinkBufferSetResolution) { _asm { jmp[binkw32.Orig_BinkBufferSetResolution_12] } } + STDCALL_PROXY_12(BinkBufferSetScale) { _asm { jmp[binkw32.Orig_BinkBufferSetScale_12] } } + STDCALL_PROXY_4(BinkBufferUnlock) { _asm { jmp[binkw32.Orig_BinkBufferUnlock_4] } } + STDCALL_PROXY_20(BinkCheckCursor) { _asm { jmp[binkw32.Orig_BinkCheckCursor_20] } } + STDCALL_PROXY_4(BinkClose) { _asm { jmp[binkw32.Orig_BinkClose_4] } } + STDCALL_PROXY_4(BinkCloseTrack) { _asm { jmp[binkw32.Orig_BinkCloseTrack_4] } } + STDCALL_PROXY_28(BinkCopyToBuffer) { _asm { jmp[binkw32.Orig_BinkCopyToBuffer_28] } } + STDCALL_PROXY_4(BinkDDSurfaceType) { _asm { jmp[binkw32.Orig_BinkDDSurfaceType_4] } } + STDCALL_PROXY_4(BinkDX8SurfaceType) { _asm { jmp[binkw32.Orig_BinkDX8SurfaceType_4] } } + STDCALL_PROXY_4(BinkDoFrame) { _asm { jmp[binkw32.Orig_BinkDoFrame_4] } } + STDCALL_PROXY_0(BinkGetError) { _asm { jmp[binkw32.Orig_BinkGetError_0] } } + STDCALL_PROXY_12(BinkGetKeyFrame) { _asm { jmp[binkw32.Orig_BinkGetKeyFrame_12] } } + STDCALL_PROXY_12(BinkGetRealtime) { _asm { jmp[binkw32.Orig_BinkGetRealtime_12] } } + STDCALL_PROXY_8(BinkGetRects) { _asm { jmp[binkw32.Orig_BinkGetRects_8] } } + STDCALL_PROXY_8(BinkGetSummary) { _asm { jmp[binkw32.Orig_BinkGetSummary_8] } } + STDCALL_PROXY_8(BinkGetTrackData) { _asm { jmp[binkw32.Orig_BinkGetTrackData_8] } } + STDCALL_PROXY_8(BinkGetTrackID) { _asm { jmp[binkw32.Orig_BinkGetTrackID_8] } } + STDCALL_PROXY_8(BinkGetTrackMaxSize) { _asm { jmp[binkw32.Orig_BinkGetTrackMaxSize_8] } } + STDCALL_PROXY_8(BinkGetTrackType) { _asm { jmp[binkw32.Orig_BinkGetTrackType_8] } } + STDCALL_PROXY_12(BinkGoto) { _asm { jmp[binkw32.Orig_BinkGoto_12] } } + STDCALL_PROXY_8(BinkIsSoftwareCursor) { _asm { jmp[binkw32.Orig_BinkIsSoftwareCursor_8] } } + STDCALL_PROXY_0(BinkLogoAddress) { _asm { jmp[binkw32.Orig_BinkLogoAddress_0] } } + STDCALL_PROXY_4(BinkNextFrame) { _asm { jmp[binkw32.Orig_BinkNextFrame_4] } } + STDCALL_PROXY_8(BinkOpen) { _asm { jmp[binkw32.Orig_BinkOpen_8] } } + STDCALL_PROXY_4(BinkOpenDirectSound) { _asm { jmp[binkw32.Orig_BinkOpenDirectSound_4] } } + STDCALL_PROXY_4(BinkOpenMiles) { _asm { jmp[binkw32.Orig_BinkOpenMiles_4] } } + STDCALL_PROXY_8(BinkOpenTrack) { _asm { jmp[binkw32.Orig_BinkOpenTrack_8] } } + STDCALL_PROXY_4(BinkOpenWaveOut) { _asm { jmp[binkw32.Orig_BinkOpenWaveOut_4] } } + STDCALL_PROXY_8(BinkPause) { _asm { jmp[binkw32.Orig_BinkPause_8] } } + STDCALL_PROXY_4(BinkRestoreCursor) { _asm { jmp[binkw32.Orig_BinkRestoreCursor_4] } } + STDCALL_PROXY_4(BinkService) { _asm { jmp[binkw32.Orig_BinkService_4] } } + STDCALL_PROXY_4(BinkSetError) { _asm { jmp[binkw32.Orig_BinkSetError_4] } } + STDCALL_PROXY_8(BinkSetFrameRate) { _asm { jmp[binkw32.Orig_BinkSetFrameRate_8] } } + STDCALL_PROXY_4(BinkSetIO) { _asm { jmp[binkw32.Orig_BinkSetIO_4] } } + STDCALL_PROXY_4(BinkSetIOSize) { _asm { jmp[binkw32.Orig_BinkSetIOSize_4] } } + STDCALL_PROXY_8(BinkSetMixBins) { _asm { jmp[binkw32.Orig_BinkSetMixBins_8] } } + STDCALL_PROXY_8(BinkSetPan) { _asm { jmp[binkw32.Orig_BinkSetPan_8] } } + STDCALL_PROXY_4(BinkSetSimulate) { _asm { jmp[binkw32.Orig_BinkSetSimulate_4] } } + STDCALL_PROXY_8(BinkSetSoundOnOff) { _asm { jmp[binkw32.Orig_BinkSetSoundOnOff_8] } } + STDCALL_PROXY_8(BinkSetSoundSystem) { _asm { jmp[binkw32.Orig_BinkSetSoundSystem_8] } } + STDCALL_PROXY_4(BinkSetSoundTrack) { _asm { jmp[binkw32.Orig_BinkSetSoundTrack_4] } } + STDCALL_PROXY_8(BinkSetVideoOnOff) { _asm { jmp[binkw32.Orig_BinkSetVideoOnOff_8] } } + STDCALL_PROXY_8(BinkSetVolume) { _asm { jmp[binkw32.Orig_BinkSetVolume_8] } } + STDCALL_PROXY_4(BinkWait) { _asm { jmp[binkw32.Orig_BinkWait_4] } } + STDCALL_PROXY_8(RADSetMemory) { _asm { jmp[binkw32.Orig_RADSetMemory_8] } } + STDCALL_PROXY_0(RADTimerRead) { _asm { jmp[binkw32.Orig_RADTimerRead_0] } } + STDCALL_PROXY_52(YUV_blit_16a1bpp) { _asm { jmp[binkw32.Orig_YUV_blit_16a1bpp_52] } } + STDCALL_PROXY_52(YUV_blit_16a1bpp_mask) { _asm { jmp[binkw32.Orig_YUV_blit_16a1bpp_mask_52] } } + STDCALL_PROXY_52(YUV_blit_16a4bpp) { _asm { jmp[binkw32.Orig_YUV_blit_16a4bpp_52] } } + STDCALL_PROXY_52(YUV_blit_16a4bpp_mask) { _asm { jmp[binkw32.Orig_YUV_blit_16a4bpp_mask_52] } } + STDCALL_PROXY_48(YUV_blit_16bpp) { _asm { jmp[binkw32.Orig_YUV_blit_16bpp_48] } } + STDCALL_PROXY_48(YUV_blit_16bpp_mask) { _asm { jmp[binkw32.Orig_YUV_blit_16bpp_mask_48] } } + STDCALL_PROXY_48(YUV_blit_24bpp) { _asm { jmp[binkw32.Orig_YUV_blit_24bpp_48] } } + STDCALL_PROXY_48(YUV_blit_24bpp_mask) { _asm { jmp[binkw32.Orig_YUV_blit_24bpp_mask_48] } } + STDCALL_PROXY_48(YUV_blit_24rbpp) { _asm { jmp[binkw32.Orig_YUV_blit_24rbpp_48] } } + STDCALL_PROXY_48(YUV_blit_24rbpp_mask) { _asm { jmp[binkw32.Orig_YUV_blit_24rbpp_mask_48] } } + STDCALL_PROXY_52(YUV_blit_32abpp) { _asm { jmp[binkw32.Orig_YUV_blit_32abpp_52] } } + STDCALL_PROXY_52(YUV_blit_32abpp_mask) { _asm { jmp[binkw32.Orig_YUV_blit_32abpp_mask_52] } } + STDCALL_PROXY_48(YUV_blit_32bpp) { _asm { jmp[binkw32.Orig_YUV_blit_32bpp_48] } } + STDCALL_PROXY_48(YUV_blit_32bpp_mask) { _asm { jmp[binkw32.Orig_YUV_blit_32bpp_mask_48] } } + STDCALL_PROXY_52(YUV_blit_32rabpp) { _asm { jmp[binkw32.Orig_YUV_blit_32rabpp_52] } } + STDCALL_PROXY_52(YUV_blit_32rabpp_mask) { _asm { jmp[binkw32.Orig_YUV_blit_32rabpp_mask_52] } } + STDCALL_PROXY_48(YUV_blit_32rbpp) { _asm { jmp[binkw32.Orig_YUV_blit_32rbpp_48] } } + STDCALL_PROXY_48(YUV_blit_32rbpp_mask) { _asm { jmp[binkw32.Orig_YUV_blit_32rbpp_mask_48] } } + STDCALL_PROXY_48(YUV_blit_UYVY) { _asm { jmp[binkw32.Orig_YUV_blit_UYVY_48] } } + STDCALL_PROXY_48(YUV_blit_UYVY_mask) { _asm { jmp[binkw32.Orig_YUV_blit_UYVY_mask_48] } } + STDCALL_PROXY_48(YUV_blit_YUY2) { _asm { jmp[binkw32.Orig_YUV_blit_YUY2_48] } } + STDCALL_PROXY_48(YUV_blit_YUY2_mask) { _asm { jmp[binkw32.Orig_YUV_blit_YUY2_mask_48] } } + STDCALL_PROXY_52(YUV_blit_YV12) { _asm { jmp[binkw32.Orig_YUV_blit_YV12_52] } } + STDCALL_PROXY_4(YUV_init) { _asm { jmp[binkw32.Orig_YUV_init_4] } } + STDCALL_PROXY_4(radfree) { _asm { jmp[binkw32.Orig_radfree_4] } } + STDCALL_PROXY_4(radmalloc) { _asm { jmp[binkw32.Orig_radmalloc_4] } } +} + +BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + binkw32.hDll = LoadLibraryA("binkw32Hooked.dll"); + if (binkw32.hDll == NULL) + ERROR_BOX(L"Cannot load original binkw32Hooked.dll library!\n\nTo use this ASI loader, you must rename the original binkw32.dll to binkw32hooked.dll. Repair the game and make sure to exactly follow the instructions of the README."); + binkw32.Orig_BinkBufferBlit_12 = GetProcAddress(binkw32.hDll, "_BinkBufferBlit@12"); + binkw32.Orig_BinkBufferCheckWinPos_12 = GetProcAddress(binkw32.hDll, "_BinkBufferCheckWinPos@12"); + binkw32.Orig_BinkBufferClear_8 = GetProcAddress(binkw32.hDll, "_BinkBufferClear@8"); + binkw32.Orig_BinkBufferClose_4 = GetProcAddress(binkw32.hDll, "_BinkBufferClose@4"); + binkw32.Orig_BinkBufferGetDescription_4 = GetProcAddress(binkw32.hDll, "_BinkBufferGetDescription@4"); + binkw32.Orig_BinkBufferGetError_0 = GetProcAddress(binkw32.hDll, "_BinkBufferGetError@0"); + binkw32.Orig_BinkBufferLock_4 = GetProcAddress(binkw32.hDll, "_BinkBufferLock@4"); + binkw32.Orig_BinkBufferOpen_16 = GetProcAddress(binkw32.hDll, "_BinkBufferOpen@16"); + binkw32.Orig_BinkBufferSetDirectDraw_8 = GetProcAddress(binkw32.hDll, "_BinkBufferSetDirectDraw@8"); + binkw32.Orig_BinkBufferSetHWND_8 = GetProcAddress(binkw32.hDll, "_BinkBufferSetHWND@8"); + binkw32.Orig_BinkBufferSetOffset_12 = GetProcAddress(binkw32.hDll, "_BinkBufferSetOffset@12"); + binkw32.Orig_BinkBufferSetResolution_12 = GetProcAddress(binkw32.hDll, "_BinkBufferSetResolution@12"); + binkw32.Orig_BinkBufferSetScale_12 = GetProcAddress(binkw32.hDll, "_BinkBufferSetScale@12"); + binkw32.Orig_BinkBufferUnlock_4 = GetProcAddress(binkw32.hDll, "_BinkBufferUnlock@4"); + binkw32.Orig_BinkCheckCursor_20 = GetProcAddress(binkw32.hDll, "_BinkCheckCursor@20"); + binkw32.Orig_BinkClose_4 = GetProcAddress(binkw32.hDll, "_BinkClose@4"); + binkw32.Orig_BinkCloseTrack_4 = GetProcAddress(binkw32.hDll, "_BinkCloseTrack@4"); + binkw32.Orig_BinkCopyToBuffer_28 = GetProcAddress(binkw32.hDll, "_BinkCopyToBuffer@28"); + binkw32.Orig_BinkDDSurfaceType_4 = GetProcAddress(binkw32.hDll, "_BinkDDSurfaceType@4"); + binkw32.Orig_BinkDX8SurfaceType_4 = GetProcAddress(binkw32.hDll, "_BinkDX8SurfaceType@4"); + binkw32.Orig_BinkDoFrame_4 = GetProcAddress(binkw32.hDll, "_BinkDoFrame@4"); + binkw32.Orig_BinkGetError_0 = GetProcAddress(binkw32.hDll, "_BinkGetError@0"); + binkw32.Orig_BinkGetKeyFrame_12 = GetProcAddress(binkw32.hDll, "_BinkGetKeyFrame@12"); + binkw32.Orig_BinkGetRealtime_12 = GetProcAddress(binkw32.hDll, "_BinkGetRealtime@12"); + binkw32.Orig_BinkGetRects_8 = GetProcAddress(binkw32.hDll, "_BinkGetRects@8"); + binkw32.Orig_BinkGetSummary_8 = GetProcAddress(binkw32.hDll, "_BinkGetSummary@8"); + binkw32.Orig_BinkGetTrackData_8 = GetProcAddress(binkw32.hDll, "_BinkGetTrackData@8"); + binkw32.Orig_BinkGetTrackID_8 = GetProcAddress(binkw32.hDll, "_BinkGetTrackID@8"); + binkw32.Orig_BinkGetTrackMaxSize_8 = GetProcAddress(binkw32.hDll, "_BinkGetTrackMaxSize@8"); + binkw32.Orig_BinkGetTrackType_8 = GetProcAddress(binkw32.hDll, "_BinkGetTrackType@8"); + binkw32.Orig_BinkGoto_12 = GetProcAddress(binkw32.hDll, "_BinkGoto@12"); + binkw32.Orig_BinkIsSoftwareCursor_8 = GetProcAddress(binkw32.hDll, "_BinkIsSoftwareCursor@8"); + binkw32.Orig_BinkLogoAddress_0 = GetProcAddress(binkw32.hDll, "_BinkLogoAddress@0"); + binkw32.Orig_BinkNextFrame_4 = GetProcAddress(binkw32.hDll, "_BinkNextFrame@4"); + binkw32.Orig_BinkOpen_8 = GetProcAddress(binkw32.hDll, "_BinkOpen@8"); + binkw32.Orig_BinkOpenDirectSound_4 = GetProcAddress(binkw32.hDll, "_BinkOpenDirectSound@4"); + binkw32.Orig_BinkOpenMiles_4 = GetProcAddress(binkw32.hDll, "_BinkOpenMiles@4"); + binkw32.Orig_BinkOpenTrack_8 = GetProcAddress(binkw32.hDll, "_BinkOpenTrack@8"); + binkw32.Orig_BinkOpenWaveOut_4 = GetProcAddress(binkw32.hDll, "_BinkOpenWaveOut@4"); + binkw32.Orig_BinkPause_8 = GetProcAddress(binkw32.hDll, "_BinkPause@8"); + binkw32.Orig_BinkRestoreCursor_4 = GetProcAddress(binkw32.hDll, "_BinkRestoreCursor@4"); + binkw32.Orig_BinkService_4 = GetProcAddress(binkw32.hDll, "_BinkService@4"); + binkw32.Orig_BinkSetError_4 = GetProcAddress(binkw32.hDll, "_BinkSetError@4"); + binkw32.Orig_BinkSetFrameRate_8 = GetProcAddress(binkw32.hDll, "_BinkSetFrameRate@8"); + binkw32.Orig_BinkSetIO_4 = GetProcAddress(binkw32.hDll, "_BinkSetIO@4"); + binkw32.Orig_BinkSetIOSize_4 = GetProcAddress(binkw32.hDll, "_BinkSetIOSize@4"); + binkw32.Orig_BinkSetMixBins_8 = GetProcAddress(binkw32.hDll, "_BinkSetMixBins@8"); + binkw32.Orig_BinkSetPan_8 = GetProcAddress(binkw32.hDll, "_BinkSetPan@8"); + binkw32.Orig_BinkSetSimulate_4 = GetProcAddress(binkw32.hDll, "_BinkSetSimulate@4"); + binkw32.Orig_BinkSetSoundOnOff_8 = GetProcAddress(binkw32.hDll, "_BinkSetSoundOnOff@8"); + binkw32.Orig_BinkSetSoundSystem_8 = GetProcAddress(binkw32.hDll, "_BinkSetSoundSystem@8"); + binkw32.Orig_BinkSetSoundTrack_4 = GetProcAddress(binkw32.hDll, "_BinkSetSoundTrack@4"); + binkw32.Orig_BinkSetVideoOnOff_8 = GetProcAddress(binkw32.hDll, "_BinkSetVideoOnOff@8"); + binkw32.Orig_BinkSetVolume_8 = GetProcAddress(binkw32.hDll, "_BinkSetVolume@8"); + binkw32.Orig_BinkWait_4 = GetProcAddress(binkw32.hDll, "_BinkWait@4"); + binkw32.Orig_RADSetMemory_8 = GetProcAddress(binkw32.hDll, "_RADSetMemory@8"); + binkw32.Orig_RADTimerRead_0 = GetProcAddress(binkw32.hDll, "_RADTimerRead@0"); + binkw32.Orig_YUV_blit_16a1bpp_52 = GetProcAddress(binkw32.hDll, "_YUV_blit_16a1bpp_52"); + binkw32.Orig_YUV_blit_16a1bpp_mask_52 = GetProcAddress(binkw32.hDll, "_YUV_blit_16a1bpp_mask_52"); + binkw32.Orig_YUV_blit_16a4bpp_52 = GetProcAddress(binkw32.hDll, "_YUV_blit_16a4bpp_52"); + binkw32.Orig_YUV_blit_16a4bpp_mask_52 = GetProcAddress(binkw32.hDll, "_YUV_blit_16a4bpp_mask_52"); + binkw32.Orig_YUV_blit_16bpp_48 = GetProcAddress(binkw32.hDll, "_YUV_blit_16bpp_48"); + binkw32.Orig_YUV_blit_16bpp_mask_48 = GetProcAddress(binkw32.hDll, "_YUV_blit_16bpp_mask_48"); + binkw32.Orig_YUV_blit_24bpp_48 = GetProcAddress(binkw32.hDll, "_YUV_blit_24bpp_48"); + binkw32.Orig_YUV_blit_24bpp_mask_48 = GetProcAddress(binkw32.hDll, "_YUV_blit_24bpp_mask_48"); + binkw32.Orig_YUV_blit_24rbpp_48 = GetProcAddress(binkw32.hDll, "_YUV_blit_24rbpp_48"); + binkw32.Orig_YUV_blit_24rbpp_mask_48 = GetProcAddress(binkw32.hDll, "_YUV_blit_24rbpp_mask_48"); + binkw32.Orig_YUV_blit_32abpp_52 = GetProcAddress(binkw32.hDll, "_YUV_blit_32abpp_52"); + binkw32.Orig_YUV_blit_32abpp_mask_52 = GetProcAddress(binkw32.hDll, "_YUV_blit_32abpp_mask_52"); + binkw32.Orig_YUV_blit_32bpp_48 = GetProcAddress(binkw32.hDll, "_YUV_blit_32bpp_48"); + binkw32.Orig_YUV_blit_32bpp_mask_48 = GetProcAddress(binkw32.hDll, "_YUV_blit_32bpp_mask_48"); + binkw32.Orig_YUV_blit_32rabpp_52 = GetProcAddress(binkw32.hDll, "_YUV_blit_32rabpp_52"); + binkw32.Orig_YUV_blit_32rabpp_mask_52 = GetProcAddress(binkw32.hDll, "_YUV_blit_32rabpp_mask_52"); + binkw32.Orig_YUV_blit_32rbpp_48 = GetProcAddress(binkw32.hDll, "_YUV_blit_32rbpp_48"); + binkw32.Orig_YUV_blit_32rbpp_mask_48 = GetProcAddress(binkw32.hDll, "_YUV_blit_32rbpp_mask_48"); + binkw32.Orig_YUV_blit_UYVY_48 = GetProcAddress(binkw32.hDll, "_YUV_blit_UYVY_48"); + binkw32.Orig_YUV_blit_UYVY_mask_48 = GetProcAddress(binkw32.hDll, "_YUV_blit_UYVY_mask_48"); + binkw32.Orig_YUV_blit_YUY2_48 = GetProcAddress(binkw32.hDll, "_YUV_blit_YUY2_48"); + binkw32.Orig_YUV_blit_YUY2_mask_48 = GetProcAddress(binkw32.hDll, "_YUV_blit_YUY2_mask_48"); + binkw32.Orig_YUV_blit_YV12_52 = GetProcAddress(binkw32.hDll, "_YUV_blit_YV12_52"); + binkw32.Orig_YUV_init_4 = GetProcAddress(binkw32.hDll, "_YUV_init_4"); + binkw32.Orig_radfree_4 = GetProcAddress(binkw32.hDll, "_radfree@4"); + binkw32.Orig_radmalloc_4 = GetProcAddress(binkw32.hDll, "_radmalloc@4"); + { + // Load the plugins + HMODULE main = GetModuleHandle(NULL); + if (main == NULL) + ERROR_BOX(L"Cannot get module handle of your exe."); + wchar_t filename[MAX_PATH + 1 + _countof(PLUGINDIR PLUGINFILTER)]; + auto len = GetModuleFileName(main, filename, MAX_PATH); + if (len <= 0) + ERROR_BOX(L"Cannot get file name of your exe."); + // get the path + filename[len] = L'\0'; + for (--len; len >= 0; len--) { + if (filename[len] == L'\\') { + filename[++len] = L'\0'; + break; + } + } + // change directory to PLUGINDIR and add PLUGINFILTER + memcpy(&(filename[len]), PLUGINDIR PLUGINFILTER, sizeof(PLUGINDIR PLUGINFILTER)); + len += _countof(PLUGINDIR)-1; // len of the fully qualified plugin dir + WIN32_FIND_DATA ffd; + HANDLE hFind; + hFind = FindFirstFile(filename, &ffd); + if (hFind == INVALID_HANDLE_VALUE) + ERROR_BOX(L"Cannot enumerate plugins in " PLUGINDIR); + do { + if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + continue; + // Due to some DOS compatibility FindFirstFile does match *.asi*. + // So we use this to match to *.asi only. + if (!PathMatchSpec(ffd.cFileName, PLUGINFILTER)) + continue; + wcscpy_s(&(filename[len]), _countof(filename) - len, ffd.cFileName); + HMODULE hMod = LoadLibrary(filename); + if (hMod) { + plugins.push_back(hMod); + } else { + const TCHAR fmt[] = L"Cannot load plugin\n%s" L"\n\nError Code %d."; + TCHAR buf[sizeof(fmt) + MAX_PATH + 32]; \ + swprintf_s(buf, fmt, filename, (DWORD)GetLastError()); \ + MessageBox(NULL, buf, L"ASI LOADER ERROR", MB_ICONEXCLAMATION | MB_OK); + } + } while (FindNextFile(hFind, &ffd) != 0); + + FindClose(hFind); + } + break; + case DLL_PROCESS_DETACH: + for (auto& mod : plugins) + FreeLibrary(mod); + if (binkw32.hDll) + FreeLibrary(binkw32.hDll); + break; + } + return TRUE; +} diff --git a/S4_ASI_Loader/resource.h b/S4_ASI_Loader/resource.h new file mode 100644 index 0000000..81f4cfd --- /dev/null +++ b/S4_ASI_Loader/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by S4_ASI_Loader.rc + +// Nächste Standardwerte für neue Objekte +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/installation.png b/installation.png new file mode 100644 index 0000000000000000000000000000000000000000..ac504f55a505f132c72eb67643a68c8701548610 GIT binary patch literal 13657 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