├── .gitignore ├── LICENSE.txt ├── README.md ├── directplay-lite.props ├── directplay-lite.sln ├── directplay-lite ├── directplay-lite.vcxproj └── directplay-lite.vcxproj.filters ├── dpnet ├── dpnet.vcxproj └── dpnet.vcxproj.filters ├── googletest ├── include │ └── gtest │ │ ├── gtest-death-test.h │ │ ├── gtest-message.h │ │ ├── gtest-param-test.h │ │ ├── gtest-param-test.h.pump │ │ ├── gtest-printers.h │ │ ├── gtest-spi.h │ │ ├── gtest-test-part.h │ │ ├── gtest-typed-test.h │ │ ├── gtest.h │ │ ├── gtest_pred_impl.h │ │ ├── gtest_prod.h │ │ └── internal │ │ ├── custom │ │ ├── README.md │ │ ├── gtest-port.h │ │ ├── gtest-printers.h │ │ └── gtest.h │ │ ├── gtest-death-test-internal.h │ │ ├── gtest-filepath.h │ │ ├── gtest-internal.h │ │ ├── gtest-linked_ptr.h │ │ ├── gtest-param-util-generated.h │ │ ├── gtest-param-util-generated.h.pump │ │ ├── gtest-param-util.h │ │ ├── gtest-port-arch.h │ │ ├── gtest-port.h │ │ ├── gtest-string.h │ │ ├── gtest-tuple.h │ │ ├── gtest-tuple.h.pump │ │ ├── gtest-type-util.h │ │ └── gtest-type-util.h.pump └── src │ ├── gtest-all.cc │ ├── gtest-death-test.cc │ ├── gtest-filepath.cc │ ├── gtest-internal-inl.h │ ├── gtest-port.cc │ ├── gtest-printers.cc │ ├── gtest-test-part.cc │ ├── gtest-typed-test.cc │ ├── gtest.cc │ └── gtest_main.cc ├── hookdll ├── ddraw │ ├── ddraw.asm │ ├── ddraw.def │ ├── ddraw.vcxproj │ └── ddraw.vcxproj.filters ├── dsound │ ├── dsound.asm │ ├── dsound.def │ ├── dsound.vcxproj │ └── dsound.vcxproj.filters └── hookdll.cpp ├── include ├── dpaddr.h └── dplay8.h ├── minhook ├── AUTHORS.txt ├── LICENSE.txt ├── include │ └── MinHook.h ├── minhook.vcxproj ├── minhook.vcxproj.filters └── src │ ├── buffer.c │ ├── buffer.h │ ├── hde │ ├── hde32.c │ ├── hde32.h │ ├── hde64.c │ ├── hde64.h │ ├── pstdint.h │ ├── table32.h │ └── table64.h │ ├── hook.c │ ├── trampoline.c │ └── trampoline.h ├── mkstubs.pl ├── src ├── AsyncHandleAllocator.cpp ├── AsyncHandleAllocator.hpp ├── COMAPIException.cpp ├── COMAPIException.hpp ├── DirectPlay8Address.cpp ├── DirectPlay8Address.hpp ├── DirectPlay8Peer.cpp ├── DirectPlay8Peer.hpp ├── EventObject.cpp ├── EventObject.hpp ├── Factory.hpp ├── HandleHandlingPool.cpp ├── HandleHandlingPool.hpp ├── HostEnumerator.cpp ├── HostEnumerator.hpp ├── Log.cpp ├── Log.hpp ├── Messages.hpp ├── SendQueue.cpp ├── SendQueue.hpp ├── dpnet.cpp ├── dpnet.def ├── network.cpp ├── network.hpp ├── packet.cpp └── packet.hpp └── tests ├── DirectPlay8Address.cpp ├── DirectPlay8Peer.cpp ├── HandleHandlingPool.cpp ├── PacketDeserialiser.cpp ├── PacketSerialiser.cpp ├── SendQueue.cpp ├── soak-peer-client.cpp ├── soak-peer-server.cpp ├── tests.vcxproj └── tests.vcxproj.filters /.gitignore: -------------------------------------------------------------------------------- 1 | *.obj 2 | *.dll 3 | *.exp 4 | *.lib 5 | *.exe 6 | *.pdb 7 | *.ilk 8 | *.vcxproj.user 9 | 10 | Debug/ 11 | Release/ 12 | 13 | /.vs/ 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DirectPlay Lite 2 | 3 | ## What is this? 4 | 5 | DirectPlay Lite is an open-source reimplementation of Microsoft's DirectPlay API, intended to help preseve old games as official support for DirectPlay wanes. 6 | 7 | Rather than being a full reimplementation of the DirectPlay specification, DirectPlay Lite aims to provide a compatible API to games, while removing some of the other complexity, such as support for multiple service providers - games requesting the TCP/IP or IPX service providers will actually use IP, masquerading as another protocol where necessary. 8 | 9 | **NOTE**: This is currently early in development and aimed at people or companies repackaging old games. Only a limited portion of the DirectPlay (8) APIs are implemented and installing it isn't user-friendly. 10 | 11 | ## Building 12 | 13 | Use the `directplay-lite.sln` solution in Visual Studio 2017 or later. 14 | 15 | ## Using 16 | 17 | DirectPlay Lite can be loaded into a game using the two following methods. 18 | 19 | ### Installation as a COM DLL 20 | 21 | This is the way DirectPlay and COM were designed to operate. The DirectPlay class registrations are added to the registry and the DLLs are copied somewhere for all applications to use. 22 | 23 | ### Registration from a hook DLL 24 | 25 | This method is less invasive, but depends on undefined behaviour and may not work everywhere. A "hook" DLL is placed alongside the game, which masks one of the libraries it usually loads. When the hook DLL is loaded, it hooks some of the COM APIs in order to inject the DirectPlay class registrations and loads the masked library, redirecting any function calls into it. 26 | 27 | The following hook DLLs are currently built: 28 | 29 | * ddraw.dll 30 | * dsound.dll 31 | 32 | New hook DLLs can be built by dumping a list of exported functions from the DLL you want to wrap, producing a stub assembly listing with `mkstubs.pl` and updating `build.bat` to build it. 33 | 34 | **NOTE**: Only ONE hook DLL should be used. 35 | 36 | ## Copyright 37 | 38 | Copyright © 2018 Daniel Collins 39 | 40 | Includes the [Minhook](https://github.com/TsudaKageyu/minhook) library by Tsuda Kageyu. 41 | -------------------------------------------------------------------------------- /directplay-lite.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | NOMINMAX;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /directplay-lite.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.102 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "directplay-lite", "directplay-lite\directplay-lite.vcxproj", "{6243E219-3927-43F6-9B5F-E34164900687}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dpnet", "dpnet\dpnet.vcxproj", "{AE3053CB-1C4C-427E-B2B9-902CCB5DA4BA}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ddraw", "hookdll\ddraw\ddraw.vcxproj", "{55AAE098-DAC0-47A7-95EE-E9EAAB5742DD}" 11 | EndProject 12 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "minhook", "minhook\minhook.vcxproj", "{8F39F2E4-0EF8-40F7-AD96-F76F2F200B3F}" 13 | EndProject 14 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dsound", "hookdll\dsound\dsound.vcxproj", "{DCDFDDD5-4D4B-4A62-BC02-079A54252B2A}" 15 | EndProject 16 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tests", "tests\tests.vcxproj", "{7DFB7CFB-C59A-44D8-A701-CA14D153EBF2}" 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|x86 = Debug|x86 21 | Release|x86 = Release|x86 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {6243E219-3927-43F6-9B5F-E34164900687}.Debug|x86.ActiveCfg = Debug|Win32 25 | {6243E219-3927-43F6-9B5F-E34164900687}.Debug|x86.Build.0 = Debug|Win32 26 | {6243E219-3927-43F6-9B5F-E34164900687}.Release|x86.ActiveCfg = Release|Win32 27 | {6243E219-3927-43F6-9B5F-E34164900687}.Release|x86.Build.0 = Release|Win32 28 | {AE3053CB-1C4C-427E-B2B9-902CCB5DA4BA}.Debug|x86.ActiveCfg = Debug|Win32 29 | {AE3053CB-1C4C-427E-B2B9-902CCB5DA4BA}.Debug|x86.Build.0 = Debug|Win32 30 | {AE3053CB-1C4C-427E-B2B9-902CCB5DA4BA}.Release|x86.ActiveCfg = Release|Win32 31 | {AE3053CB-1C4C-427E-B2B9-902CCB5DA4BA}.Release|x86.Build.0 = Release|Win32 32 | {55AAE098-DAC0-47A7-95EE-E9EAAB5742DD}.Debug|x86.ActiveCfg = Debug|Win32 33 | {55AAE098-DAC0-47A7-95EE-E9EAAB5742DD}.Debug|x86.Build.0 = Debug|Win32 34 | {55AAE098-DAC0-47A7-95EE-E9EAAB5742DD}.Release|x86.ActiveCfg = Release|Win32 35 | {55AAE098-DAC0-47A7-95EE-E9EAAB5742DD}.Release|x86.Build.0 = Release|Win32 36 | {8F39F2E4-0EF8-40F7-AD96-F76F2F200B3F}.Debug|x86.ActiveCfg = Debug|Win32 37 | {8F39F2E4-0EF8-40F7-AD96-F76F2F200B3F}.Debug|x86.Build.0 = Debug|Win32 38 | {8F39F2E4-0EF8-40F7-AD96-F76F2F200B3F}.Release|x86.ActiveCfg = Release|Win32 39 | {8F39F2E4-0EF8-40F7-AD96-F76F2F200B3F}.Release|x86.Build.0 = Release|Win32 40 | {DCDFDDD5-4D4B-4A62-BC02-079A54252B2A}.Debug|x86.ActiveCfg = Debug|Win32 41 | {DCDFDDD5-4D4B-4A62-BC02-079A54252B2A}.Debug|x86.Build.0 = Debug|Win32 42 | {DCDFDDD5-4D4B-4A62-BC02-079A54252B2A}.Release|x86.ActiveCfg = Release|Win32 43 | {DCDFDDD5-4D4B-4A62-BC02-079A54252B2A}.Release|x86.Build.0 = Release|Win32 44 | {7DFB7CFB-C59A-44D8-A701-CA14D153EBF2}.Debug|x86.ActiveCfg = Debug|Win32 45 | {7DFB7CFB-C59A-44D8-A701-CA14D153EBF2}.Debug|x86.Build.0 = Debug|Win32 46 | {7DFB7CFB-C59A-44D8-A701-CA14D153EBF2}.Release|x86.ActiveCfg = Release|Win32 47 | {7DFB7CFB-C59A-44D8-A701-CA14D153EBF2}.Release|x86.Build.0 = Release|Win32 48 | EndGlobalSection 49 | GlobalSection(SolutionProperties) = preSolution 50 | HideSolutionNode = FALSE 51 | EndGlobalSection 52 | GlobalSection(ExtensibilityGlobals) = postSolution 53 | SolutionGuid = {1609DD77-56F8-463D-BDBD-C08334701561} 54 | EndGlobalSection 55 | EndGlobal 56 | -------------------------------------------------------------------------------- /directplay-lite/directplay-lite.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | 15.0 15 | {6243E219-3927-43F6-9B5F-E34164900687} 16 | dpnetlib 17 | 10.0.17763.0 18 | 19 | 20 | 21 | StaticLibrary 22 | true 23 | v141 24 | MultiByte 25 | 26 | 27 | StaticLibrary 28 | false 29 | v141 30 | true 31 | MultiByte 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | $(SolutionDir)include;$(IncludePath) 49 | 50 | 51 | $(SolutionDir)include;$(IncludePath) 52 | 53 | 54 | 55 | Level3 56 | Disabled 57 | true 58 | true 59 | WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 60 | 61 | 62 | 63 | 64 | Level3 65 | MaxSpeed 66 | true 67 | true 68 | true 69 | true 70 | WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 71 | 72 | 73 | true 74 | true 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /directplay-lite/directplay-lite.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 47 | 48 | 49 | Source Files 50 | 51 | 52 | -------------------------------------------------------------------------------- /dpnet/dpnet.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | {6243e219-3927-43f6-9b5f-e34164900687} 19 | 20 | 21 | 22 | 23 | 24 | 25 | 15.0 26 | {AE3053CB-1C4C-427E-B2B9-902CCB5DA4BA} 27 | Win32Proj 28 | dpnetdll 29 | 10.0.17763.0 30 | 31 | 32 | 33 | DynamicLibrary 34 | true 35 | v141 36 | Unicode 37 | 38 | 39 | DynamicLibrary 40 | false 41 | v141 42 | true 43 | Unicode 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | true 61 | $(SolutionDir)include;$(IncludePath) 62 | dpnet 63 | 64 | 65 | false 66 | $(SolutionDir)include;$(IncludePath) 67 | dpnet 68 | 69 | 70 | 71 | NotUsing 72 | Level3 73 | Disabled 74 | true 75 | WIN32;_DEBUG;DPNETDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 76 | true 77 | 78 | 79 | Windows 80 | true 81 | dxguid.lib;iphlpapi.lib;ws2_32.lib;%(AdditionalDependencies) 82 | $(SolutionDir)src\dpnet.def 83 | 84 | 85 | 86 | 87 | NotUsing 88 | Level3 89 | MaxSpeed 90 | true 91 | true 92 | true 93 | WIN32;NDEBUG;DPNETDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 94 | true 95 | 96 | 97 | Windows 98 | true 99 | true 100 | true 101 | dxguid.lib;iphlpapi.lib;ws2_32.lib;%(AdditionalDependencies) 102 | $(SolutionDir)src\dpnet.def 103 | 104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /dpnet/dpnet.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | 23 | 24 | Source Files 25 | 26 | 27 | -------------------------------------------------------------------------------- /googletest/include/gtest/gtest-test-part.h: -------------------------------------------------------------------------------- 1 | // Copyright 2008, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // GOOGLETEST_CM0001 DO NOT DELETE 31 | 32 | #ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ 33 | #define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ 34 | 35 | #include 36 | #include 37 | #include "gtest/internal/gtest-internal.h" 38 | #include "gtest/internal/gtest-string.h" 39 | 40 | GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ 41 | /* class A needs to have dll-interface to be used by clients of class B */) 42 | 43 | namespace testing { 44 | 45 | // A copyable object representing the result of a test part (i.e. an 46 | // assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()). 47 | // 48 | // Don't inherit from TestPartResult as its destructor is not virtual. 49 | class GTEST_API_ TestPartResult { 50 | public: 51 | // The possible outcomes of a test part (i.e. an assertion or an 52 | // explicit SUCCEED(), FAIL(), or ADD_FAILURE()). 53 | enum Type { 54 | kSuccess, // Succeeded. 55 | kNonFatalFailure, // Failed but the test can continue. 56 | kFatalFailure // Failed and the test should be terminated. 57 | }; 58 | 59 | // C'tor. TestPartResult does NOT have a default constructor. 60 | // Always use this constructor (with parameters) to create a 61 | // TestPartResult object. 62 | TestPartResult(Type a_type, 63 | const char* a_file_name, 64 | int a_line_number, 65 | const char* a_message) 66 | : type_(a_type), 67 | file_name_(a_file_name == NULL ? "" : a_file_name), 68 | line_number_(a_line_number), 69 | summary_(ExtractSummary(a_message)), 70 | message_(a_message) { 71 | } 72 | 73 | // Gets the outcome of the test part. 74 | Type type() const { return type_; } 75 | 76 | // Gets the name of the source file where the test part took place, or 77 | // NULL if it's unknown. 78 | const char* file_name() const { 79 | return file_name_.empty() ? NULL : file_name_.c_str(); 80 | } 81 | 82 | // Gets the line in the source file where the test part took place, 83 | // or -1 if it's unknown. 84 | int line_number() const { return line_number_; } 85 | 86 | // Gets the summary of the failure message. 87 | const char* summary() const { return summary_.c_str(); } 88 | 89 | // Gets the message associated with the test part. 90 | const char* message() const { return message_.c_str(); } 91 | 92 | // Returns true iff the test part passed. 93 | bool passed() const { return type_ == kSuccess; } 94 | 95 | // Returns true iff the test part failed. 96 | bool failed() const { return type_ != kSuccess; } 97 | 98 | // Returns true iff the test part non-fatally failed. 99 | bool nonfatally_failed() const { return type_ == kNonFatalFailure; } 100 | 101 | // Returns true iff the test part fatally failed. 102 | bool fatally_failed() const { return type_ == kFatalFailure; } 103 | 104 | private: 105 | Type type_; 106 | 107 | // Gets the summary of the failure message by omitting the stack 108 | // trace in it. 109 | static std::string ExtractSummary(const char* message); 110 | 111 | // The name of the source file where the test part took place, or 112 | // "" if the source file is unknown. 113 | std::string file_name_; 114 | // The line in the source file where the test part took place, or -1 115 | // if the line number is unknown. 116 | int line_number_; 117 | std::string summary_; // The test failure summary. 118 | std::string message_; // The test failure message. 119 | }; 120 | 121 | // Prints a TestPartResult object. 122 | std::ostream& operator<<(std::ostream& os, const TestPartResult& result); 123 | 124 | // An array of TestPartResult objects. 125 | // 126 | // Don't inherit from TestPartResultArray as its destructor is not 127 | // virtual. 128 | class GTEST_API_ TestPartResultArray { 129 | public: 130 | TestPartResultArray() {} 131 | 132 | // Appends the given TestPartResult to the array. 133 | void Append(const TestPartResult& result); 134 | 135 | // Returns the TestPartResult at the given index (0-based). 136 | const TestPartResult& GetTestPartResult(int index) const; 137 | 138 | // Returns the number of TestPartResult objects in the array. 139 | int size() const; 140 | 141 | private: 142 | std::vector array_; 143 | 144 | GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray); 145 | }; 146 | 147 | // This interface knows how to report a test part result. 148 | class GTEST_API_ TestPartResultReporterInterface { 149 | public: 150 | virtual ~TestPartResultReporterInterface() {} 151 | 152 | virtual void ReportTestPartResult(const TestPartResult& result) = 0; 153 | }; 154 | 155 | namespace internal { 156 | 157 | // This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a 158 | // statement generates new fatal failures. To do so it registers itself as the 159 | // current test part result reporter. Besides checking if fatal failures were 160 | // reported, it only delegates the reporting to the former result reporter. 161 | // The original result reporter is restored in the destructor. 162 | // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. 163 | class GTEST_API_ HasNewFatalFailureHelper 164 | : public TestPartResultReporterInterface { 165 | public: 166 | HasNewFatalFailureHelper(); 167 | virtual ~HasNewFatalFailureHelper(); 168 | virtual void ReportTestPartResult(const TestPartResult& result); 169 | bool has_new_fatal_failure() const { return has_new_fatal_failure_; } 170 | private: 171 | bool has_new_fatal_failure_; 172 | TestPartResultReporterInterface* original_reporter_; 173 | 174 | GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper); 175 | }; 176 | 177 | } // namespace internal 178 | 179 | } // namespace testing 180 | 181 | GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 182 | 183 | #endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ 184 | -------------------------------------------------------------------------------- /googletest/include/gtest/gtest_prod.h: -------------------------------------------------------------------------------- 1 | // Copyright 2006, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // 31 | // Google C++ Testing and Mocking Framework definitions useful in production code. 32 | // GOOGLETEST_CM0003 DO NOT DELETE 33 | 34 | #ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ 35 | #define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ 36 | 37 | // When you need to test the private or protected members of a class, 38 | // use the FRIEND_TEST macro to declare your tests as friends of the 39 | // class. For example: 40 | // 41 | // class MyClass { 42 | // private: 43 | // void PrivateMethod(); 44 | // FRIEND_TEST(MyClassTest, PrivateMethodWorks); 45 | // }; 46 | // 47 | // class MyClassTest : public testing::Test { 48 | // // ... 49 | // }; 50 | // 51 | // TEST_F(MyClassTest, PrivateMethodWorks) { 52 | // // Can call MyClass::PrivateMethod() here. 53 | // } 54 | // 55 | // Note: The test class must be in the same namespace as the class being tested. 56 | // For example, putting MyClassTest in an anonymous namespace will not work. 57 | 58 | #define FRIEND_TEST(test_case_name, test_name)\ 59 | friend class test_case_name##_##test_name##_Test 60 | 61 | #endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_ 62 | -------------------------------------------------------------------------------- /googletest/include/gtest/internal/custom/README.md: -------------------------------------------------------------------------------- 1 | # Customization Points 2 | 3 | The custom directory is an injection point for custom user configurations. 4 | 5 | ## Header `gtest.h` 6 | 7 | ### The following macros can be defined: 8 | 9 | * `GTEST_OS_STACK_TRACE_GETTER_` - The name of an implementation of 10 | `OsStackTraceGetterInterface`. 11 | * `GTEST_CUSTOM_TEMPDIR_FUNCTION_` - An override for `testing::TempDir()`. See 12 | `testing::TempDir` for semantics and signature. 13 | 14 | ## Header `gtest-port.h` 15 | 16 | The following macros can be defined: 17 | 18 | ### Flag related macros: 19 | 20 | * `GTEST_FLAG(flag_name)` 21 | * `GTEST_USE_OWN_FLAGFILE_FLAG_` - Define to 0 when the system provides its 22 | own flagfile flag parsing. 23 | * `GTEST_DECLARE_bool_(name)` 24 | * `GTEST_DECLARE_int32_(name)` 25 | * `GTEST_DECLARE_string_(name)` 26 | * `GTEST_DEFINE_bool_(name, default_val, doc)` 27 | * `GTEST_DEFINE_int32_(name, default_val, doc)` 28 | * `GTEST_DEFINE_string_(name, default_val, doc)` 29 | 30 | ### Logging: 31 | 32 | * `GTEST_LOG_(severity)` 33 | * `GTEST_CHECK_(condition)` 34 | * Functions `LogToStderr()` and `FlushInfoLog()` have to be provided too. 35 | 36 | ### Threading: 37 | 38 | * `GTEST_HAS_NOTIFICATION_` - Enabled if Notification is already provided. 39 | * `GTEST_HAS_MUTEX_AND_THREAD_LOCAL_` - Enabled if `Mutex` and `ThreadLocal` 40 | are already provided. Must also provide `GTEST_DECLARE_STATIC_MUTEX_(mutex)` 41 | and `GTEST_DEFINE_STATIC_MUTEX_(mutex)` 42 | * `GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks)` 43 | * `GTEST_LOCK_EXCLUDED_(locks)` 44 | 45 | ### Underlying library support features 46 | 47 | * `GTEST_HAS_CXXABI_H_` 48 | 49 | ### Exporting API symbols: 50 | 51 | * `GTEST_API_` - Specifier for exported symbols. 52 | 53 | ## Header `gtest-printers.h` 54 | 55 | * See documentation at `gtest/gtest-printers.h` for details on how to define a 56 | custom printer. 57 | -------------------------------------------------------------------------------- /googletest/include/gtest/internal/custom/gtest-port.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Injection point for custom user configurations. See README for details 31 | // 32 | // ** Custom implementation starts here ** 33 | 34 | #ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ 35 | #define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ 36 | 37 | #endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ 38 | -------------------------------------------------------------------------------- /googletest/include/gtest/internal/custom/gtest-printers.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // This file provides an injection point for custom printers in a local 31 | // installation of gTest. 32 | // It will be included from gtest-printers.h and the overrides in this file 33 | // will be visible to everyone. 34 | // 35 | // Injection point for custom user configurations. See README for details 36 | // 37 | // ** Custom implementation starts here ** 38 | 39 | #ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ 40 | #define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ 41 | 42 | #endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ 43 | -------------------------------------------------------------------------------- /googletest/include/gtest/internal/custom/gtest.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Injection point for custom user configurations. See README for details 31 | // 32 | // ** Custom implementation starts here ** 33 | 34 | #ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ 35 | #define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ 36 | 37 | #endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ 38 | -------------------------------------------------------------------------------- /googletest/include/gtest/internal/gtest-port-arch.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // The Google C++ Testing and Mocking Framework (Google Test) 31 | // 32 | // This header file defines the GTEST_OS_* macro. 33 | // It is separate from gtest-port.h so that custom/gtest-port.h can include it. 34 | 35 | #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ 36 | #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ 37 | 38 | // Determines the platform on which Google Test is compiled. 39 | #ifdef __CYGWIN__ 40 | # define GTEST_OS_CYGWIN 1 41 | #elif defined __SYMBIAN32__ 42 | # define GTEST_OS_SYMBIAN 1 43 | #elif defined _WIN32 44 | # define GTEST_OS_WINDOWS 1 45 | # ifdef _WIN32_WCE 46 | # define GTEST_OS_WINDOWS_MOBILE 1 47 | # elif defined(__MINGW__) || defined(__MINGW32__) 48 | # define GTEST_OS_WINDOWS_MINGW 1 49 | # elif defined(WINAPI_FAMILY) 50 | # include 51 | # if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) 52 | # define GTEST_OS_WINDOWS_DESKTOP 1 53 | # elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) 54 | # define GTEST_OS_WINDOWS_PHONE 1 55 | # elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) 56 | # define GTEST_OS_WINDOWS_RT 1 57 | # elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_TV_TITLE) 58 | # define GTEST_OS_WINDOWS_PHONE 1 59 | # define GTEST_OS_WINDOWS_TV_TITLE 1 60 | # else 61 | // WINAPI_FAMILY defined but no known partition matched. 62 | // Default to desktop. 63 | # define GTEST_OS_WINDOWS_DESKTOP 1 64 | # endif 65 | # else 66 | # define GTEST_OS_WINDOWS_DESKTOP 1 67 | # endif // _WIN32_WCE 68 | #elif defined __APPLE__ 69 | # define GTEST_OS_MAC 1 70 | # if TARGET_OS_IPHONE 71 | # define GTEST_OS_IOS 1 72 | # endif 73 | #elif defined __FreeBSD__ 74 | # define GTEST_OS_FREEBSD 1 75 | #elif defined __Fuchsia__ 76 | # define GTEST_OS_FUCHSIA 1 77 | #elif defined __linux__ 78 | # define GTEST_OS_LINUX 1 79 | # if defined __ANDROID__ 80 | # define GTEST_OS_LINUX_ANDROID 1 81 | # endif 82 | #elif defined __MVS__ 83 | # define GTEST_OS_ZOS 1 84 | #elif defined(__sun) && defined(__SVR4) 85 | # define GTEST_OS_SOLARIS 1 86 | #elif defined(_AIX) 87 | # define GTEST_OS_AIX 1 88 | #elif defined(__hpux) 89 | # define GTEST_OS_HPUX 1 90 | #elif defined __native_client__ 91 | # define GTEST_OS_NACL 1 92 | #elif defined __NetBSD__ 93 | # define GTEST_OS_NETBSD 1 94 | #elif defined __OpenBSD__ 95 | # define GTEST_OS_OPENBSD 1 96 | #elif defined __QNX__ 97 | # define GTEST_OS_QNX 1 98 | #endif // __CYGWIN__ 99 | 100 | #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ 101 | -------------------------------------------------------------------------------- /googletest/include/gtest/internal/gtest-string.h: -------------------------------------------------------------------------------- 1 | // Copyright 2005, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // The Google C++ Testing and Mocking Framework (Google Test) 31 | // 32 | // This header file declares the String class and functions used internally by 33 | // Google Test. They are subject to change without notice. They should not used 34 | // by code external to Google Test. 35 | // 36 | // This header file is #included by gtest-internal.h. 37 | // It should not be #included by other files. 38 | 39 | // GOOGLETEST_CM0001 DO NOT DELETE 40 | 41 | #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ 42 | #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ 43 | 44 | #ifdef __BORLANDC__ 45 | // string.h is not guaranteed to provide strcpy on C++ Builder. 46 | # include 47 | #endif 48 | 49 | #include 50 | #include 51 | 52 | #include "gtest/internal/gtest-port.h" 53 | 54 | namespace testing { 55 | namespace internal { 56 | 57 | // String - an abstract class holding static string utilities. 58 | class GTEST_API_ String { 59 | public: 60 | // Static utility methods 61 | 62 | // Clones a 0-terminated C string, allocating memory using new. The 63 | // caller is responsible for deleting the return value using 64 | // delete[]. Returns the cloned string, or NULL if the input is 65 | // NULL. 66 | // 67 | // This is different from strdup() in string.h, which allocates 68 | // memory using malloc(). 69 | static const char* CloneCString(const char* c_str); 70 | 71 | #if GTEST_OS_WINDOWS_MOBILE 72 | // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be 73 | // able to pass strings to Win32 APIs on CE we need to convert them 74 | // to 'Unicode', UTF-16. 75 | 76 | // Creates a UTF-16 wide string from the given ANSI string, allocating 77 | // memory using new. The caller is responsible for deleting the return 78 | // value using delete[]. Returns the wide string, or NULL if the 79 | // input is NULL. 80 | // 81 | // The wide string is created using the ANSI codepage (CP_ACP) to 82 | // match the behaviour of the ANSI versions of Win32 calls and the 83 | // C runtime. 84 | static LPCWSTR AnsiToUtf16(const char* c_str); 85 | 86 | // Creates an ANSI string from the given wide string, allocating 87 | // memory using new. The caller is responsible for deleting the return 88 | // value using delete[]. Returns the ANSI string, or NULL if the 89 | // input is NULL. 90 | // 91 | // The returned string is created using the ANSI codepage (CP_ACP) to 92 | // match the behaviour of the ANSI versions of Win32 calls and the 93 | // C runtime. 94 | static const char* Utf16ToAnsi(LPCWSTR utf16_str); 95 | #endif 96 | 97 | // Compares two C strings. Returns true iff they have the same content. 98 | // 99 | // Unlike strcmp(), this function can handle NULL argument(s). A 100 | // NULL C string is considered different to any non-NULL C string, 101 | // including the empty string. 102 | static bool CStringEquals(const char* lhs, const char* rhs); 103 | 104 | // Converts a wide C string to a String using the UTF-8 encoding. 105 | // NULL will be converted to "(null)". If an error occurred during 106 | // the conversion, "(failed to convert from wide string)" is 107 | // returned. 108 | static std::string ShowWideCString(const wchar_t* wide_c_str); 109 | 110 | // Compares two wide C strings. Returns true iff they have the same 111 | // content. 112 | // 113 | // Unlike wcscmp(), this function can handle NULL argument(s). A 114 | // NULL C string is considered different to any non-NULL C string, 115 | // including the empty string. 116 | static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); 117 | 118 | // Compares two C strings, ignoring case. Returns true iff they 119 | // have the same content. 120 | // 121 | // Unlike strcasecmp(), this function can handle NULL argument(s). 122 | // A NULL C string is considered different to any non-NULL C string, 123 | // including the empty string. 124 | static bool CaseInsensitiveCStringEquals(const char* lhs, 125 | const char* rhs); 126 | 127 | // Compares two wide C strings, ignoring case. Returns true iff they 128 | // have the same content. 129 | // 130 | // Unlike wcscasecmp(), this function can handle NULL argument(s). 131 | // A NULL C string is considered different to any non-NULL wide C string, 132 | // including the empty string. 133 | // NB: The implementations on different platforms slightly differ. 134 | // On windows, this method uses _wcsicmp which compares according to LC_CTYPE 135 | // environment variable. On GNU platform this method uses wcscasecmp 136 | // which compares according to LC_CTYPE category of the current locale. 137 | // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the 138 | // current locale. 139 | static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs, 140 | const wchar_t* rhs); 141 | 142 | // Returns true iff the given string ends with the given suffix, ignoring 143 | // case. Any string is considered to end with an empty suffix. 144 | static bool EndsWithCaseInsensitive( 145 | const std::string& str, const std::string& suffix); 146 | 147 | // Formats an int value as "%02d". 148 | static std::string FormatIntWidth2(int value); // "%02d" for width == 2 149 | 150 | // Formats an int value as "%X". 151 | static std::string FormatHexInt(int value); 152 | 153 | // Formats a byte as "%02X". 154 | static std::string FormatByte(unsigned char value); 155 | 156 | private: 157 | String(); // Not meant to be instantiated. 158 | }; // class String 159 | 160 | // Gets the content of the stringstream's buffer as an std::string. Each '\0' 161 | // character in the buffer is replaced with "\\0". 162 | GTEST_API_ std::string StringStreamToString(::std::stringstream* stream); 163 | 164 | } // namespace internal 165 | } // namespace testing 166 | 167 | #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ 168 | -------------------------------------------------------------------------------- /googletest/src/gtest-all.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2008, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // 31 | // Google C++ Testing and Mocking Framework (Google Test) 32 | // 33 | // Sometimes it's desirable to build Google Test by compiling a single file. 34 | // This file serves this purpose. 35 | 36 | // This line ensures that gtest.h can be compiled on its own, even 37 | // when it's fused. 38 | #include "gtest/gtest.h" 39 | 40 | // The following lines pull in the real gtest *.cc files. 41 | #include "src/gtest.cc" 42 | #include "src/gtest-death-test.cc" 43 | #include "src/gtest-filepath.cc" 44 | #include "src/gtest-port.cc" 45 | #include "src/gtest-printers.cc" 46 | #include "src/gtest-test-part.cc" 47 | #include "src/gtest-typed-test.cc" 48 | -------------------------------------------------------------------------------- /googletest/src/gtest-test-part.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2008, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // 31 | // The Google C++ Testing and Mocking Framework (Google Test) 32 | 33 | #include "gtest/gtest-test-part.h" 34 | #include "src/gtest-internal-inl.h" 35 | 36 | namespace testing { 37 | 38 | using internal::GetUnitTestImpl; 39 | 40 | // Gets the summary of the failure message by omitting the stack trace 41 | // in it. 42 | std::string TestPartResult::ExtractSummary(const char* message) { 43 | const char* const stack_trace = strstr(message, internal::kStackTraceMarker); 44 | return stack_trace == NULL ? message : 45 | std::string(message, stack_trace); 46 | } 47 | 48 | // Prints a TestPartResult object. 49 | std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { 50 | return os 51 | << result.file_name() << ":" << result.line_number() << ": " 52 | << (result.type() == TestPartResult::kSuccess ? "Success" : 53 | result.type() == TestPartResult::kFatalFailure ? "Fatal failure" : 54 | "Non-fatal failure") << ":\n" 55 | << result.message() << std::endl; 56 | } 57 | 58 | // Appends a TestPartResult to the array. 59 | void TestPartResultArray::Append(const TestPartResult& result) { 60 | array_.push_back(result); 61 | } 62 | 63 | // Returns the TestPartResult at the given index (0-based). 64 | const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { 65 | if (index < 0 || index >= size()) { 66 | printf("\nInvalid index (%d) into TestPartResultArray.\n", index); 67 | internal::posix::Abort(); 68 | } 69 | 70 | return array_[index]; 71 | } 72 | 73 | // Returns the number of TestPartResult objects in the array. 74 | int TestPartResultArray::size() const { 75 | return static_cast(array_.size()); 76 | } 77 | 78 | namespace internal { 79 | 80 | HasNewFatalFailureHelper::HasNewFatalFailureHelper() 81 | : has_new_fatal_failure_(false), 82 | original_reporter_(GetUnitTestImpl()-> 83 | GetTestPartResultReporterForCurrentThread()) { 84 | GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this); 85 | } 86 | 87 | HasNewFatalFailureHelper::~HasNewFatalFailureHelper() { 88 | GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread( 89 | original_reporter_); 90 | } 91 | 92 | void HasNewFatalFailureHelper::ReportTestPartResult( 93 | const TestPartResult& result) { 94 | if (result.fatally_failed()) 95 | has_new_fatal_failure_ = true; 96 | original_reporter_->ReportTestPartResult(result); 97 | } 98 | 99 | } // namespace internal 100 | 101 | } // namespace testing 102 | -------------------------------------------------------------------------------- /googletest/src/gtest-typed-test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2008 Google Inc. 2 | // All Rights Reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | 31 | #include "gtest/gtest-typed-test.h" 32 | 33 | #include "gtest/gtest.h" 34 | 35 | namespace testing { 36 | namespace internal { 37 | 38 | #if GTEST_HAS_TYPED_TEST_P 39 | 40 | // Skips to the first non-space char in str. Returns an empty string if str 41 | // contains only whitespace characters. 42 | static const char* SkipSpaces(const char* str) { 43 | while (IsSpace(*str)) 44 | str++; 45 | return str; 46 | } 47 | 48 | static std::vector SplitIntoTestNames(const char* src) { 49 | std::vector name_vec; 50 | src = SkipSpaces(src); 51 | for (; src != NULL; src = SkipComma(src)) { 52 | name_vec.push_back(StripTrailingSpaces(GetPrefixUntilComma(src))); 53 | } 54 | return name_vec; 55 | } 56 | 57 | // Verifies that registered_tests match the test names in 58 | // registered_tests_; returns registered_tests if successful, or 59 | // aborts the program otherwise. 60 | const char* TypedTestCasePState::VerifyRegisteredTestNames( 61 | const char* file, int line, const char* registered_tests) { 62 | typedef RegisteredTestsMap::const_iterator RegisteredTestIter; 63 | registered_ = true; 64 | 65 | std::vector name_vec = SplitIntoTestNames(registered_tests); 66 | 67 | Message errors; 68 | 69 | std::set tests; 70 | for (std::vector::const_iterator name_it = name_vec.begin(); 71 | name_it != name_vec.end(); ++name_it) { 72 | const std::string& name = *name_it; 73 | if (tests.count(name) != 0) { 74 | errors << "Test " << name << " is listed more than once.\n"; 75 | continue; 76 | } 77 | 78 | bool found = false; 79 | for (RegisteredTestIter it = registered_tests_.begin(); 80 | it != registered_tests_.end(); 81 | ++it) { 82 | if (name == it->first) { 83 | found = true; 84 | break; 85 | } 86 | } 87 | 88 | if (found) { 89 | tests.insert(name); 90 | } else { 91 | errors << "No test named " << name 92 | << " can be found in this test case.\n"; 93 | } 94 | } 95 | 96 | for (RegisteredTestIter it = registered_tests_.begin(); 97 | it != registered_tests_.end(); 98 | ++it) { 99 | if (tests.count(it->first) == 0) { 100 | errors << "You forgot to list test " << it->first << ".\n"; 101 | } 102 | } 103 | 104 | const std::string& errors_str = errors.GetString(); 105 | if (errors_str != "") { 106 | fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), 107 | errors_str.c_str()); 108 | fflush(stderr); 109 | posix::Abort(); 110 | } 111 | 112 | return registered_tests; 113 | } 114 | 115 | #endif // GTEST_HAS_TYPED_TEST_P 116 | 117 | } // namespace internal 118 | } // namespace testing 119 | -------------------------------------------------------------------------------- /googletest/src/gtest_main.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2006, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | #include 31 | #include "gtest/gtest.h" 32 | 33 | GTEST_API_ int main(int argc, char **argv) { 34 | printf("Running main() from %s\n", __FILE__); 35 | testing::InitGoogleTest(&argc, argv); 36 | return RUN_ALL_TESTS(); 37 | } 38 | -------------------------------------------------------------------------------- /hookdll/ddraw/ddraw.def: -------------------------------------------------------------------------------- 1 | LIBRARY DDRAW.dll 2 | EXPORTS 3 | AcquireDDThreadLock @1 4 | CompleteCreateSysmemSurface @2 5 | D3DParseUnknownCommand @3 6 | DDGetAttachedSurfaceLcl @4 7 | DDInternalLock @5 8 | DDInternalUnlock @6 9 | DirectDrawCreate @8 10 | DirectDrawCreateClipper @9 11 | DirectDrawCreateEx @10 12 | DirectDrawEnumerateA @11 13 | DirectDrawEnumerateExA @12 14 | DirectDrawEnumerateExW @13 15 | DirectDrawEnumerateW @14 16 | DllCanUnloadNow @15 PRIVATE 17 | DllGetClassObject @16 PRIVATE 18 | DSoundHelp @7 19 | GetDDSurfaceLocal @17 20 | GetOLEThunkData @18 21 | GetSurfaceFromDC @19 22 | RegisterSpecialCase @20 23 | ReleaseDDThreadLock @21 24 | SetAppCompatData @22 25 | -------------------------------------------------------------------------------- /hookdll/ddraw/ddraw.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | {6243e219-3927-43f6-9b5f-e34164900687} 19 | 20 | 21 | {8f39f2e4-0ef8-40f7-ad96-f76f2f200b3f} 22 | 23 | 24 | 25 | 26 | Document 27 | ml /c /Cx /coff /Fo$(OutDir)%(Filename).obj %(FullPath) 28 | $(OutDir)%(Filename).obj 29 | ml /c /Cx /coff /Fo$(OutDir)%(Filename).obj %(FullPath) 30 | $(OutDir)%(Filename).obj 31 | true 32 | true 33 | 34 | 35 | 36 | 37 | 38 | 39 | 15.0 40 | {55AAE098-DAC0-47A7-95EE-E9EAAB5742DD} 41 | Win32Proj 42 | ddraw 43 | 10.0.17763.0 44 | 45 | 46 | 47 | DynamicLibrary 48 | true 49 | v141 50 | MultiByte 51 | 52 | 53 | DynamicLibrary 54 | false 55 | v141 56 | true 57 | MultiByte 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | $(SolutionDir)include;$(SolutionDir)minhook\include;$(IncludePath) 76 | 77 | 78 | false 79 | $(SolutionDir)include;$(SolutionDir)minhook\include;$(IncludePath) 80 | 81 | 82 | 83 | NotUsing 84 | Level3 85 | Disabled 86 | true 87 | WIN32;_DEBUG;DDRAW_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 88 | true 89 | 90 | 91 | Windows 92 | true 93 | dxguid.lib;iphlpapi.lib;ws2_32.lib;%(AdditionalDependencies) 94 | $(ProjectDir)$(MSBuildProjectName).def 95 | 96 | 97 | true 98 | 99 | 100 | 101 | 102 | NotUsing 103 | Level3 104 | MaxSpeed 105 | true 106 | true 107 | true 108 | WIN32;NDEBUG;DDRAW_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 109 | true 110 | 111 | 112 | Windows 113 | true 114 | true 115 | true 116 | dxguid.lib;iphlpapi.lib;ws2_32.lib;%(AdditionalDependencies) 117 | $(ProjectDir)$(MSBuildProjectName).def 118 | 119 | 120 | 121 | true 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /hookdll/ddraw/ddraw.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | 23 | 24 | Source Files 25 | 26 | 27 | 28 | 29 | Source Files 30 | 31 | 32 | -------------------------------------------------------------------------------- /hookdll/dsound/dsound.asm: -------------------------------------------------------------------------------- 1 | .586 2 | .MODEL FLAT, C 3 | 4 | EXTERN find_sym@8: PROC 5 | 6 | .DATA 7 | 8 | dll_name db "dsound.dll", 0 9 | 10 | .DATA 11 | 12 | DirectSoundCreate_sym db "DirectSoundCreate", 0 13 | DirectSoundCreate_addr dd 0 14 | 15 | .CODE 16 | 17 | PUBLIC DirectSoundCreate 18 | DirectSoundCreate PROC 19 | cmp DirectSoundCreate_addr, 0 20 | jne DirectSoundCreate_jmp 21 | push offset DirectSoundCreate_sym 22 | push offset dll_name 23 | call find_sym@8 24 | mov DirectSoundCreate_addr, eax 25 | DirectSoundCreate_jmp: 26 | jmp [DirectSoundCreate_addr] 27 | DirectSoundCreate ENDP 28 | 29 | .DATA 30 | 31 | DirectSoundEnumerateA_sym db "DirectSoundEnumerateA", 0 32 | DirectSoundEnumerateA_addr dd 0 33 | 34 | .CODE 35 | 36 | PUBLIC DirectSoundEnumerateA 37 | DirectSoundEnumerateA PROC 38 | cmp DirectSoundEnumerateA_addr, 0 39 | jne DirectSoundEnumerateA_jmp 40 | push offset DirectSoundEnumerateA_sym 41 | push offset dll_name 42 | call find_sym@8 43 | mov DirectSoundEnumerateA_addr, eax 44 | DirectSoundEnumerateA_jmp: 45 | jmp [DirectSoundEnumerateA_addr] 46 | DirectSoundEnumerateA ENDP 47 | 48 | .DATA 49 | 50 | DirectSoundEnumerateW_sym db "DirectSoundEnumerateW", 0 51 | DirectSoundEnumerateW_addr dd 0 52 | 53 | .CODE 54 | 55 | PUBLIC DirectSoundEnumerateW 56 | DirectSoundEnumerateW PROC 57 | cmp DirectSoundEnumerateW_addr, 0 58 | jne DirectSoundEnumerateW_jmp 59 | push offset DirectSoundEnumerateW_sym 60 | push offset dll_name 61 | call find_sym@8 62 | mov DirectSoundEnumerateW_addr, eax 63 | DirectSoundEnumerateW_jmp: 64 | jmp [DirectSoundEnumerateW_addr] 65 | DirectSoundEnumerateW ENDP 66 | 67 | .DATA 68 | 69 | DllCanUnloadNow_sym db "DllCanUnloadNow", 0 70 | DllCanUnloadNow_addr dd 0 71 | 72 | .CODE 73 | 74 | PUBLIC DllCanUnloadNow 75 | DllCanUnloadNow PROC 76 | cmp DllCanUnloadNow_addr, 0 77 | jne DllCanUnloadNow_jmp 78 | push offset DllCanUnloadNow_sym 79 | push offset dll_name 80 | call find_sym@8 81 | mov DllCanUnloadNow_addr, eax 82 | DllCanUnloadNow_jmp: 83 | jmp [DllCanUnloadNow_addr] 84 | DllCanUnloadNow ENDP 85 | 86 | .DATA 87 | 88 | DllGetClassObject_sym db "DllGetClassObject", 0 89 | DllGetClassObject_addr dd 0 90 | 91 | .CODE 92 | 93 | PUBLIC DllGetClassObject 94 | DllGetClassObject PROC 95 | cmp DllGetClassObject_addr, 0 96 | jne DllGetClassObject_jmp 97 | push offset DllGetClassObject_sym 98 | push offset dll_name 99 | call find_sym@8 100 | mov DllGetClassObject_addr, eax 101 | DllGetClassObject_jmp: 102 | jmp [DllGetClassObject_addr] 103 | DllGetClassObject ENDP 104 | 105 | .DATA 106 | 107 | DirectSoundCaptureCreate_sym db "DirectSoundCaptureCreate", 0 108 | DirectSoundCaptureCreate_addr dd 0 109 | 110 | .CODE 111 | 112 | PUBLIC DirectSoundCaptureCreate 113 | DirectSoundCaptureCreate PROC 114 | cmp DirectSoundCaptureCreate_addr, 0 115 | jne DirectSoundCaptureCreate_jmp 116 | push offset DirectSoundCaptureCreate_sym 117 | push offset dll_name 118 | call find_sym@8 119 | mov DirectSoundCaptureCreate_addr, eax 120 | DirectSoundCaptureCreate_jmp: 121 | jmp [DirectSoundCaptureCreate_addr] 122 | DirectSoundCaptureCreate ENDP 123 | 124 | .DATA 125 | 126 | DirectSoundCaptureEnumerateA_sym db "DirectSoundCaptureEnumerateA", 0 127 | DirectSoundCaptureEnumerateA_addr dd 0 128 | 129 | .CODE 130 | 131 | PUBLIC DirectSoundCaptureEnumerateA 132 | DirectSoundCaptureEnumerateA PROC 133 | cmp DirectSoundCaptureEnumerateA_addr, 0 134 | jne DirectSoundCaptureEnumerateA_jmp 135 | push offset DirectSoundCaptureEnumerateA_sym 136 | push offset dll_name 137 | call find_sym@8 138 | mov DirectSoundCaptureEnumerateA_addr, eax 139 | DirectSoundCaptureEnumerateA_jmp: 140 | jmp [DirectSoundCaptureEnumerateA_addr] 141 | DirectSoundCaptureEnumerateA ENDP 142 | 143 | .DATA 144 | 145 | DirectSoundCaptureEnumerateW_sym db "DirectSoundCaptureEnumerateW", 0 146 | DirectSoundCaptureEnumerateW_addr dd 0 147 | 148 | .CODE 149 | 150 | PUBLIC DirectSoundCaptureEnumerateW 151 | DirectSoundCaptureEnumerateW PROC 152 | cmp DirectSoundCaptureEnumerateW_addr, 0 153 | jne DirectSoundCaptureEnumerateW_jmp 154 | push offset DirectSoundCaptureEnumerateW_sym 155 | push offset dll_name 156 | call find_sym@8 157 | mov DirectSoundCaptureEnumerateW_addr, eax 158 | DirectSoundCaptureEnumerateW_jmp: 159 | jmp [DirectSoundCaptureEnumerateW_addr] 160 | DirectSoundCaptureEnumerateW ENDP 161 | 162 | .DATA 163 | 164 | GetDeviceID_sym db "GetDeviceID", 0 165 | GetDeviceID_addr dd 0 166 | 167 | .CODE 168 | 169 | PUBLIC GetDeviceID 170 | GetDeviceID PROC 171 | cmp GetDeviceID_addr, 0 172 | jne GetDeviceID_jmp 173 | push offset GetDeviceID_sym 174 | push offset dll_name 175 | call find_sym@8 176 | mov GetDeviceID_addr, eax 177 | GetDeviceID_jmp: 178 | jmp [GetDeviceID_addr] 179 | GetDeviceID ENDP 180 | 181 | .DATA 182 | 183 | DirectSoundFullDuplexCreate_sym db "DirectSoundFullDuplexCreate", 0 184 | DirectSoundFullDuplexCreate_addr dd 0 185 | 186 | .CODE 187 | 188 | PUBLIC DirectSoundFullDuplexCreate 189 | DirectSoundFullDuplexCreate PROC 190 | cmp DirectSoundFullDuplexCreate_addr, 0 191 | jne DirectSoundFullDuplexCreate_jmp 192 | push offset DirectSoundFullDuplexCreate_sym 193 | push offset dll_name 194 | call find_sym@8 195 | mov DirectSoundFullDuplexCreate_addr, eax 196 | DirectSoundFullDuplexCreate_jmp: 197 | jmp [DirectSoundFullDuplexCreate_addr] 198 | DirectSoundFullDuplexCreate ENDP 199 | 200 | .DATA 201 | 202 | DirectSoundCreate8_sym db "DirectSoundCreate8", 0 203 | DirectSoundCreate8_addr dd 0 204 | 205 | .CODE 206 | 207 | PUBLIC DirectSoundCreate8 208 | DirectSoundCreate8 PROC 209 | cmp DirectSoundCreate8_addr, 0 210 | jne DirectSoundCreate8_jmp 211 | push offset DirectSoundCreate8_sym 212 | push offset dll_name 213 | call find_sym@8 214 | mov DirectSoundCreate8_addr, eax 215 | DirectSoundCreate8_jmp: 216 | jmp [DirectSoundCreate8_addr] 217 | DirectSoundCreate8 ENDP 218 | 219 | .DATA 220 | 221 | DirectSoundCaptureCreate8_sym db "DirectSoundCaptureCreate8", 0 222 | DirectSoundCaptureCreate8_addr dd 0 223 | 224 | .CODE 225 | 226 | PUBLIC DirectSoundCaptureCreate8 227 | DirectSoundCaptureCreate8 PROC 228 | cmp DirectSoundCaptureCreate8_addr, 0 229 | jne DirectSoundCaptureCreate8_jmp 230 | push offset DirectSoundCaptureCreate8_sym 231 | push offset dll_name 232 | call find_sym@8 233 | mov DirectSoundCaptureCreate8_addr, eax 234 | DirectSoundCaptureCreate8_jmp: 235 | jmp [DirectSoundCaptureCreate8_addr] 236 | DirectSoundCaptureCreate8 ENDP 237 | 238 | END 239 | -------------------------------------------------------------------------------- /hookdll/dsound/dsound.def: -------------------------------------------------------------------------------- 1 | LIBRARY DSOUND.dll 2 | EXPORTS 3 | DirectSoundCreate @1 4 | DirectSoundEnumerateA @2 5 | DirectSoundEnumerateW @3 6 | DllCanUnloadNow @4 PRIVATE 7 | DllGetClassObject @5 PRIVATE 8 | DirectSoundCaptureCreate @6 9 | DirectSoundCaptureEnumerateA @7 10 | DirectSoundCaptureEnumerateW @8 11 | GetDeviceID @9 12 | DirectSoundFullDuplexCreate @10 13 | DirectSoundCreate8 @11 14 | DirectSoundCaptureCreate8 @12 15 | -------------------------------------------------------------------------------- /hookdll/dsound/dsound.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | {6243e219-3927-43f6-9b5f-e34164900687} 19 | 20 | 21 | {8f39f2e4-0ef8-40f7-ad96-f76f2f200b3f} 22 | 23 | 24 | 25 | 26 | Document 27 | ml /c /Cx /coff /Fo$(OutDir)%(Filename).obj %(FullPath) 28 | $(OutDir)%(Filename).obj 29 | ml /c /Cx /coff /Fo$(OutDir)%(Filename).obj %(FullPath) 30 | $(OutDir)%(Filename).obj 31 | true 32 | true 33 | 34 | 35 | 36 | 37 | 38 | 39 | 15.0 40 | {DCDFDDD5-4D4B-4A62-BC02-079A54252B2A} 41 | Win32Proj 42 | dsound 43 | 10.0.17763.0 44 | 45 | 46 | 47 | DynamicLibrary 48 | true 49 | v141 50 | MultiByte 51 | 52 | 53 | DynamicLibrary 54 | false 55 | v141 56 | true 57 | MultiByte 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | false 75 | $(SolutionDir)include;$(SolutionDir)minhook\include;$(IncludePath) 76 | 77 | 78 | true 79 | $(SolutionDir)include;$(SolutionDir)minhook\include;$(IncludePath) 80 | 81 | 82 | 83 | NotUsing 84 | Level3 85 | MaxSpeed 86 | true 87 | true 88 | true 89 | WIN32;NDEBUG;DSOUND_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 90 | true 91 | 92 | 93 | Windows 94 | true 95 | true 96 | true 97 | dxguid.lib;iphlpapi.lib;ws2_32.lib;%(AdditionalDependencies) 98 | $(ProjectDir)$(MSBuildProjectName).def 99 | 100 | 101 | 102 | 103 | 104 | NotUsing 105 | Level3 106 | Disabled 107 | true 108 | WIN32;_DEBUG;DSOUND_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 109 | true 110 | 111 | 112 | Windows 113 | true 114 | dxguid.lib;iphlpapi.lib;ws2_32.lib;%(AdditionalDependencies) 115 | $(ProjectDir)$(MSBuildProjectName).def 116 | 117 | 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /hookdll/dsound/dsound.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | 23 | 24 | Source Files 25 | 26 | 27 | Source Files 28 | 29 | 30 | -------------------------------------------------------------------------------- /hookdll/hookdll.cpp: -------------------------------------------------------------------------------- 1 | /* DirectPlay Lite 2 | * Copyright (C) 2018 Daniel Collins 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "../src/DirectPlay8Address.hpp" 26 | #include "../src/DirectPlay8Peer.hpp" 27 | #include "../src/Factory.hpp" 28 | #include "../src/Log.hpp" 29 | 30 | static HMODULE dll_handle = NULL; 31 | static unsigned int coinit_depth = 0; 32 | 33 | static DWORD DirectPlay8Address_cookie; 34 | static DWORD DirectPlay8Peer_cookie; 35 | 36 | static HRESULT (__stdcall *real_CoInitialize)(LPVOID) = NULL; 37 | static HRESULT (__stdcall *real_CoInitializeEx)(LPVOID, DWORD) = NULL; 38 | static void (__stdcall *real_CoUninitialize)() = NULL; 39 | 40 | static HRESULT __stdcall hook_CoInitialize(LPVOID pvReserved); 41 | static HRESULT __stdcall hook_CoInitializeEx(LPVOID pvReserved, DWORD dwCoInit); 42 | static void __stdcall hook_CoUninitialize(); 43 | 44 | template void register_class(const char *CLASS_NAME, DWORD *cookie); 45 | 46 | extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 47 | { 48 | if(fdwReason == DLL_PROCESS_ATTACH) 49 | { 50 | if(MH_Initialize() != MH_OK) 51 | { 52 | log_printf("Unable to initialise MinHook"); 53 | return FALSE; 54 | } 55 | 56 | if(MH_CreateHook(&CoInitialize, &hook_CoInitialize, (LPVOID*)(&real_CoInitialize)) != MH_OK 57 | || MH_EnableHook(&CoInitialize) != MH_OK 58 | || MH_CreateHook(&CoInitializeEx, &hook_CoInitializeEx, (LPVOID*)(&real_CoInitializeEx)) != MH_OK 59 | || MH_EnableHook(&CoInitializeEx) != MH_OK 60 | || MH_CreateHook(&CoUninitialize, &hook_CoUninitialize, (LPVOID*)(&real_CoUninitialize)) != MH_OK 61 | || MH_EnableHook(&CoUninitialize) != MH_OK) 62 | { 63 | log_printf("Unable to hook COM initialisation functions"); 64 | abort(); 65 | } 66 | } 67 | else if(fdwReason == DLL_PROCESS_DETACH && lpvReserved == NULL) 68 | { 69 | if(MH_RemoveHook(&CoUninitialize) != MH_OK 70 | || MH_RemoveHook(&CoInitializeEx) != MH_OK 71 | || MH_RemoveHook(&CoInitialize) != MH_OK 72 | || MH_Uninitialize() != MH_OK) 73 | { 74 | log_printf("Unable to un-hook COM initialisation functions"); 75 | abort(); 76 | } 77 | 78 | log_fini(); 79 | } 80 | 81 | return TRUE; 82 | } 83 | 84 | extern "C" void* __stdcall find_sym(const char *dll_name, const char *sym_name) 85 | { 86 | if(dll_handle == NULL) 87 | { 88 | char path[512]; 89 | GetSystemDirectory(path, sizeof(path)); 90 | 91 | if(strlen(path) + strlen(dll_name) + 2 > sizeof(path)) 92 | { 93 | abort(); 94 | } 95 | 96 | strcat(path, "\\"); 97 | strcat(path, dll_name); 98 | 99 | dll_handle = LoadLibrary(path); 100 | if(dll_handle == NULL) 101 | { 102 | DWORD err = GetLastError(); 103 | log_printf("Unable to load %s: %s", path, win_strerror(err).c_str()); 104 | abort(); 105 | } 106 | } 107 | 108 | void *sym_addr = GetProcAddress(dll_handle, sym_name); 109 | if(sym_addr == NULL) 110 | { 111 | DWORD err = GetLastError(); 112 | log_printf("Unable to get address of %s in %s: %s", sym_name, dll_name, win_strerror(err).c_str()); 113 | abort(); 114 | } 115 | 116 | return sym_addr; 117 | } 118 | 119 | static HRESULT __stdcall hook_CoInitialize(LPVOID pvReserved) 120 | { 121 | HRESULT res = real_CoInitialize(pvReserved); 122 | if((res == S_OK || res == S_FALSE) && ++coinit_depth == 1) 123 | { 124 | /* Register COM classes. */ 125 | 126 | register_class("DirectPlay8Address", &DirectPlay8Address_cookie); 127 | register_class ("DirectPlay8Peer", &DirectPlay8Peer_cookie); 128 | } 129 | 130 | return res; 131 | } 132 | 133 | static HRESULT __stdcall hook_CoInitializeEx(LPVOID pvReserved, DWORD dwCoInit) 134 | { 135 | HRESULT res = real_CoInitializeEx(pvReserved, dwCoInit); 136 | if((res == S_OK || res == S_FALSE) && ++coinit_depth == 1) 137 | { 138 | /* Register COM classes. */ 139 | 140 | register_class("DirectPlay8Address", &DirectPlay8Address_cookie); 141 | register_class ("DirectPlay8Peer", &DirectPlay8Peer_cookie); 142 | } 143 | 144 | return res; 145 | } 146 | 147 | static void __stdcall hook_CoUninitialize() 148 | { 149 | if(--coinit_depth == 0) 150 | { 151 | /* Unregister COM classes. */ 152 | 153 | CoRevokeClassObject(DirectPlay8Peer_cookie); 154 | CoRevokeClassObject(DirectPlay8Address_cookie); 155 | } 156 | 157 | real_CoUninitialize(); 158 | } 159 | 160 | template void register_class(const char *CLASS_NAME, DWORD *cookie) 161 | { 162 | IClassFactory *factory = new Factory(NULL); 163 | 164 | HRESULT result = CoRegisterClassObject(CLASS_ID, factory, CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, cookie); 165 | if(result != S_OK) 166 | { 167 | log_printf("Unable to register COM class object for %s (result = %08x)", CLASS_NAME, (unsigned)(result)); 168 | abort(); 169 | } 170 | 171 | /* CoRegisterClassObject() calls AddRef(), release our reference to the factory. */ 172 | factory->Release(); 173 | } 174 | -------------------------------------------------------------------------------- /minhook/AUTHORS.txt: -------------------------------------------------------------------------------- 1 | Tsuda Kageyu 2 | Creator, maintainer 3 | 4 | Michael Maltsev 5 | Added "Queue" functions. A lot of bug fixes. 6 | 7 | Andrey Unis 8 | Rewrote the hook engine in plain C. 9 | -------------------------------------------------------------------------------- /minhook/LICENSE.txt: -------------------------------------------------------------------------------- 1 | MinHook - The Minimalistic API Hooking Library for x64/x86 2 | Copyright (C) 2009-2017 Tsuda Kageyu. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions 7 | are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | 2. Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 18 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 19 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | 27 | ================================================================================ 28 | Portions of this software are Copyright (c) 2008-2009, Vyacheslav Patkov. 29 | ================================================================================ 30 | Hacker Disassembler Engine 32 C 31 | Copyright (c) 2008-2009, Vyacheslav Patkov. 32 | All rights reserved. 33 | 34 | Redistribution and use in source and binary forms, with or without 35 | modification, are permitted provided that the following conditions 36 | are met: 37 | 38 | 1. Redistributions of source code must retain the above copyright 39 | notice, this list of conditions and the following disclaimer. 40 | 2. Redistributions in binary form must reproduce the above copyright 41 | notice, this list of conditions and the following disclaimer in the 42 | documentation and/or other materials provided with the distribution. 43 | 44 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 45 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 46 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 47 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR 48 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 49 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 50 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 51 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 52 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 53 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 54 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 55 | 56 | ------------------------------------------------------------------------------- 57 | Hacker Disassembler Engine 64 C 58 | Copyright (c) 2008-2009, Vyacheslav Patkov. 59 | All rights reserved. 60 | 61 | Redistribution and use in source and binary forms, with or without 62 | modification, are permitted provided that the following conditions 63 | are met: 64 | 65 | 1. Redistributions of source code must retain the above copyright 66 | notice, this list of conditions and the following disclaimer. 67 | 2. Redistributions in binary form must reproduce the above copyright 68 | notice, this list of conditions and the following disclaimer in the 69 | documentation and/or other materials provided with the distribution. 70 | 71 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 72 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 73 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 74 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR 75 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 76 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 77 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 78 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 79 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 80 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 81 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 82 | -------------------------------------------------------------------------------- /minhook/minhook.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 15.0 32 | {8F39F2E4-0EF8-40F7-AD96-F76F2F200B3F} 33 | Win32Proj 34 | minhook 35 | 10.0.17763.0 36 | 37 | 38 | 39 | StaticLibrary 40 | true 41 | v141 42 | Unicode 43 | 44 | 45 | StaticLibrary 46 | false 47 | v141 48 | true 49 | Unicode 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | true 67 | 68 | 69 | false 70 | 71 | 72 | 73 | NotUsing 74 | Level3 75 | Disabled 76 | true 77 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) 78 | true 79 | 80 | 81 | Windows 82 | true 83 | 84 | 85 | 86 | 87 | NotUsing 88 | Level3 89 | MaxSpeed 90 | true 91 | true 92 | true 93 | WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) 94 | true 95 | 96 | 97 | Windows 98 | true 99 | true 100 | true 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /minhook/minhook.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | 35 | 36 | Header Files 37 | 38 | 39 | Header Files 40 | 41 | 42 | Header Files 43 | 44 | 45 | Header Files 46 | 47 | 48 | Header Files 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | Header Files 58 | 59 | 60 | -------------------------------------------------------------------------------- /minhook/src/buffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MinHook - The Minimalistic API Hooking Library for x64/x86 3 | * Copyright (C) 2009-2017 Tsuda Kageyu. 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 20 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #pragma once 30 | 31 | // Size of each memory slot. 32 | #if defined(_M_X64) || defined(__x86_64__) 33 | #define MEMORY_SLOT_SIZE 64 34 | #else 35 | #define MEMORY_SLOT_SIZE 32 36 | #endif 37 | 38 | VOID InitializeBuffer(VOID); 39 | VOID UninitializeBuffer(VOID); 40 | LPVOID AllocateBuffer(LPVOID pOrigin); 41 | VOID FreeBuffer(LPVOID pBuffer); 42 | BOOL IsExecutableAddress(LPVOID pAddress); 43 | -------------------------------------------------------------------------------- /minhook/src/hde/hde32.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 32 3 | * Copyright (c) 2006-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | * hde32.h: C/C++ header file 7 | * 8 | */ 9 | 10 | #ifndef _HDE32_H_ 11 | #define _HDE32_H_ 12 | 13 | /* stdint.h - C99 standard header 14 | * http://en.wikipedia.org/wiki/stdint.h 15 | * 16 | * if your compiler doesn't contain "stdint.h" header (for 17 | * example, Microsoft Visual C++), you can download file: 18 | * http://www.azillionmonkeys.com/qed/pstdint.h 19 | * and change next line to: 20 | * #include "pstdint.h" 21 | */ 22 | #include "pstdint.h" 23 | 24 | #define F_MODRM 0x00000001 25 | #define F_SIB 0x00000002 26 | #define F_IMM8 0x00000004 27 | #define F_IMM16 0x00000008 28 | #define F_IMM32 0x00000010 29 | #define F_DISP8 0x00000020 30 | #define F_DISP16 0x00000040 31 | #define F_DISP32 0x00000080 32 | #define F_RELATIVE 0x00000100 33 | #define F_2IMM16 0x00000800 34 | #define F_ERROR 0x00001000 35 | #define F_ERROR_OPCODE 0x00002000 36 | #define F_ERROR_LENGTH 0x00004000 37 | #define F_ERROR_LOCK 0x00008000 38 | #define F_ERROR_OPERAND 0x00010000 39 | #define F_PREFIX_REPNZ 0x01000000 40 | #define F_PREFIX_REPX 0x02000000 41 | #define F_PREFIX_REP 0x03000000 42 | #define F_PREFIX_66 0x04000000 43 | #define F_PREFIX_67 0x08000000 44 | #define F_PREFIX_LOCK 0x10000000 45 | #define F_PREFIX_SEG 0x20000000 46 | #define F_PREFIX_ANY 0x3f000000 47 | 48 | #define PREFIX_SEGMENT_CS 0x2e 49 | #define PREFIX_SEGMENT_SS 0x36 50 | #define PREFIX_SEGMENT_DS 0x3e 51 | #define PREFIX_SEGMENT_ES 0x26 52 | #define PREFIX_SEGMENT_FS 0x64 53 | #define PREFIX_SEGMENT_GS 0x65 54 | #define PREFIX_LOCK 0xf0 55 | #define PREFIX_REPNZ 0xf2 56 | #define PREFIX_REPX 0xf3 57 | #define PREFIX_OPERAND_SIZE 0x66 58 | #define PREFIX_ADDRESS_SIZE 0x67 59 | 60 | #pragma pack(push,1) 61 | 62 | typedef struct { 63 | uint8_t len; 64 | uint8_t p_rep; 65 | uint8_t p_lock; 66 | uint8_t p_seg; 67 | uint8_t p_66; 68 | uint8_t p_67; 69 | uint8_t opcode; 70 | uint8_t opcode2; 71 | uint8_t modrm; 72 | uint8_t modrm_mod; 73 | uint8_t modrm_reg; 74 | uint8_t modrm_rm; 75 | uint8_t sib; 76 | uint8_t sib_scale; 77 | uint8_t sib_index; 78 | uint8_t sib_base; 79 | union { 80 | uint8_t imm8; 81 | uint16_t imm16; 82 | uint32_t imm32; 83 | } imm; 84 | union { 85 | uint8_t disp8; 86 | uint16_t disp16; 87 | uint32_t disp32; 88 | } disp; 89 | uint32_t flags; 90 | } hde32s; 91 | 92 | #pragma pack(pop) 93 | 94 | #ifdef __cplusplus 95 | extern "C" { 96 | #endif 97 | 98 | /* __cdecl */ 99 | unsigned int hde32_disasm(const void *code, hde32s *hs); 100 | 101 | #ifdef __cplusplus 102 | } 103 | #endif 104 | 105 | #endif /* _HDE32_H_ */ 106 | -------------------------------------------------------------------------------- /minhook/src/hde/hde64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 64 3 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | * hde64.h: C/C++ header file 7 | * 8 | */ 9 | 10 | #ifndef _HDE64_H_ 11 | #define _HDE64_H_ 12 | 13 | /* stdint.h - C99 standard header 14 | * http://en.wikipedia.org/wiki/stdint.h 15 | * 16 | * if your compiler doesn't contain "stdint.h" header (for 17 | * example, Microsoft Visual C++), you can download file: 18 | * http://www.azillionmonkeys.com/qed/pstdint.h 19 | * and change next line to: 20 | * #include "pstdint.h" 21 | */ 22 | #include "pstdint.h" 23 | 24 | #define F_MODRM 0x00000001 25 | #define F_SIB 0x00000002 26 | #define F_IMM8 0x00000004 27 | #define F_IMM16 0x00000008 28 | #define F_IMM32 0x00000010 29 | #define F_IMM64 0x00000020 30 | #define F_DISP8 0x00000040 31 | #define F_DISP16 0x00000080 32 | #define F_DISP32 0x00000100 33 | #define F_RELATIVE 0x00000200 34 | #define F_ERROR 0x00001000 35 | #define F_ERROR_OPCODE 0x00002000 36 | #define F_ERROR_LENGTH 0x00004000 37 | #define F_ERROR_LOCK 0x00008000 38 | #define F_ERROR_OPERAND 0x00010000 39 | #define F_PREFIX_REPNZ 0x01000000 40 | #define F_PREFIX_REPX 0x02000000 41 | #define F_PREFIX_REP 0x03000000 42 | #define F_PREFIX_66 0x04000000 43 | #define F_PREFIX_67 0x08000000 44 | #define F_PREFIX_LOCK 0x10000000 45 | #define F_PREFIX_SEG 0x20000000 46 | #define F_PREFIX_REX 0x40000000 47 | #define F_PREFIX_ANY 0x7f000000 48 | 49 | #define PREFIX_SEGMENT_CS 0x2e 50 | #define PREFIX_SEGMENT_SS 0x36 51 | #define PREFIX_SEGMENT_DS 0x3e 52 | #define PREFIX_SEGMENT_ES 0x26 53 | #define PREFIX_SEGMENT_FS 0x64 54 | #define PREFIX_SEGMENT_GS 0x65 55 | #define PREFIX_LOCK 0xf0 56 | #define PREFIX_REPNZ 0xf2 57 | #define PREFIX_REPX 0xf3 58 | #define PREFIX_OPERAND_SIZE 0x66 59 | #define PREFIX_ADDRESS_SIZE 0x67 60 | 61 | #pragma pack(push,1) 62 | 63 | typedef struct { 64 | uint8_t len; 65 | uint8_t p_rep; 66 | uint8_t p_lock; 67 | uint8_t p_seg; 68 | uint8_t p_66; 69 | uint8_t p_67; 70 | uint8_t rex; 71 | uint8_t rex_w; 72 | uint8_t rex_r; 73 | uint8_t rex_x; 74 | uint8_t rex_b; 75 | uint8_t opcode; 76 | uint8_t opcode2; 77 | uint8_t modrm; 78 | uint8_t modrm_mod; 79 | uint8_t modrm_reg; 80 | uint8_t modrm_rm; 81 | uint8_t sib; 82 | uint8_t sib_scale; 83 | uint8_t sib_index; 84 | uint8_t sib_base; 85 | union { 86 | uint8_t imm8; 87 | uint16_t imm16; 88 | uint32_t imm32; 89 | uint64_t imm64; 90 | } imm; 91 | union { 92 | uint8_t disp8; 93 | uint16_t disp16; 94 | uint32_t disp32; 95 | } disp; 96 | uint32_t flags; 97 | } hde64s; 98 | 99 | #pragma pack(pop) 100 | 101 | #ifdef __cplusplus 102 | extern "C" { 103 | #endif 104 | 105 | /* __cdecl */ 106 | unsigned int hde64_disasm(const void *code, hde64s *hs); 107 | 108 | #ifdef __cplusplus 109 | } 110 | #endif 111 | 112 | #endif /* _HDE64_H_ */ 113 | -------------------------------------------------------------------------------- /minhook/src/hde/pstdint.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MinHook - The Minimalistic API Hooking Library for x64/x86 3 | * Copyright (C) 2009-2017 Tsuda Kageyu. All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #pragma once 28 | 29 | #include 30 | 31 | // Integer types for HDE. 32 | typedef INT8 int8_t; 33 | typedef INT16 int16_t; 34 | typedef INT32 int32_t; 35 | typedef INT64 int64_t; 36 | typedef UINT8 uint8_t; 37 | typedef UINT16 uint16_t; 38 | typedef UINT32 uint32_t; 39 | typedef UINT64 uint64_t; 40 | -------------------------------------------------------------------------------- /minhook/src/hde/table32.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 32 C 3 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | */ 7 | 8 | #define C_NONE 0x00 9 | #define C_MODRM 0x01 10 | #define C_IMM8 0x02 11 | #define C_IMM16 0x04 12 | #define C_IMM_P66 0x10 13 | #define C_REL8 0x20 14 | #define C_REL32 0x40 15 | #define C_GROUP 0x80 16 | #define C_ERROR 0xff 17 | 18 | #define PRE_ANY 0x00 19 | #define PRE_NONE 0x01 20 | #define PRE_F2 0x02 21 | #define PRE_F3 0x04 22 | #define PRE_66 0x08 23 | #define PRE_67 0x10 24 | #define PRE_LOCK 0x20 25 | #define PRE_SEG 0x40 26 | #define PRE_ALL 0xff 27 | 28 | #define DELTA_OPCODES 0x4a 29 | #define DELTA_FPU_REG 0xf1 30 | #define DELTA_FPU_MODRM 0xf8 31 | #define DELTA_PREFIXES 0x130 32 | #define DELTA_OP_LOCK_OK 0x1a1 33 | #define DELTA_OP2_LOCK_OK 0x1b9 34 | #define DELTA_OP_ONLY_MEM 0x1cb 35 | #define DELTA_OP2_ONLY_MEM 0x1da 36 | 37 | unsigned char hde32_table[] = { 38 | 0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3, 39 | 0xa8,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xac,0xaa,0xb2,0xaa,0x9f,0x9f, 40 | 0x9f,0x9f,0xb5,0xa3,0xa3,0xa4,0xaa,0xaa,0xba,0xaa,0x96,0xaa,0xa8,0xaa,0xc3, 41 | 0xc3,0x96,0x96,0xb7,0xae,0xd6,0xbd,0xa3,0xc5,0xa3,0xa3,0x9f,0xc3,0x9c,0xaa, 42 | 0xaa,0xac,0xaa,0xbf,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0x90, 43 | 0x82,0x7d,0x97,0x59,0x59,0x59,0x59,0x59,0x7f,0x59,0x59,0x60,0x7d,0x7f,0x7f, 44 | 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x9a,0x88,0x7d, 45 | 0x59,0x50,0x50,0x50,0x50,0x59,0x59,0x59,0x59,0x61,0x94,0x61,0x9e,0x59,0x59, 46 | 0x85,0x59,0x92,0xa3,0x60,0x60,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59, 47 | 0x59,0x59,0x9f,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xcc,0x01,0xbc,0x03,0xf0, 48 | 0x10,0x10,0x10,0x10,0x50,0x50,0x50,0x50,0x14,0x20,0x20,0x20,0x20,0x01,0x01, 49 | 0x01,0x01,0xc4,0x02,0x10,0x00,0x00,0x00,0x00,0x01,0x01,0xc0,0xc2,0x10,0x11, 50 | 0x02,0x03,0x11,0x03,0x03,0x04,0x00,0x00,0x14,0x00,0x02,0x00,0x00,0xc6,0xc8, 51 | 0x02,0x02,0x02,0x02,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0xca, 52 | 0x01,0x01,0x01,0x00,0x06,0x00,0x04,0x00,0xc0,0xc2,0x01,0x01,0x03,0x01,0xff, 53 | 0xff,0x01,0x00,0x03,0xc4,0xc4,0xc6,0x03,0x01,0x01,0x01,0xff,0x03,0x03,0x03, 54 | 0xc8,0x40,0x00,0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00, 55 | 0x00,0x00,0x00,0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00, 56 | 0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 57 | 0x00,0xff,0xff,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 58 | 0x7f,0x00,0x00,0xff,0x4a,0x4a,0x4a,0x4a,0x4b,0x52,0x4a,0x4a,0x4a,0x4a,0x4f, 59 | 0x4c,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x55,0x45,0x40,0x4a,0x4a,0x4a, 60 | 0x45,0x59,0x4d,0x46,0x4a,0x5d,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a, 61 | 0x4a,0x4a,0x4a,0x4a,0x4a,0x61,0x63,0x67,0x4e,0x4a,0x4a,0x6b,0x6d,0x4a,0x4a, 62 | 0x45,0x6d,0x4a,0x4a,0x44,0x45,0x4a,0x4a,0x00,0x00,0x00,0x02,0x0d,0x06,0x06, 63 | 0x06,0x06,0x0e,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x00,0x06,0x06,0x02,0x06, 64 | 0x00,0x0a,0x0a,0x07,0x07,0x06,0x02,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04, 65 | 0x04,0x04,0x00,0x00,0x00,0x0e,0x05,0x06,0x06,0x06,0x01,0x06,0x00,0x00,0x08, 66 | 0x00,0x10,0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01, 67 | 0x86,0x00,0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba, 68 | 0xf8,0xbb,0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00, 69 | 0xc4,0xff,0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00, 70 | 0x13,0x09,0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07, 71 | 0xb2,0xff,0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf, 72 | 0xe7,0x08,0x00,0xf0,0x02,0x00 73 | }; 74 | -------------------------------------------------------------------------------- /minhook/src/hde/table64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 64 C 3 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | */ 7 | 8 | #define C_NONE 0x00 9 | #define C_MODRM 0x01 10 | #define C_IMM8 0x02 11 | #define C_IMM16 0x04 12 | #define C_IMM_P66 0x10 13 | #define C_REL8 0x20 14 | #define C_REL32 0x40 15 | #define C_GROUP 0x80 16 | #define C_ERROR 0xff 17 | 18 | #define PRE_ANY 0x00 19 | #define PRE_NONE 0x01 20 | #define PRE_F2 0x02 21 | #define PRE_F3 0x04 22 | #define PRE_66 0x08 23 | #define PRE_67 0x10 24 | #define PRE_LOCK 0x20 25 | #define PRE_SEG 0x40 26 | #define PRE_ALL 0xff 27 | 28 | #define DELTA_OPCODES 0x4a 29 | #define DELTA_FPU_REG 0xfd 30 | #define DELTA_FPU_MODRM 0x104 31 | #define DELTA_PREFIXES 0x13c 32 | #define DELTA_OP_LOCK_OK 0x1ae 33 | #define DELTA_OP2_LOCK_OK 0x1c6 34 | #define DELTA_OP_ONLY_MEM 0x1d8 35 | #define DELTA_OP2_ONLY_MEM 0x1e7 36 | 37 | unsigned char hde64_table[] = { 38 | 0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5, 39 | 0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1, 40 | 0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea, 41 | 0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0, 42 | 0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab, 43 | 0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92, 44 | 0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90, 45 | 0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b, 46 | 0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b, 47 | 0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc, 48 | 0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20, 49 | 0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff, 50 | 0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00, 51 | 0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01, 52 | 0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10, 53 | 0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00, 54 | 0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00, 55 | 0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00, 56 | 0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00, 57 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff, 58 | 0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00, 59 | 0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40, 60 | 0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43, 61 | 0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, 62 | 0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40, 63 | 0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06, 64 | 0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07, 65 | 0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04, 66 | 0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10, 67 | 0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00, 68 | 0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb, 69 | 0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff, 70 | 0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09, 71 | 0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff, 72 | 0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08, 73 | 0x00,0xf0,0x02,0x00 74 | }; 75 | -------------------------------------------------------------------------------- /minhook/src/trampoline.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MinHook - The Minimalistic API Hooking Library for x64/x86 3 | * Copyright (C) 2009-2017 Tsuda Kageyu. 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 20 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #pragma once 30 | 31 | #pragma pack(push, 1) 32 | 33 | // Structs for writing x86/x64 instructions. 34 | 35 | // 8-bit relative jump. 36 | typedef struct _JMP_REL_SHORT 37 | { 38 | UINT8 opcode; // EB xx: JMP +2+xx 39 | UINT8 operand; 40 | } JMP_REL_SHORT, *PJMP_REL_SHORT; 41 | 42 | // 32-bit direct relative jump/call. 43 | typedef struct _JMP_REL 44 | { 45 | UINT8 opcode; // E9/E8 xxxxxxxx: JMP/CALL +5+xxxxxxxx 46 | UINT32 operand; // Relative destination address 47 | } JMP_REL, *PJMP_REL, CALL_REL; 48 | 49 | // 64-bit indirect absolute jump. 50 | typedef struct _JMP_ABS 51 | { 52 | UINT8 opcode0; // FF25 00000000: JMP [+6] 53 | UINT8 opcode1; 54 | UINT32 dummy; 55 | UINT64 address; // Absolute destination address 56 | } JMP_ABS, *PJMP_ABS; 57 | 58 | // 64-bit indirect absolute call. 59 | typedef struct _CALL_ABS 60 | { 61 | UINT8 opcode0; // FF15 00000002: CALL [+6] 62 | UINT8 opcode1; 63 | UINT32 dummy0; 64 | UINT8 dummy1; // EB 08: JMP +10 65 | UINT8 dummy2; 66 | UINT64 address; // Absolute destination address 67 | } CALL_ABS; 68 | 69 | // 32-bit direct relative conditional jumps. 70 | typedef struct _JCC_REL 71 | { 72 | UINT8 opcode0; // 0F8* xxxxxxxx: J** +6+xxxxxxxx 73 | UINT8 opcode1; 74 | UINT32 operand; // Relative destination address 75 | } JCC_REL; 76 | 77 | // 64bit indirect absolute conditional jumps that x64 lacks. 78 | typedef struct _JCC_ABS 79 | { 80 | UINT8 opcode; // 7* 0E: J** +16 81 | UINT8 dummy0; 82 | UINT8 dummy1; // FF25 00000000: JMP [+6] 83 | UINT8 dummy2; 84 | UINT32 dummy3; 85 | UINT64 address; // Absolute destination address 86 | } JCC_ABS; 87 | 88 | #pragma pack(pop) 89 | 90 | typedef struct _TRAMPOLINE 91 | { 92 | LPVOID pTarget; // [In] Address of the target function. 93 | LPVOID pDetour; // [In] Address of the detour function. 94 | LPVOID pTrampoline; // [In] Buffer address for the trampoline and relay function. 95 | 96 | #if defined(_M_X64) || defined(__x86_64__) 97 | LPVOID pRelay; // [Out] Address of the relay function. 98 | #endif 99 | BOOL patchAbove; // [Out] Should use the hot patch area? 100 | UINT nIP; // [Out] Number of the instruction boundaries. 101 | UINT8 oldIPs[8]; // [Out] Instruction boundaries of the target function. 102 | UINT8 newIPs[8]; // [Out] Instruction boundaries of the trampoline function. 103 | } TRAMPOLINE, *PTRAMPOLINE; 104 | 105 | BOOL CreateTrampolineFunction(PTRAMPOLINE ct); 106 | -------------------------------------------------------------------------------- /mkstubs.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # DirectPlay Lite - Hook DLL stub function generator 3 | # Copyright (C) 2018 Daniel Collins 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License along 16 | # with this program; if not, write to the Free Software Foundation, Inc., 17 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | use strict; 20 | use warnings; 21 | 22 | if((scalar @ARGV) != 1) 23 | { 24 | print STDERR "Usage: $0 < func-names.txt > dll-name.asm\n"; 25 | exit(42); # EX_USAGE 26 | } 27 | 28 | my ($dllname) = @ARGV; 29 | 30 | print <)) 43 | { 44 | $func =~ s/[\r\n]//g; 45 | next if($func eq ""); 46 | 47 | print < 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include 20 | 21 | #include "AsyncHandleAllocator.hpp" 22 | 23 | AsyncHandleAllocator::AsyncHandleAllocator(): 24 | next_enum_id(1), 25 | next_connect_id(1), 26 | next_send_id(1), 27 | next_pinfo_id(1), 28 | next_cgroup_id(1), 29 | next_dgroup_id(1), 30 | next_apgroup_id(1), 31 | next_rpgroup_id(1) {} 32 | 33 | static DPNHANDLE new_XXX(DPNHANDLE *next, DPNHANDLE type) 34 | { 35 | DPNHANDLE handle = (*next)++ | type; 36 | 37 | (*next) &= ~AsyncHandleAllocator::TYPE_MASK; 38 | if((*next) == 0) 39 | { 40 | (*next) = 1; 41 | } 42 | 43 | return handle; 44 | } 45 | 46 | DPNHANDLE AsyncHandleAllocator::new_enum() 47 | { 48 | return new_XXX(&next_enum_id, TYPE_ENUM); 49 | } 50 | 51 | DPNHANDLE AsyncHandleAllocator::new_connect() 52 | { 53 | return new_XXX(&next_connect_id, TYPE_CONNECT); 54 | } 55 | 56 | DPNHANDLE AsyncHandleAllocator::new_send() 57 | { 58 | return new_XXX(&next_send_id, TYPE_SEND); 59 | } 60 | 61 | DPNHANDLE AsyncHandleAllocator::new_pinfo() 62 | { 63 | return new_XXX(&next_pinfo_id, TYPE_PINFO); 64 | } 65 | 66 | DPNHANDLE AsyncHandleAllocator::new_cgroup() 67 | { 68 | return new_XXX(&next_cgroup_id, TYPE_CGROUP); 69 | } 70 | 71 | DPNHANDLE AsyncHandleAllocator::new_dgroup() 72 | { 73 | return new_XXX(&next_dgroup_id, TYPE_DGROUP); 74 | } 75 | 76 | DPNHANDLE AsyncHandleAllocator::new_apgroup() 77 | { 78 | return new_XXX(&next_apgroup_id, TYPE_APGROUP); 79 | } 80 | 81 | DPNHANDLE AsyncHandleAllocator::new_rpgroup() 82 | { 83 | return new_XXX(&next_rpgroup_id, TYPE_RPGROUP); 84 | } 85 | -------------------------------------------------------------------------------- /src/AsyncHandleAllocator.hpp: -------------------------------------------------------------------------------- 1 | /* DirectPlay Lite 2 | * Copyright (C) 2018 Daniel Collins 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef DPLITE_ASYNCHANDLEALLOCATOR_HPP 20 | #define DPLITE_ASYNCHANDLEALLOCATOR_HPP 21 | 22 | #include 23 | 24 | /* There is an instance of this class in each DirectPlay8Peer/etc instance to allocate DPNHANDLEs 25 | * for async operations. 26 | * 27 | * Handles are allocated sequentially, they aren't currently tracked, but I doubt anyone will ever 28 | * have enough running at once to wrap around and conflict. 29 | * 30 | * The handle's type is encoded in the high bits so CancelAsyncOperation() can know where it needs 31 | * to look rather than having to search through each type of async task. 32 | * 33 | * 0x00000000 and 0xFFFFFFFF are both impossible values as they have significance to some parts of 34 | * DirectPlay. 35 | */ 36 | 37 | class AsyncHandleAllocator 38 | { 39 | private: 40 | DPNHANDLE next_enum_id; 41 | DPNHANDLE next_connect_id; 42 | DPNHANDLE next_send_id; 43 | DPNHANDLE next_pinfo_id; 44 | DPNHANDLE next_cgroup_id; 45 | DPNHANDLE next_dgroup_id; 46 | DPNHANDLE next_apgroup_id; 47 | DPNHANDLE next_rpgroup_id; 48 | 49 | public: 50 | static const DPNHANDLE TYPE_MASK = 0xE0000000; 51 | 52 | static const DPNHANDLE TYPE_ENUM = 0x00000000; /* EnumHosts() */ 53 | static const DPNHANDLE TYPE_CONNECT = 0x20000000; /* Connect() */ 54 | static const DPNHANDLE TYPE_SEND = 0x40000000; /* SendTo() */ 55 | static const DPNHANDLE TYPE_PINFO = 0x60000000; /* SetPeerInfo() */ 56 | static const DPNHANDLE TYPE_CGROUP = 0x80000000; /* CreateGroup() */ 57 | static const DPNHANDLE TYPE_DGROUP = 0xA0000000; /* DestroyGroup() */ 58 | static const DPNHANDLE TYPE_APGROUP = 0xC0000000; /* AddPlayerToGroup() */ 59 | static const DPNHANDLE TYPE_RPGROUP = 0xE0000000; /* RemovePlayerFromGroup() */ 60 | 61 | AsyncHandleAllocator(); 62 | 63 | DPNHANDLE new_enum(); 64 | DPNHANDLE new_connect(); 65 | DPNHANDLE new_send(); 66 | DPNHANDLE new_pinfo(); 67 | DPNHANDLE new_cgroup(); 68 | DPNHANDLE new_dgroup(); 69 | DPNHANDLE new_apgroup(); 70 | DPNHANDLE new_rpgroup(); 71 | }; 72 | 73 | #endif /* !DPLITE_ASYNCHANDLEALLOCATOR_HPP */ 74 | -------------------------------------------------------------------------------- /src/COMAPIException.cpp: -------------------------------------------------------------------------------- 1 | /* DirectPlay Lite 2 | * Copyright (C) 2018 Daniel Collins 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include 20 | 21 | #include "COMAPIException.hpp" 22 | 23 | COMAPIException::COMAPIException(HRESULT result): 24 | hr(result) 25 | { 26 | snprintf(what_s, sizeof(what_s), "COMAPIException, HRESULT %08X", (unsigned)(result)); 27 | } 28 | 29 | COMAPIException::~COMAPIException() {} 30 | 31 | HRESULT COMAPIException::result() const noexcept 32 | { 33 | return hr; 34 | } 35 | 36 | const char *COMAPIException::what() const noexcept 37 | { 38 | return what_s; 39 | } 40 | -------------------------------------------------------------------------------- /src/COMAPIException.hpp: -------------------------------------------------------------------------------- 1 | /* DirectPlay Lite 2 | * Copyright (C) 2018 Daniel Collins 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef DPLITE_COMAPIEXCEPTION_HPP 20 | #define DPLITE_COMAPIEXCEPTION_HPP 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | class COMAPIException: public std::exception 27 | { 28 | private: 29 | const HRESULT hr; 30 | char what_s[64]; 31 | 32 | public: 33 | COMAPIException(HRESULT result); 34 | virtual ~COMAPIException(); 35 | 36 | HRESULT result() const noexcept; 37 | virtual const char *what() const noexcept; 38 | }; 39 | 40 | #endif /* !DPLITE_COMAPIEXCEPTION_HPP */ 41 | -------------------------------------------------------------------------------- /src/DirectPlay8Address.hpp: -------------------------------------------------------------------------------- 1 | /* DirectPlay Lite 2 | * Copyright (C) 2018 Daniel Collins 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef DPLITE_DIRECTPLAY8ADDRESS_HPP 20 | #define DPLITE_DIRECTPLAY8ADDRESS_HPP 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | class DirectPlay8Address: public IDirectPlay8Address 30 | { 31 | private: 32 | class Component 33 | { 34 | public: 35 | const std::wstring name; 36 | const DWORD type; 37 | 38 | virtual ~Component(); 39 | 40 | virtual Component *clone() = 0; 41 | virtual HRESULT get_component(LPVOID pvBuffer, PDWORD pdwBufferSize, PDWORD pdwDataType) = 0; 42 | 43 | protected: 44 | Component(const std::wstring &name, DWORD type); 45 | }; 46 | 47 | class StringComponentW: public Component 48 | { 49 | public: 50 | const std::wstring value; 51 | 52 | StringComponentW(const std::wstring &name, const wchar_t *lpvData, DWORD dwDataSize); 53 | virtual Component *clone(); 54 | virtual HRESULT get_component(LPVOID pvBuffer, PDWORD pdwBufferSize, PDWORD pdwDataType); 55 | }; 56 | 57 | class DWORDComponent: public Component 58 | { 59 | public: 60 | const DWORD value; 61 | 62 | DWORDComponent(const std::wstring &name, DWORD value); 63 | virtual Component *clone(); 64 | virtual HRESULT get_component(LPVOID pvBuffer, PDWORD pdwBufferSize, PDWORD pdwDataType); 65 | }; 66 | 67 | class GUIDComponent: public Component 68 | { 69 | public: 70 | const GUID value; 71 | 72 | GUIDComponent(const std::wstring &name, GUID value); 73 | virtual Component *clone(); 74 | virtual HRESULT get_component(LPVOID pvBuffer, PDWORD pdwBufferSize, PDWORD pdwDataType); 75 | }; 76 | 77 | std::atomic * const global_refcount; 78 | ULONG local_refcount; 79 | 80 | std::vector components; 81 | std::vector user_data; 82 | 83 | void clear_components(); 84 | void replace_components(const std::vector src); 85 | 86 | public: 87 | DirectPlay8Address(std::atomic *global_refcount); 88 | DirectPlay8Address(const DirectPlay8Address &src); 89 | virtual ~DirectPlay8Address(); 90 | 91 | static DirectPlay8Address *create_host_address(std::atomic *global_refcount, GUID service_provider, const struct sockaddr *sa); 92 | 93 | /* IUnknown */ 94 | virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override; 95 | virtual ULONG STDMETHODCALLTYPE AddRef() override; 96 | virtual ULONG STDMETHODCALLTYPE Release() override; 97 | 98 | /* IDirectPlay8Address */ 99 | virtual HRESULT STDMETHODCALLTYPE BuildFromURLW(WCHAR* pwszSourceURL) override; 100 | virtual HRESULT STDMETHODCALLTYPE BuildFromURLA(CHAR* pszSourceURL) override; 101 | virtual HRESULT STDMETHODCALLTYPE Duplicate(PDIRECTPLAY8ADDRESS* ppdpaNewAddress) override; 102 | virtual HRESULT STDMETHODCALLTYPE SetEqual(PDIRECTPLAY8ADDRESS pdpaAddress) override; 103 | virtual HRESULT STDMETHODCALLTYPE IsEqual(PDIRECTPLAY8ADDRESS pdpaAddress) override; 104 | virtual HRESULT STDMETHODCALLTYPE Clear() override; 105 | virtual HRESULT STDMETHODCALLTYPE GetURLW(WCHAR* pwszURL, PDWORD pdwNumChars) override; 106 | virtual HRESULT STDMETHODCALLTYPE GetURLA(CHAR* pszURL, PDWORD pdwNumChars) override; 107 | virtual HRESULT STDMETHODCALLTYPE GetSP(GUID* pguidSP) override; 108 | virtual HRESULT STDMETHODCALLTYPE GetUserData(LPVOID pvUserData, PDWORD pdwBufferSize) override; 109 | virtual HRESULT STDMETHODCALLTYPE SetSP(CONST GUID* CONST pguidSP) override; 110 | virtual HRESULT STDMETHODCALLTYPE SetUserData(CONST void* CONST pvUserData, CONST DWORD dwDataSize) override; 111 | virtual HRESULT STDMETHODCALLTYPE GetNumComponents(PDWORD pdwNumComponents) override; 112 | virtual HRESULT STDMETHODCALLTYPE GetComponentByName(CONST WCHAR* CONST pwszName, LPVOID pvBuffer, PDWORD pdwBufferSize, PDWORD pdwDataType) override; 113 | virtual HRESULT STDMETHODCALLTYPE GetComponentByIndex(CONST DWORD dwComponentID, WCHAR* pwszName, PDWORD pdwNameLen, void* pvBuffer, PDWORD pdwBufferSize, PDWORD pdwDataType) override; 114 | virtual HRESULT STDMETHODCALLTYPE AddComponent(CONST WCHAR* CONST pwszName, CONST void* CONST lpvData, CONST DWORD dwDataSize, CONST DWORD dwDataType) override; 115 | virtual HRESULT STDMETHODCALLTYPE GetDevice(GUID* pDevGuid) override; 116 | virtual HRESULT STDMETHODCALLTYPE SetDevice(CONST GUID* CONST devGuid) override; 117 | virtual HRESULT STDMETHODCALLTYPE BuildFromDirectPlay4Address(LPVOID pvAddress, DWORD dwDataSize) override; 118 | }; 119 | 120 | #endif /* DPLITE_DIRECTPLAY8ADDRESS_HPP */ 121 | -------------------------------------------------------------------------------- /src/EventObject.cpp: -------------------------------------------------------------------------------- 1 | /* DirectPlay Lite 2 | * Copyright (C) 2018 Daniel Collins 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "EventObject.hpp" 24 | 25 | EventObject::EventObject(BOOL bManualReset, BOOL bInitialState) 26 | { 27 | handle = CreateEvent(NULL, bManualReset, bInitialState, NULL); 28 | if(handle == NULL) 29 | { 30 | throw std::runtime_error("Unable to create event object"); 31 | } 32 | } 33 | 34 | EventObject::~EventObject() 35 | { 36 | CloseHandle(handle); 37 | } 38 | 39 | EventObject::operator HANDLE() const 40 | { 41 | return handle; 42 | } 43 | -------------------------------------------------------------------------------- /src/EventObject.hpp: -------------------------------------------------------------------------------- 1 | /* DirectPlay Lite 2 | * Copyright (C) 2018 Daniel Collins 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef DPLITE_EVENTOBJECT_HPP 20 | #define DPLITE_EVENTOBJECT_HPP 21 | 22 | #include 23 | #include 24 | 25 | class EventObject 26 | { 27 | private: 28 | /* No copy c'tor. */ 29 | EventObject(const EventObject&) = delete; 30 | 31 | HANDLE handle; 32 | 33 | public: 34 | EventObject(BOOL bManualReset = FALSE, BOOL bInitialState = FALSE); 35 | ~EventObject(); 36 | 37 | operator HANDLE() const; 38 | }; 39 | 40 | #endif /* !DPLITE_EVENTOBJECT_HPP */ 41 | -------------------------------------------------------------------------------- /src/Factory.hpp: -------------------------------------------------------------------------------- 1 | /* DirectPlay Lite 2 | * Copyright (C) 2018-2023 Daniel Collins 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef DPLITE_FACTORY_HPP 20 | #define DPLITE_FACTORY_HPP 21 | 22 | #include 23 | #include 24 | 25 | template class Factory: public IClassFactory 26 | { 27 | private: 28 | std::atomic * const global_refcount; 29 | ULONG local_refcount; 30 | 31 | public: 32 | Factory(std::atomic *global_refcount): 33 | global_refcount(global_refcount), 34 | local_refcount(0) 35 | { 36 | AddRef(); 37 | } 38 | 39 | virtual ~Factory() {} 40 | 41 | virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override 42 | { 43 | if(riid == IID_IClassFactory || riid == IID_IUnknown) 44 | { 45 | *((IUnknown**)(ppvObject)) = this; 46 | AddRef(); 47 | 48 | return S_OK; 49 | } 50 | else{ 51 | return E_NOINTERFACE; 52 | } 53 | } 54 | 55 | virtual ULONG STDMETHODCALLTYPE AddRef(void) override 56 | { 57 | if(global_refcount != NULL) 58 | { 59 | ++(*global_refcount); 60 | } 61 | 62 | return ++local_refcount; 63 | } 64 | 65 | virtual ULONG STDMETHODCALLTYPE Release(void) override 66 | { 67 | std::atomic *global_refcount = this->global_refcount; 68 | 69 | ULONG rc = --local_refcount; 70 | if(rc == 0) 71 | { 72 | delete this; 73 | } 74 | 75 | if(global_refcount != NULL) 76 | { 77 | --(*global_refcount); 78 | } 79 | 80 | return rc; 81 | } 82 | 83 | virtual HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter, const IID &riid, void **ppvObject) override 84 | { 85 | if(pUnkOuter != NULL) 86 | { 87 | return CLASS_E_NOAGGREGATION; 88 | } 89 | 90 | if(riid == IMPLEMENTS || riid == IID_IUnknown) 91 | { 92 | *((IUnknown**)(ppvObject)) = new T(global_refcount); 93 | return S_OK; 94 | } 95 | else{ 96 | return E_NOINTERFACE; 97 | } 98 | } 99 | 100 | virtual HRESULT STDMETHODCALLTYPE LockServer(BOOL) override 101 | { 102 | return S_OK; 103 | } 104 | 105 | static HRESULT CreateFactoryInstance(void **ppvObject, std::atomic *global_refcount) 106 | { 107 | try { 108 | *((IUnknown**)(ppvObject)) = new Factory(global_refcount); 109 | return S_OK; 110 | } 111 | catch (const std::bad_alloc&) 112 | { 113 | return E_OUTOFMEMORY; 114 | } 115 | catch (...) 116 | { 117 | return E_UNEXPECTED; 118 | } 119 | } 120 | }; 121 | 122 | typedef HRESULT(*CreateFactoryInstanceFunc)(void**, std::atomic *); 123 | 124 | #endif /* !DPLITE_FACTORY_HPP */ 125 | -------------------------------------------------------------------------------- /src/HandleHandlingPool.hpp: -------------------------------------------------------------------------------- 1 | /* DirectPlay Lite 2 | * Copyright (C) 2018 Daniel Collins 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef DPLITE_HANDLEHANDLINGPOOL_HPP 20 | #define DPLITE_HANDLEHANDLINGPOOL_HPP 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | /* This class maintains a pool of threads to wait on HANDLEs and invoke callback functors when the 34 | * HANDLEs become signalled. 35 | * 36 | * For up to every max_handles_per_pool HANDLEs registered, threads_per_pool worker threads will be 37 | * created to wait on them. Each block of HANDLEs will be assigned to their own pool of threads but 38 | * may move between them when handles are removed. 39 | * 40 | * Handles may be added or removed at any point, although this is not a heavily optimised path and 41 | * will temporarily block all worker threads from waiting on their handles. 42 | * 43 | * Note that the same callback may be invoked in multiple threads concurrently if the linked HANDLE 44 | * is signalled multiple times in quick sucession or is a manual reset event. Ensure your callbacks 45 | * can handle this and do not block, as this will prevent other HANDLEs managed by the same thread 46 | * from being invoked. 47 | */ 48 | 49 | class HandleHandlingPool 50 | { 51 | private: 52 | struct Worker 53 | { 54 | const size_t base_index; 55 | std::thread thread; 56 | 57 | Worker(size_t base_index); 58 | }; 59 | 60 | const size_t threads_per_pool; 61 | const size_t max_handles_per_pool; 62 | 63 | /* spin_workers is a MANUAL RESET event object, we set this to signalled whenever 64 | * we need all the worker threads to exit their WaitForMultipleObjects() calls. 65 | */ 66 | 67 | HANDLE spin_workers; 68 | std::atomic stopping; 69 | 70 | /* Array of handles to wait for, and the callbacks to invoke when they become 71 | * signalled. 72 | * 73 | * These are interlaced with spin_workers every multiple of max_handles_per_pool 74 | * elements, so each thread may pass a range directly into WaitForMultipleObjects() 75 | * and will be woken by WAIT_OBJECT_0 when we signal spin_workers. 76 | * 77 | * Slots in callbacks which correspond to spin_workers have functors which must 78 | * never be called to simplify the implementation. 79 | */ 80 | 81 | std::vector handles; 82 | std::vector< std::function > callbacks; 83 | 84 | /* This shared_mutex protects access to handles/callbacks. 85 | * 86 | * Multiple workers may hold it, and will do so before they start waiting for 87 | * events until they enter a callback method. 88 | * 89 | * One thread may hold it exclusively in order to add or remove a handle, this 90 | * will block any workers from waiting for events. 91 | */ 92 | 93 | std::shared_mutex wait_lock; 94 | 95 | /* pending_writer ensures worker threads cannot starve writers which are trying to 96 | * exclusively take wait_lock. 97 | * 98 | * When a thread wants to take the lock exclusively, they: 99 | * 100 | * 1) Claim pending_writer_lock 101 | * 2) Set pending_writer 102 | * 3) Set spin_workers to signalled 103 | * 4) Exclusively lock wait_lock 104 | * 105 | * Then, any worker threads will do the following: 106 | * 107 | * 4) If currently waiting, return from WaitForMultipleObjects() and then release 108 | * its shared lock on wait_lock. 109 | * 110 | * 5) Check pending_writer, if true, wait on pending_writer_cv for it to be false. 111 | * 112 | * This doesn't really need to be mutex protected, and there is still a possible 113 | * race between the worker releasing pending_writer_lock and re-acquiring 114 | * wait_lock and another thread attempting to lock it exclusively again, but 115 | * then it will just spin around the loop again due to spin_workers. 116 | * 117 | * Once all workers have relinquished wait_lock, the thread which has 118 | * pending_writer_lock will do the following: 119 | * 120 | * 6) Reset spin_workers to non-signalled 121 | * 7) Clear pending_writer 122 | * 8) Release pending_writer_lock 123 | * 124 | * At this point, the writer is free to mess around with the handles, before 125 | * releasing wait_lock and signalling pending_writer_cv. All worker threads will 126 | * now be eligible to wake up and resume operations. 127 | */ 128 | 129 | std::atomic pending_writer; 130 | std::mutex pending_writer_lock; 131 | std::condition_variable pending_writer_cv; 132 | 133 | /* active_workers contains a pointer to the Worker object for each running or 134 | * starting worker thread. 135 | * 136 | * join_worker, if joinable, is a handle to the last worker thread which exited. 137 | * 138 | * Worker threads are responsible for removing themselves from the active_workers 139 | * set when they exit and placing themselves into join_worker. If join_worker is 140 | * already set to a valid thread, the new exiting thread must wait on it. The final 141 | * thread is joined by our destructor. 142 | * 143 | * This ensures that we can only ever have one zombie thread at a time and all 144 | * threads have been joined before our destructor returns. 145 | * 146 | * workers_lock serialises access to active_workers AND join_worker; any thread 147 | * must lock it before performing ANY operation on either. 148 | * 149 | * workers_cv is signalled by worker threads when they exit, after they have placed 150 | * themselves into join_worker and are about to exit. This is used by the destructor 151 | * to wait for zero active_workers. 152 | */ 153 | 154 | std::set active_workers; 155 | std::thread join_worker; 156 | std::mutex workers_lock; 157 | std::condition_variable workers_cv; 158 | 159 | void worker_main(HandleHandlingPool::Worker *w); 160 | void worker_exit(HandleHandlingPool::Worker *w); 161 | 162 | public: 163 | HandleHandlingPool(size_t threads_per_pool, size_t max_handles_per_pool); 164 | ~HandleHandlingPool(); 165 | 166 | void add_handle(HANDLE handle, const std::function &callback); 167 | void remove_handle(HANDLE handle); 168 | }; 169 | 170 | #endif /* !DPLITE_HANDLEHANDLINGPOOL_HPP */ 171 | -------------------------------------------------------------------------------- /src/HostEnumerator.hpp: -------------------------------------------------------------------------------- 1 | /* DirectPlay Lite 2 | * Copyright (C) 2018 Daniel Collins 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef DPLITE_HOSTENUMERATOR_HPP 20 | #define DPLITE_HOSTENUMERATOR_HPP 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "network.hpp" 30 | 31 | #define DEFAULT_ENUM_COUNT 5 32 | #define DEFAULT_ENUM_INTERVAL 1500 33 | #define DEFAULT_ENUM_TIMEOUT 1500 34 | 35 | class HostEnumerator 36 | { 37 | private: 38 | /* No copy c'tor. */ 39 | HostEnumerator(const HostEnumerator&) = delete; 40 | 41 | /* Pointer to the global refcount (if in use), for instantiating DirectPlay8Address objects. */ 42 | std::atomic * const global_refcount; 43 | 44 | /* DirectPlay message handler and context value */ 45 | PFNDPNMESSAGEHANDLER message_handler; 46 | PVOID message_handler_ctx; 47 | 48 | std::function complete_cb; 49 | 50 | GUID service_provider; 51 | struct sockaddr_in send_addr; 52 | 53 | GUID application_guid; /* GUID of application to search for, or GUID_NULL */ 54 | std::vector user_data; /* Data to include in request. */ 55 | 56 | DWORD tx_remain; /* Number of remaining requests to transmit, may be INFINITE. */ 57 | DWORD tx_interval; /* Number of milliseconds to wait between transmits. */ 58 | DWORD rx_timeout; /* Number of milliseconds to wait for replies to a request. */ 59 | 60 | void *user_context; /* DPNMSG_ENUM_HOSTS_REPONSE.pvUserContext */ 61 | 62 | DWORD next_tx_at; 63 | DWORD stop_at; 64 | 65 | int sock; 66 | HANDLE wake_thread; 67 | std::thread *thread; 68 | bool req_cancel; 69 | 70 | unsigned char recv_buf[MAX_PACKET_SIZE]; 71 | 72 | void main(); 73 | void handle_packet(const void *data, size_t size, struct sockaddr_in *from_addr); 74 | 75 | public: 76 | HostEnumerator( 77 | std::atomic * const global_refcount, 78 | 79 | PFNDPNMESSAGEHANDLER message_handler, 80 | PVOID message_handler_ctx, 81 | 82 | PDPN_APPLICATION_DESC const pApplicationDesc, 83 | IDirectPlay8Address *const pdpaddrHost, 84 | IDirectPlay8Address *const pdpaddrDeviceInfo, 85 | PVOID const pvUserEnumData, 86 | const DWORD dwUserEnumDataSize, 87 | const DWORD dwEnumCount, 88 | const DWORD dwRetryInterval, 89 | const DWORD dwTimeOut, 90 | PVOID const pvUserContext, 91 | 92 | std::function complete_cb 93 | ); 94 | 95 | ~HostEnumerator(); 96 | 97 | void cancel(); 98 | void wait(); 99 | }; 100 | 101 | #endif /* !DPLITE_HOSTENUMERATOR_HPP */ 102 | -------------------------------------------------------------------------------- /src/Log.cpp: -------------------------------------------------------------------------------- 1 | /* DirectPlay Lite 2 | * Copyright (C) 2018 Daniel Collins 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "Log.hpp" 27 | 28 | static std::mutex lock; 29 | static bool initialised = false; 30 | static FILE *log_fh = NULL; 31 | static bool trace_enabled = false; 32 | 33 | static void _log_init() 34 | { 35 | if(initialised) 36 | { 37 | return; 38 | } 39 | 40 | const char *log_name = getenv("DPLITE_LOG"); 41 | if(log_name != NULL) 42 | { 43 | log_fh = fopen(log_name, "a"); 44 | if(log_fh != NULL) 45 | { 46 | setbuf(log_fh, NULL); 47 | } 48 | } 49 | 50 | const char *t = getenv("DPLITE_TRACE"); 51 | trace_enabled = (t && atoi(t) != 0); 52 | 53 | initialised = true; 54 | } 55 | 56 | static void _log_fini() 57 | { 58 | initialised = false; 59 | 60 | trace_enabled = false; 61 | 62 | if(log_fh != NULL) 63 | { 64 | fclose(log_fh); 65 | log_fh = NULL; 66 | } 67 | } 68 | 69 | void log_init() 70 | { 71 | std::unique_lock l(lock); 72 | _log_init(); 73 | } 74 | 75 | void log_fini() 76 | { 77 | std::unique_lock l(lock); 78 | _log_fini(); 79 | } 80 | 81 | bool log_trace_enabled() 82 | { 83 | std::unique_lock l(lock); 84 | _log_init(); 85 | 86 | return trace_enabled; 87 | } 88 | 89 | void log_printf(const char *fmt, ...) 90 | { 91 | std::unique_lock l(lock); 92 | _log_init(); 93 | 94 | if(log_fh != NULL) 95 | { 96 | fprintf(log_fh, "[thread=%u time=%u] ", 97 | (unsigned)(GetCurrentThreadId()), (unsigned)(GetTickCount())); 98 | 99 | va_list argv; 100 | va_start(argv, fmt); 101 | vfprintf(log_fh, fmt, argv); 102 | va_end(argv); 103 | 104 | fprintf(log_fh, "\n"); 105 | } 106 | } 107 | 108 | /* Convert a windows error number to an error message */ 109 | std::string win_strerror(DWORD errnum) 110 | { 111 | char buf[256]; 112 | memset(buf, '\0', sizeof(buf)); 113 | 114 | FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errnum, 0, buf, (sizeof(buf) - 1), NULL); 115 | buf[strcspn(buf, "\r\n")] = '\0'; 116 | 117 | return buf; 118 | } 119 | -------------------------------------------------------------------------------- /src/Log.hpp: -------------------------------------------------------------------------------- 1 | /* DirectPlay Lite 2 | * Copyright (C) 2018 Daniel Collins 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef DPLITE_LOG_HPP 20 | #define DPLITE_LOG_HPP 21 | 22 | #include 23 | 24 | void log_init(); 25 | void log_fini(); 26 | bool log_trace_enabled(); 27 | 28 | void log_printf(const char *fmt, ...); 29 | 30 | std::string win_strerror(DWORD errnum); 31 | 32 | #endif /* !DPLITE_LOG_HPP */ 33 | -------------------------------------------------------------------------------- /src/SendQueue.cpp: -------------------------------------------------------------------------------- 1 | /* DirectPlay Lite 2 | * Copyright (C) 2018 Daniel Collins 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "SendQueue.hpp" 24 | 25 | void SendQueue::send(SendPriority priority, const PacketSerialiser &ps, 26 | const struct sockaddr_in *dest_addr, 27 | const std::function&, HRESULT)> &callback) 28 | { 29 | send(priority, ps, dest_addr, 0, callback); 30 | } 31 | 32 | void SendQueue::send(SendPriority priority, const PacketSerialiser &ps, 33 | const struct sockaddr_in *dest_addr, DPNHANDLE async_handle, 34 | const std::function&, HRESULT)> &callback) 35 | { 36 | std::pair data = ps.raw_packet(); 37 | 38 | SendOp *op = new SendOp( 39 | data.first, data.second, 40 | (const struct sockaddr*)(dest_addr), (dest_addr != NULL ? sizeof(*dest_addr) : 0), 41 | async_handle, 42 | callback); 43 | 44 | switch(priority) 45 | { 46 | case SEND_PRI_LOW: 47 | low_queue.push_back(op); 48 | break; 49 | 50 | case SEND_PRI_MEDIUM: 51 | medium_queue.push_back(op); 52 | break; 53 | 54 | case SEND_PRI_HIGH: 55 | high_queue.push_back(op); 56 | break; 57 | } 58 | 59 | SetEvent(signal_on_queue); 60 | } 61 | 62 | SendQueue::SendOp *SendQueue::get_pending() 63 | { 64 | if(current != NULL) 65 | { 66 | return current; 67 | } 68 | 69 | if(!high_queue.empty()) 70 | { 71 | current = high_queue.front(); 72 | high_queue.pop_front(); 73 | } 74 | else if(!medium_queue.empty()) 75 | { 76 | current = medium_queue.front(); 77 | medium_queue.pop_front(); 78 | } 79 | else if(!low_queue.empty()) 80 | { 81 | current = low_queue.front(); 82 | low_queue.pop_front(); 83 | } 84 | 85 | return current; 86 | } 87 | 88 | void SendQueue::pop_pending(SendQueue::SendOp *op) 89 | { 90 | assert(op == current); 91 | current = NULL; 92 | } 93 | 94 | /* NOTE: The remove_queued() family of methods will ONLY return SendOps which 95 | * have a nonzero async_handle. This is for cancelling application-created SendOps 96 | * without also aborting internal ones. 97 | */ 98 | 99 | SendQueue::SendOp *SendQueue::remove_queued() 100 | { 101 | std::list *queues[] = { &high_queue, &medium_queue, &low_queue }; 102 | 103 | for(int i = 0; i < 3; ++i) 104 | { 105 | for(auto it = queues[i]->begin(); it != queues[i]->end(); ++it) 106 | { 107 | SendOp *op = *it; 108 | 109 | if(op->async_handle != 0) 110 | { 111 | queues[i]->erase(it); 112 | return op; 113 | } 114 | } 115 | } 116 | 117 | return NULL; 118 | } 119 | 120 | SendQueue::SendOp *SendQueue::remove_queued_by_handle(DPNHANDLE async_handle) 121 | { 122 | std::list *queues[] = { &low_queue, &medium_queue, &high_queue }; 123 | 124 | for(int i = 0; i < 3; ++i) 125 | { 126 | for(auto it = queues[i]->begin(); it != queues[i]->end(); ++it) 127 | { 128 | SendOp *op = *it; 129 | 130 | if(op->async_handle != 0 && op->async_handle == async_handle) 131 | { 132 | queues[i]->erase(it); 133 | return op; 134 | } 135 | } 136 | } 137 | 138 | return NULL; 139 | } 140 | 141 | SendQueue::SendOp *SendQueue::remove_queued_by_priority(SendPriority priority) 142 | { 143 | std::list *queue; 144 | 145 | switch(priority) 146 | { 147 | case SEND_PRI_LOW: 148 | queue = &low_queue; 149 | break; 150 | 151 | case SEND_PRI_MEDIUM: 152 | queue = &medium_queue; 153 | break; 154 | 155 | case SEND_PRI_HIGH: 156 | queue = &high_queue; 157 | break; 158 | 159 | default: 160 | /* Unreachable. */ 161 | abort(); 162 | } 163 | 164 | for(auto it = queue->begin(); it != queue->end(); ++it) 165 | { 166 | SendOp *op = *it; 167 | 168 | if(op->async_handle != 0) 169 | { 170 | queue->erase(it); 171 | return op; 172 | } 173 | } 174 | 175 | return NULL; 176 | } 177 | 178 | bool SendQueue::handle_is_pending(DPNHANDLE async_handle) 179 | { 180 | return (current != NULL && current->async_handle == async_handle); 181 | } 182 | 183 | SendQueue::SendOp::SendOp(const void *data, size_t data_size, 184 | const struct sockaddr *dest_addr, size_t dest_addr_size, 185 | DPNHANDLE async_handle, 186 | const std::function&, HRESULT)> &callback): 187 | 188 | data((const unsigned char*)(data), (const unsigned char*)(data) + data_size), 189 | sent_data(0), 190 | async_handle(async_handle), 191 | callback(callback) 192 | { 193 | assert((size_t)(dest_addr_size) <= sizeof(this->dest_addr)); 194 | 195 | memcpy(&(this->dest_addr), dest_addr, dest_addr_size); 196 | this->dest_addr_size = dest_addr_size; 197 | } 198 | 199 | std::pair SendQueue::SendOp::get_data() const 200 | { 201 | return std::make_pair(data.data(), data.size()); 202 | } 203 | 204 | std::pair SendQueue::SendOp::get_dest_addr() const 205 | { 206 | return std::make_pair((const struct sockaddr*)(&dest_addr), dest_addr_size); 207 | } 208 | 209 | void SendQueue::SendOp::inc_sent_data(size_t sent) 210 | { 211 | sent_data += sent; 212 | assert(sent_data <= data.size()); 213 | } 214 | 215 | std::pair SendQueue::SendOp::get_pending_data() const 216 | { 217 | return std::make_pair(data.data() + sent_data, data.size() - sent_data); 218 | } 219 | 220 | void SendQueue::SendOp::invoke_callback(std::unique_lock &l, HRESULT result) const 221 | { 222 | callback(l, result); 223 | } 224 | -------------------------------------------------------------------------------- /src/SendQueue.hpp: -------------------------------------------------------------------------------- 1 | /* DirectPlay Lite 2 | * Copyright (C) 2018 Daniel Collins 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef DPLITE_SENDQUEUE_HPP 20 | #define DPLITE_SENDQUEUE_HPP 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "packet.hpp" 35 | 36 | class SendQueue 37 | { 38 | public: 39 | enum SendPriority { 40 | SEND_PRI_LOW = 1, 41 | SEND_PRI_MEDIUM = 2, 42 | SEND_PRI_HIGH = 4, 43 | }; 44 | 45 | class SendOp 46 | { 47 | private: 48 | std::vector data; 49 | size_t sent_data; 50 | 51 | struct sockaddr_storage dest_addr; 52 | size_t dest_addr_size; 53 | 54 | std::function&, HRESULT)> callback; 55 | 56 | public: 57 | const DPNHANDLE async_handle; 58 | 59 | SendOp( 60 | const void *data, size_t data_size, 61 | const struct sockaddr *dest_addr, size_t dest_addr_size, 62 | DPNHANDLE async_handle, 63 | const std::function&, HRESULT)> &callback); 64 | 65 | std::pair get_data() const; 66 | std::pair get_dest_addr() const; 67 | 68 | void inc_sent_data(size_t sent); 69 | std::pair get_pending_data() const; 70 | 71 | void invoke_callback(std::unique_lock &l, HRESULT result) const; 72 | }; 73 | 74 | private: 75 | std::list low_queue; 76 | std::list medium_queue; 77 | std::list high_queue; 78 | 79 | SendOp *current; 80 | 81 | HANDLE signal_on_queue; 82 | 83 | public: 84 | SendQueue(HANDLE signal_on_queue): current(NULL), signal_on_queue(signal_on_queue) {} 85 | 86 | /* No copy c'tor. */ 87 | SendQueue(const SendQueue &src) = delete; 88 | 89 | void send(SendPriority priority, const PacketSerialiser &ps, const struct sockaddr_in *dest_addr, const std::function&, HRESULT)> &callback); 90 | void send(SendPriority priority, const PacketSerialiser &ps, const struct sockaddr_in *dest_addr, DPNHANDLE async_handle, const std::function&, HRESULT)> &callback); 91 | 92 | SendOp *get_pending(); 93 | void pop_pending(SendOp *op); 94 | 95 | SendOp *remove_queued(); 96 | SendOp *remove_queued_by_handle(DPNHANDLE async_handle); 97 | SendOp *remove_queued_by_priority(SendPriority priority); 98 | bool handle_is_pending(DPNHANDLE async_handle); 99 | }; 100 | 101 | #endif /* !DPLITE_SENDQUEUE_HPP */ 102 | -------------------------------------------------------------------------------- /src/dpnet.cpp: -------------------------------------------------------------------------------- 1 | /* DirectPlay Lite 2 | * Copyright (C) 2018-2023 Daniel Collins 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "DirectPlay8Address.hpp" 27 | #include "DirectPlay8Peer.hpp" 28 | #include "Factory.hpp" 29 | 30 | struct DllClass 31 | { 32 | GUID clsid; 33 | const char *desc; 34 | 35 | CreateFactoryInstanceFunc CreateFactoryInstance; 36 | }; 37 | 38 | DllClass DLL_CLASSES[] = { 39 | { CLSID_DirectPlay8Address, "DirectPlay8Address Object", &Factory::CreateFactoryInstance }, 40 | { CLSID_DirectPlay8Peer, "DirectPlay8Peer Object", &Factory::CreateFactoryInstance }, 41 | }; 42 | 43 | size_t NUM_DLL_CLASSES = sizeof(DLL_CLASSES) / sizeof(*DLL_CLASSES); 44 | 45 | /* Sum of refcounts of all created COM objects. */ 46 | static std::atomic global_refcount; 47 | 48 | BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 49 | { 50 | if(fdwReason == DLL_PROCESS_ATTACH) 51 | { 52 | global_refcount = 0; 53 | } 54 | 55 | return TRUE; 56 | } 57 | 58 | HRESULT CALLBACK DllCanUnloadNow() 59 | { 60 | return (global_refcount == 0 ? S_OK : S_FALSE); 61 | } 62 | 63 | HRESULT CALLBACK DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) 64 | { 65 | if(riid != IID_IClassFactory && riid != IID_IUnknown) 66 | { 67 | return CLASS_E_CLASSNOTAVAILABLE; 68 | } 69 | 70 | for (size_t i = 0; i < NUM_DLL_CLASSES; ++i) 71 | { 72 | if (rclsid == DLL_CLASSES[i].clsid) 73 | { 74 | return DLL_CLASSES[i].CreateFactoryInstance(ppv, &global_refcount); 75 | } 76 | } 77 | 78 | return CLASS_E_CLASSNOTAVAILABLE; 79 | } 80 | 81 | HRESULT CALLBACK DllRegisterServer() 82 | { 83 | HRESULT status = S_OK; 84 | 85 | HMODULE this_dll; 86 | if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (TCHAR*)(&DllRegisterServer), &this_dll)) 87 | { 88 | return E_UNEXPECTED; 89 | } 90 | 91 | char this_dll_path[MAX_PATH]; 92 | if (GetModuleFileNameA(this_dll, this_dll_path, sizeof(this_dll_path)) != ERROR_SUCCESS) 93 | { 94 | return E_UNEXPECTED; 95 | } 96 | 97 | for (size_t i = 0; i < NUM_DLL_CLASSES; ++i) 98 | { 99 | OLECHAR *clsid_string; 100 | HRESULT status2 = StringFromCLSID(DLL_CLASSES[i].clsid, &clsid_string); 101 | if (status2 == E_OUTOFMEMORY) 102 | { 103 | status = E_OUTOFMEMORY; 104 | continue; 105 | } 106 | else if (status2 != S_OK) 107 | { 108 | status = SELFREG_E_CLASS; 109 | continue; 110 | } 111 | 112 | char clsid_path[72]; 113 | snprintf(clsid_path, sizeof(clsid_path), "SOFTWARE\\Classes\\CLSID\\%ls", clsid_string); 114 | 115 | HKEY clsid_key; 116 | if (RegCreateKeyExA( 117 | HKEY_LOCAL_MACHINE, 118 | clsid_path, 119 | 0, 120 | NULL, 121 | 0, 122 | KEY_READ | KEY_WRITE, 123 | NULL, 124 | &clsid_key, 125 | NULL) == ERROR_SUCCESS) 126 | { 127 | if (RegSetValueExA(clsid_key, NULL, 0, REG_SZ, (BYTE*)(DLL_CLASSES[i].desc), strlen(DLL_CLASSES[i].desc) + 1) != ERROR_SUCCESS) 128 | { 129 | status = SELFREG_E_CLASS; 130 | } 131 | 132 | HKEY ips32_key; 133 | if (RegCreateKeyExA( 134 | clsid_key, 135 | "InprocServer32", 136 | 0, 137 | NULL, 138 | 0, 139 | KEY_READ | KEY_WRITE, 140 | NULL, 141 | &ips32_key, 142 | NULL) == ERROR_SUCCESS) 143 | { 144 | if (RegSetValueExA(clsid_key, NULL, 0, REG_SZ, (BYTE*)(this_dll_path), strlen(this_dll_path) + 1) != ERROR_SUCCESS) 145 | { 146 | status = SELFREG_E_CLASS; 147 | } 148 | 149 | if (RegSetValueExA(clsid_key, "ThreadingModel", 0, REG_SZ, (BYTE*)("Both"), strlen("Both") + 1) != ERROR_SUCCESS) 150 | { 151 | status = SELFREG_E_CLASS; 152 | } 153 | 154 | RegCloseKey(ips32_key); 155 | } 156 | else { 157 | status = SELFREG_E_CLASS; 158 | } 159 | 160 | RegCloseKey(clsid_key); 161 | } 162 | else { 163 | status = SELFREG_E_CLASS; 164 | } 165 | 166 | CoTaskMemFree(clsid_string); 167 | } 168 | 169 | return status; 170 | } 171 | 172 | HRESULT CALLBACK DllUnregisterServer() 173 | { 174 | HRESULT status = S_OK; 175 | 176 | for (size_t i = 0; i < NUM_DLL_CLASSES; ++i) 177 | { 178 | OLECHAR *clsid_string; 179 | HRESULT status2 = StringFromCLSID(DLL_CLASSES[i].clsid, &clsid_string); 180 | if (status2 == E_OUTOFMEMORY) 181 | { 182 | status = E_OUTOFMEMORY; 183 | continue; 184 | } 185 | else if (status2 != S_OK) 186 | { 187 | status = SELFREG_E_CLASS; 188 | continue; 189 | } 190 | 191 | char clsid_path[72]; 192 | snprintf(clsid_path, sizeof(clsid_path), "SOFTWARE\\Classes\\CLSID\\%ls", clsid_string); 193 | 194 | /* From the DllUnregisterServer() documentation on MSDN: 195 | * 196 | * > The server must not disturb any entries that it did not create which currently exist 197 | * > for its object classes. For example, between registration and unregistration, the user 198 | * > may have specified a Treat As relationship between this class and another. In that 199 | * > case, unregistration can remove all entries except the TreatAs key and any others that 200 | * > were not explicitly created in DllRegisterServer. The registry functions specifically 201 | * > disallow the deletion of an entire populated tree in the registry. The server can 202 | * > attempt, as the last step, to remove the CLSID key, but if other entries still exist, 203 | * > the key will remain. 204 | * 205 | * And that is why we don't check whether RegDeleteKey() succeeds below. 206 | */ 207 | 208 | HKEY clsid_key; 209 | DWORD err = RegOpenKeyExA( 210 | HKEY_LOCAL_MACHINE, 211 | clsid_path, 212 | 0, 213 | KEY_READ | KEY_WRITE, 214 | &clsid_key); 215 | 216 | if (err == ERROR_SUCCESS) 217 | { 218 | err = RegDeleteValueA(clsid_key, NULL); 219 | if (err != ERROR_SUCCESS && err != ERROR_FILE_NOT_FOUND) 220 | { 221 | status = SELFREG_E_CLASS; 222 | } 223 | 224 | HKEY ips32_key; 225 | err = RegOpenKeyExA( 226 | clsid_key, 227 | "InprocServer32", 228 | 0, 229 | KEY_READ | KEY_WRITE, 230 | &ips32_key); 231 | 232 | if (err == ERROR_SUCCESS) 233 | { 234 | err = RegDeleteValueA(ips32_key, NULL); 235 | if (err != ERROR_SUCCESS && err != ERROR_FILE_NOT_FOUND) 236 | { 237 | status = SELFREG_E_CLASS; 238 | } 239 | 240 | err = RegDeleteValueA(ips32_key, "ThreadingModel"); 241 | if (err != ERROR_SUCCESS && err != ERROR_FILE_NOT_FOUND) 242 | { 243 | status = SELFREG_E_CLASS; 244 | } 245 | 246 | RegCloseKey(ips32_key); 247 | RegDeleteKeyA(clsid_key, "InprocServer32"); 248 | } 249 | 250 | RegCloseKey(clsid_key); 251 | RegDeleteKeyA(HKEY_LOCAL_MACHINE, clsid_path); 252 | } 253 | else if (err != ERROR_FILE_NOT_FOUND) 254 | { 255 | status = SELFREG_E_CLASS; 256 | } 257 | 258 | CoTaskMemFree(clsid_string); 259 | } 260 | 261 | return status; 262 | } 263 | -------------------------------------------------------------------------------- /src/dpnet.def: -------------------------------------------------------------------------------- 1 | LIBRARY dpnet.dll 2 | EXPORTS 3 | ; DirectPlay8Create @1 4 | DllCanUnloadNow @2 PRIVATE 5 | DllGetClassObject @3 PRIVATE 6 | DllRegisterServer @4 PRIVATE 7 | DllUnregisterServer @5 PRIVATE 8 | -------------------------------------------------------------------------------- /src/network.cpp: -------------------------------------------------------------------------------- 1 | /* DirectPlay Lite 2 | * Copyright (C) 2018 Daniel Collins 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "network.hpp" 28 | #include "log.hpp" 29 | 30 | int create_udp_socket(uint32_t ipaddr, uint16_t port) 31 | { 32 | int sock = socket(AF_INET, SOCK_DGRAM, 0); 33 | if(sock == -1) 34 | { 35 | return -1; 36 | } 37 | 38 | u_long non_blocking = 1; 39 | if(ioctlsocket(sock, FIONBIO, &non_blocking) != 0) 40 | { 41 | closesocket(sock); 42 | return -1; 43 | } 44 | 45 | BOOL broadcast = TRUE; 46 | if(setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)(&broadcast), sizeof(BOOL)) == -1) 47 | { 48 | closesocket(sock); 49 | return -1; 50 | } 51 | 52 | struct sockaddr_in addr; 53 | addr.sin_family = AF_INET; 54 | addr.sin_addr.s_addr = ipaddr; 55 | addr.sin_port = htons(port); 56 | 57 | if(bind(sock, (struct sockaddr*)(&addr), sizeof(addr)) == -1) 58 | { 59 | closesocket(sock); 60 | return -1; 61 | } 62 | 63 | return sock; 64 | } 65 | 66 | int create_listener_socket(uint32_t ipaddr, uint16_t port) 67 | { 68 | int sock = socket(AF_INET, SOCK_STREAM, 0); 69 | if(sock == -1) 70 | { 71 | return -1; 72 | } 73 | 74 | u_long non_blocking = 1; 75 | if(ioctlsocket(sock, FIONBIO, &non_blocking) != 0) 76 | { 77 | closesocket(sock); 78 | return -1; 79 | } 80 | 81 | BOOL reuse = TRUE; 82 | if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)(&reuse), sizeof(BOOL)) == -1) 83 | { 84 | closesocket(sock); 85 | return -1; 86 | } 87 | 88 | struct sockaddr_in addr; 89 | addr.sin_family = AF_INET; 90 | addr.sin_addr.s_addr = ipaddr; 91 | addr.sin_port = htons(port); 92 | 93 | if(bind(sock, (struct sockaddr*)(&addr), sizeof(addr)) == -1) 94 | { 95 | closesocket(sock); 96 | return -1; 97 | } 98 | 99 | if(listen(sock, LISTEN_QUEUE_SIZE) == -1) 100 | { 101 | closesocket(sock); 102 | return -1; 103 | } 104 | 105 | return sock; 106 | } 107 | 108 | int create_client_socket(uint32_t local_ipaddr, uint16_t local_port) 109 | { 110 | int sock = socket(AF_INET, SOCK_STREAM, 0); 111 | if(sock == -1) 112 | { 113 | return -1; 114 | } 115 | 116 | u_long non_blocking = 1; 117 | if(ioctlsocket(sock, FIONBIO, &non_blocking) != 0) 118 | { 119 | closesocket(sock); 120 | return -1; 121 | } 122 | 123 | BOOL reuse = TRUE; 124 | if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)(&reuse), sizeof(BOOL)) == -1) 125 | { 126 | closesocket(sock); 127 | return -1; 128 | } 129 | 130 | /* Set SO_LINGER so that closesocket() does a hard close, immediately removing the socket 131 | * address from the connection table. 132 | * 133 | * If this isn't done, then we are able to immediately bind() new sockets to the same 134 | * local address (as we may when the port isn't specified), but then outgoing connections 135 | * made from it will fail with WSAEADDRINUSE until the background close completes. 136 | */ 137 | 138 | struct linger no_linger; 139 | no_linger.l_onoff = 1; 140 | no_linger.l_linger = 0; 141 | 142 | if(setsockopt(sock, SOL_SOCKET, SO_LINGER, (char*)(&no_linger), sizeof(no_linger)) == -1) 143 | { 144 | closesocket(sock); 145 | return -1; 146 | } 147 | 148 | struct sockaddr_in l_addr; 149 | l_addr.sin_family = AF_INET; 150 | l_addr.sin_addr.s_addr = local_ipaddr; 151 | l_addr.sin_port = htons(local_port); 152 | 153 | if(bind(sock, (struct sockaddr*)(&l_addr), sizeof(l_addr)) == -1) 154 | { 155 | closesocket(sock); 156 | return -1; 157 | } 158 | 159 | return sock; 160 | } 161 | 162 | int create_discovery_socket() 163 | { 164 | int sock = socket(AF_INET, SOCK_DGRAM, 0); 165 | if(sock == -1) 166 | { 167 | return -1; 168 | } 169 | 170 | u_long non_blocking = 1; 171 | if(ioctlsocket(sock, FIONBIO, &non_blocking) != 0) 172 | { 173 | closesocket(sock); 174 | return -1; 175 | } 176 | 177 | BOOL reuse = TRUE; 178 | if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)(&reuse), sizeof(BOOL)) == -1) 179 | { 180 | closesocket(sock); 181 | return -1; 182 | } 183 | 184 | struct sockaddr_in addr; 185 | addr.sin_family = AF_INET; 186 | addr.sin_addr.s_addr = htonl(INADDR_ANY); 187 | addr.sin_port = htons(DISCOVERY_PORT); 188 | 189 | if(bind(sock, (struct sockaddr*)(&addr), sizeof(addr)) == -1) 190 | { 191 | closesocket(sock); 192 | return -1; 193 | } 194 | 195 | return sock; 196 | } 197 | 198 | std::list get_network_interfaces() 199 | { 200 | std::vector buf; 201 | 202 | while(1) 203 | { 204 | ULONG size = buf.size(); 205 | ULONG err = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, (IP_ADAPTER_ADDRESSES*)(buf.data()), &size); 206 | 207 | if(err == ERROR_SUCCESS) 208 | { 209 | break; 210 | } 211 | else if(err == ERROR_NO_DATA) 212 | { 213 | return std::list(); 214 | } 215 | else if(err == ERROR_BUFFER_OVERFLOW) 216 | { 217 | buf.resize(size); 218 | } 219 | else{ 220 | log_printf("GetAdaptersAddresses: %s", win_strerror(err).c_str()); 221 | return std::list(); 222 | } 223 | } 224 | 225 | std::list interfaces; 226 | 227 | for(IP_ADAPTER_ADDRESSES *ipaa = (IP_ADAPTER_ADDRESSES*)(buf.data()); ipaa != NULL; ipaa = ipaa->Next) 228 | { 229 | if(ipaa->IfType == IF_TYPE_SOFTWARE_LOOPBACK) 230 | { 231 | continue; 232 | } 233 | 234 | SystemNetworkInterface iface; 235 | 236 | iface.friendly_name = ipaa->FriendlyName; 237 | 238 | for(IP_ADAPTER_UNICAST_ADDRESS_LH *uc = ipaa->FirstUnicastAddress; uc != NULL; uc = uc->Next) 239 | { 240 | if(uc->Address.iSockaddrLength > sizeof(struct sockaddr_storage)) 241 | { 242 | log_printf("Ignoring oversize address (family = %u, size = %u)", 243 | (unsigned)(uc->Address.lpSockaddr->sa_family), 244 | (unsigned)(uc->Address.iSockaddrLength)); 245 | continue; 246 | } 247 | 248 | struct sockaddr_storage ss; 249 | memset(&ss, 0, sizeof(ss)); 250 | memcpy(&ss, uc->Address.lpSockaddr, uc->Address.iSockaddrLength); 251 | 252 | iface.unicast_addrs.push_back(ss); 253 | } 254 | 255 | interfaces.push_back(iface); 256 | } 257 | 258 | return interfaces; 259 | } 260 | -------------------------------------------------------------------------------- /src/network.hpp: -------------------------------------------------------------------------------- 1 | /* DirectPlay Lite 2 | * Copyright (C) 2018 Daniel Collins 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef DPLITE_NETWORK_HPP 20 | #define DPLITE_NETWORK_HPP 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #define DISCOVERY_PORT 6073 28 | #define DEFAULT_HOST_PORT 6072 29 | #define LISTEN_QUEUE_SIZE 16 30 | #define MAX_PACKET_SIZE (256 * 1024) 31 | 32 | struct SystemNetworkInterface { 33 | std::wstring friendly_name; 34 | 35 | std::list unicast_addrs; 36 | }; 37 | 38 | int create_udp_socket(uint32_t ipaddr, uint16_t port); 39 | int create_listener_socket(uint32_t ipaddr, uint16_t port); 40 | int create_client_socket(uint32_t local_ipaddr, uint16_t local_port); 41 | int create_discovery_socket(); 42 | std::list get_network_interfaces(); 43 | 44 | #endif /* !DPLITE_NETWORK_HPP */ 45 | -------------------------------------------------------------------------------- /src/packet.cpp: -------------------------------------------------------------------------------- 1 | /* DirectPlay Lite 2 | * Copyright (C) 2018 Daniel Collins 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "packet.hpp" 26 | 27 | const uint32_t FIELD_TYPE_NULL = 0; 28 | const uint32_t FIELD_TYPE_DWORD = 1; 29 | const uint32_t FIELD_TYPE_DATA = 2; 30 | const uint32_t FIELD_TYPE_WSTRING = 3; 31 | const uint32_t FIELD_TYPE_GUID = 4; 32 | 33 | PacketSerialiser::PacketSerialiser(uint32_t type) 34 | { 35 | /* Avoid reallocations during packet construction unless we get given a lot of data. */ 36 | sbuf.reserve(4096); 37 | 38 | TLVChunk header; 39 | header.type = type; 40 | header.value_length = 0; 41 | 42 | sbuf.insert(sbuf.begin(), (unsigned char*)(&header), (unsigned char*)(&header + 1)); 43 | } 44 | 45 | std::pair PacketSerialiser::raw_packet() const 46 | { 47 | return std::make_pair(sbuf.data(), sbuf.size()); 48 | } 49 | 50 | void PacketSerialiser::append_null() 51 | { 52 | TLVChunk header; 53 | header.type = FIELD_TYPE_NULL; 54 | header.value_length = 0; 55 | 56 | sbuf.insert(sbuf.end(), (unsigned char*)(&header), (unsigned char*)(&header + 1)); 57 | 58 | ((TLVChunk*)(sbuf.data()))->value_length += sizeof(header); 59 | } 60 | 61 | void PacketSerialiser::append_dword(DWORD value) 62 | { 63 | TLVChunk header; 64 | header.type = FIELD_TYPE_DWORD; 65 | header.value_length = sizeof(DWORD); 66 | 67 | sbuf.insert(sbuf.end(), (unsigned char*)(&header), (unsigned char*)(&header + 1)); 68 | sbuf.insert(sbuf.end(), (unsigned char*)(&value), (unsigned char*)(&value + 1)); 69 | 70 | ((TLVChunk*)(sbuf.data()))->value_length += sizeof(header) + sizeof(value); 71 | } 72 | 73 | void PacketSerialiser::append_data(const void *data, size_t size) 74 | { 75 | TLVChunk header; 76 | header.type = FIELD_TYPE_DATA; 77 | header.value_length = size; 78 | 79 | sbuf.insert(sbuf.end(), (unsigned char*)(&header), (unsigned char*)(&header + 1)); 80 | sbuf.insert(sbuf.end(), (unsigned char*)(data), (unsigned char*)(data) + size); 81 | 82 | ((TLVChunk*)(sbuf.data()))->value_length += sizeof(header) + size; 83 | } 84 | 85 | void PacketSerialiser::append_wstring(const std::wstring &string) 86 | { 87 | size_t string_bytes = string.length() * sizeof(wchar_t); 88 | 89 | TLVChunk header; 90 | header.type = FIELD_TYPE_WSTRING; 91 | header.value_length = string_bytes; 92 | 93 | sbuf.insert(sbuf.end(), (unsigned char*)(&header), (unsigned char*)(&header + 1)); 94 | sbuf.insert(sbuf.end(), (unsigned char*)(string.data()), (unsigned char*)(string.data()) + string_bytes); 95 | 96 | ((TLVChunk*)(sbuf.data()))->value_length += sizeof(header) + string_bytes; 97 | } 98 | 99 | void PacketSerialiser::append_guid(const GUID &guid) 100 | { 101 | TLVChunk header; 102 | header.type = FIELD_TYPE_GUID; 103 | header.value_length = sizeof(GUID); 104 | 105 | sbuf.insert(sbuf.end(), (unsigned char*)(&header), (unsigned char*)(&header + 1)); 106 | sbuf.insert(sbuf.end(), (unsigned char*)(&guid), (unsigned char*)(&guid) + sizeof(GUID)); 107 | 108 | ((TLVChunk*)(sbuf.data()))->value_length += sizeof(header) + sizeof(GUID); 109 | } 110 | 111 | PacketDeserialiser::PacketDeserialiser(const void *serialised_packet, size_t packet_size) 112 | { 113 | header = (const TLVChunk*)(serialised_packet); 114 | 115 | if(packet_size < sizeof(TLVChunk) || packet_size < sizeof(TLVChunk) + header->value_length) 116 | { 117 | throw Error::Incomplete(); 118 | } 119 | 120 | const unsigned char *at = header->value; 121 | size_t value_remain = header->value_length; 122 | 123 | while(value_remain > 0) 124 | { 125 | const TLVChunk *field = (TLVChunk*)(at); 126 | 127 | if(value_remain < sizeof(TLVChunk) || value_remain < sizeof(TLVChunk) + field->value_length) 128 | { 129 | throw Error::Malformed(); 130 | } 131 | 132 | fields.push_back(field); 133 | 134 | at += sizeof(TLVChunk) + field->value_length; 135 | value_remain -= sizeof(TLVChunk) + field->value_length; 136 | } 137 | } 138 | 139 | uint32_t PacketDeserialiser::packet_type() const 140 | { 141 | return header->type; 142 | } 143 | 144 | size_t PacketDeserialiser::num_fields() const 145 | { 146 | return fields.size(); 147 | } 148 | 149 | bool PacketDeserialiser::is_null(size_t index) const 150 | { 151 | if(fields.size() <= index) 152 | { 153 | throw Error::MissingField(); 154 | } 155 | 156 | return (fields[index]->type == FIELD_TYPE_NULL); 157 | } 158 | 159 | DWORD PacketDeserialiser::get_dword(size_t index) const 160 | { 161 | if(fields.size() <= index) 162 | { 163 | throw Error::MissingField(); 164 | } 165 | 166 | if(fields[index]->type != FIELD_TYPE_DWORD) 167 | { 168 | throw Error::TypeMismatch(); 169 | } 170 | 171 | if(fields[index]->value_length != sizeof(DWORD)) 172 | { 173 | throw Error::Malformed(); 174 | } 175 | 176 | return *(DWORD*)(fields[index]->value); 177 | } 178 | 179 | std::pair PacketDeserialiser::get_data(size_t index) const 180 | { 181 | if(fields.size() <= index) 182 | { 183 | throw Error::MissingField(); 184 | } 185 | 186 | if(fields[index]->type != FIELD_TYPE_DATA) 187 | { 188 | throw Error::TypeMismatch(); 189 | } 190 | 191 | return std::make_pair((const void*)(fields[index]->value), (size_t)(fields[index]->value_length)); 192 | } 193 | 194 | std::wstring PacketDeserialiser::get_wstring(size_t index) const 195 | { 196 | if(fields.size() <= index) 197 | { 198 | throw Error::MissingField(); 199 | } 200 | 201 | if(fields[index]->type != FIELD_TYPE_WSTRING) 202 | { 203 | throw Error::TypeMismatch(); 204 | } 205 | 206 | if((fields[index]->value_length % sizeof(wchar_t)) != 0) 207 | { 208 | throw Error::Malformed(); 209 | } 210 | 211 | return std::wstring((const wchar_t*)(fields[index]->value), (fields[index]->value_length / sizeof(wchar_t))); 212 | } 213 | 214 | GUID PacketDeserialiser::get_guid(size_t index) const 215 | { 216 | if(fields.size() <= index) 217 | { 218 | throw Error::MissingField(); 219 | } 220 | 221 | if(fields[index]->type != FIELD_TYPE_GUID) 222 | { 223 | throw Error::TypeMismatch(); 224 | } 225 | 226 | if(fields[index]->value_length != sizeof(GUID)) 227 | { 228 | throw Error::Malformed(); 229 | } 230 | 231 | return *(GUID*)(fields[index]->value); 232 | } 233 | -------------------------------------------------------------------------------- /src/packet.hpp: -------------------------------------------------------------------------------- 1 | /* DirectPlay Lite 2 | * Copyright (C) 2018-2023 Daniel Collins 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef DPLITE_PACKET_HPP 20 | #define DPLITE_PACKET_HPP 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | struct TLVChunk 31 | { 32 | uint32_t type; 33 | uint32_t value_length; 34 | 35 | #pragma warning(suppress: 4200) 36 | unsigned char value[0]; 37 | }; 38 | 39 | class PacketSerialiser 40 | { 41 | private: 42 | std::vector sbuf; 43 | 44 | public: 45 | PacketSerialiser(uint32_t type); 46 | 47 | std::pair raw_packet() const; 48 | 49 | void append_null(); 50 | void append_dword(DWORD value); 51 | void append_data(const void *data, size_t size); 52 | void append_wstring(const std::wstring &string); 53 | void append_guid(const GUID &guid); 54 | }; 55 | 56 | class PacketDeserialiser 57 | { 58 | private: 59 | const TLVChunk *header; 60 | std::vector fields; 61 | 62 | public: 63 | class Error: public std::runtime_error 64 | { 65 | protected: 66 | Error(const std::string &what): runtime_error(what) {} 67 | 68 | public: 69 | class Incomplete; 70 | class Malformed; 71 | class MissingField; 72 | class TypeMismatch; 73 | }; 74 | 75 | PacketDeserialiser(const void *serialised_packet, size_t packet_size); 76 | 77 | uint32_t packet_type() const; 78 | size_t num_fields() const; 79 | 80 | bool is_null(size_t index) const; 81 | DWORD get_dword(size_t index) const; 82 | std::pair get_data(size_t index) const; 83 | std::wstring get_wstring(size_t index) const; 84 | GUID get_guid(size_t index) const; 85 | }; 86 | 87 | class PacketDeserialiser::Error::Incomplete: public Error 88 | { 89 | public: 90 | Incomplete(const std::string &what = "Incomplete packet"): Error(what) {} 91 | }; 92 | 93 | class PacketDeserialiser::Error::Malformed: public Error 94 | { 95 | public: 96 | Malformed(const std::string &what = "Malformed packet"): Error(what) {} 97 | }; 98 | 99 | class PacketDeserialiser::Error::MissingField: public Error 100 | { 101 | public: 102 | MissingField(const std::string &what = "Missing field in packet"): Error(what) {} 103 | }; 104 | 105 | class PacketDeserialiser::Error::TypeMismatch: public Error 106 | { 107 | public: 108 | TypeMismatch(const std::string &what = "Incorrect field type in packet"): Error(what) {} 109 | }; 110 | 111 | #endif /* !DPLITE_PACKET_HPP */ 112 | -------------------------------------------------------------------------------- /tests/HandleHandlingPool.cpp: -------------------------------------------------------------------------------- 1 | /* DirectPlay Lite 2 | * Copyright (C) 2018 Daniel Collins 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "../src/EventObject.hpp" 26 | #include "../src/HandleHandlingPool.hpp" 27 | 28 | TEST(HandleHandlingPool, SingleThreadBasic) 29 | { 30 | HandleHandlingPool pool(1, 32); 31 | 32 | EventObject e1(FALSE, TRUE); 33 | std::atomic e1_counter(0); 34 | 35 | EventObject e2(FALSE, FALSE); 36 | std::atomic e2_counter(0); 37 | 38 | EventObject e3(FALSE, FALSE); 39 | std::atomic e3_counter(0); 40 | 41 | pool.add_handle(e1, [&e1, &e1_counter]() { if(++e1_counter < 4) { SetEvent(e1); } }); 42 | pool.add_handle(e2, [&e2, &e2_counter]() { if(++e2_counter < 2) { SetEvent(e2); } }); 43 | pool.add_handle(e3, [&e3_counter]() { ++e3_counter; }); 44 | 45 | SetEvent(e2); 46 | 47 | Sleep(100); 48 | 49 | EXPECT_EQ(e1_counter, 4); 50 | EXPECT_EQ(e2_counter, 2); 51 | EXPECT_EQ(e3_counter, 0); 52 | } 53 | 54 | TEST(HandleHandlingPool, MultiThreadBasic) 55 | { 56 | HandleHandlingPool pool(4, 32); 57 | 58 | EventObject e1(FALSE, TRUE); 59 | std::atomic e1_counter(0); 60 | 61 | EventObject e2(FALSE, FALSE); 62 | std::atomic e2_counter(0); 63 | 64 | EventObject e3(FALSE, FALSE); 65 | std::atomic e3_counter(0); 66 | 67 | pool.add_handle(e1, [&e1, &e1_counter]() { if(++e1_counter < 4) { SetEvent(e1); } }); 68 | pool.add_handle(e2, [&e2, &e2_counter]() { if(++e2_counter < 2) { SetEvent(e2); } }); 69 | pool.add_handle(e3, [&e3_counter]() { ++e3_counter; }); 70 | 71 | SetEvent(e2); 72 | 73 | Sleep(100); 74 | 75 | EXPECT_EQ(e1_counter, 4); 76 | EXPECT_EQ(e2_counter, 2); 77 | EXPECT_EQ(e3_counter, 0); 78 | } 79 | 80 | TEST(HandleHandlingPool, ThreadAssignment) 81 | { 82 | HandleHandlingPool pool(4, 1); 83 | 84 | EventObject e1(TRUE, TRUE); 85 | std::atomic e1_counter(0); 86 | 87 | EventObject e2(FALSE, TRUE); 88 | std::atomic e2_counter(0); 89 | 90 | EventObject e3(FALSE, FALSE); 91 | std::atomic e3_counter(0); 92 | 93 | std::mutex mutex; 94 | mutex.lock(); 95 | 96 | pool.add_handle(e1, [&mutex, &e1_counter]() { ++e1_counter; mutex.lock(); mutex.unlock(); }); 97 | pool.add_handle(e2, [&mutex, &e2, &e2_counter]() { if(++e2_counter < 20) { SetEvent(e2); } mutex.lock(); mutex.unlock(); }); 98 | pool.add_handle(e3, [&e3_counter]() { ++e3_counter; }); 99 | 100 | Sleep(100); 101 | 102 | /* We are holding the mutex, so the e1/e2 callbacks should have been invoked once by each 103 | * worker thread, and still be sleeping until we released the mutex. The thread allocation 104 | * for e3 should still be free. 105 | */ 106 | 107 | EXPECT_EQ(e1_counter, 4); 108 | EXPECT_EQ(e2_counter, 4); 109 | EXPECT_EQ(e3_counter, 0); 110 | 111 | SetEvent(e3); 112 | 113 | Sleep(100); 114 | 115 | /* Now e3 should have fired once and returned. */ 116 | 117 | EXPECT_EQ(e1_counter, 4); 118 | EXPECT_EQ(e2_counter, 4); 119 | EXPECT_EQ(e3_counter, 1); 120 | 121 | ResetEvent(e1); 122 | mutex.unlock(); 123 | 124 | Sleep(100); 125 | 126 | /* Since we released the mutex, the pending e1/e2 callbacks should return and the e2 127 | * callback should keep signalling itself until it reaches 20 calls. 128 | */ 129 | 130 | EXPECT_EQ(e1_counter, 4); 131 | EXPECT_EQ(e2_counter, 20); 132 | EXPECT_EQ(e3_counter, 1); 133 | } 134 | 135 | TEST(HandleHandlingPool, RemoveHandle) 136 | { 137 | HandleHandlingPool pool(4, 1); 138 | 139 | EventObject e1(FALSE, FALSE); 140 | std::atomic e1_counter(0); 141 | 142 | EventObject e2(FALSE, FALSE); 143 | std::atomic e2_counter(0); 144 | 145 | EventObject e3(FALSE, FALSE); 146 | std::atomic e3_counter(0); 147 | 148 | pool.add_handle(e1, [&e1_counter]() { ++e1_counter; }); 149 | pool.add_handle(e2, [&e2_counter]() { ++e2_counter; }); 150 | pool.add_handle(e3, [&e3_counter]() { ++e3_counter; }); 151 | 152 | SetEvent(e1); 153 | SetEvent(e2); 154 | SetEvent(e3); 155 | 156 | Sleep(100); 157 | 158 | EXPECT_EQ(e1_counter, 1); 159 | EXPECT_EQ(e2_counter, 1); 160 | EXPECT_EQ(e3_counter, 1); 161 | 162 | pool.remove_handle(e2); 163 | 164 | SetEvent(e1); 165 | SetEvent(e2); 166 | SetEvent(e3); 167 | 168 | Sleep(100); 169 | 170 | EXPECT_EQ(e1_counter, 2); 171 | EXPECT_EQ(e2_counter, 1); 172 | EXPECT_EQ(e3_counter, 2); 173 | } 174 | 175 | TEST(HandleHandlingPool, Stress) 176 | { 177 | /* Stress test to see if we can trigger a race/crash - 4 groups of 16 handles, each with 8 178 | * worker threads, and each handle signalling 10,000 times. 179 | */ 180 | 181 | std::vector events(64); 182 | std::vector< std::atomic > counters(64); 183 | 184 | HandleHandlingPool pool(8, 16); 185 | 186 | for(int i = 0; i < 64; ++i) 187 | { 188 | pool.add_handle(events[i], [i, &counters, &events]() { if(++counters[i] < 10000) { SetEvent(events[i]); } }); 189 | SetEvent(events[i]); 190 | } 191 | 192 | /* Is 5s enough to handle 640,000 events across 32 threads? Probably! */ 193 | Sleep(5000); 194 | 195 | for(int i = 0; i < 64; ++i) 196 | { 197 | EXPECT_EQ(counters[i], 10000); 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /tests/PacketSerialiser.cpp: -------------------------------------------------------------------------------- 1 | /* DirectPlay Lite 2 | * Copyright (C) 2018 Daniel Collins 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include 20 | 21 | #include "../src/packet.hpp" 22 | 23 | TEST(PacketSerialiser, Empty) 24 | { 25 | PacketSerialiser p(0xAA); 26 | 27 | std::pair raw = p.raw_packet(); 28 | 29 | const unsigned char EXPECT[] = { 30 | 0xAA, 0x00, 0x00, 0x00, /* type */ 31 | 0x00, 0x00, 0x00, 0x00, /* value_length */ 32 | }; 33 | 34 | std::vector got((unsigned char*)(raw.first), (unsigned char*)(raw.first) + raw.second); 35 | std::vector expect(EXPECT, EXPECT + sizeof(EXPECT)); 36 | 37 | ASSERT_EQ(got, expect); 38 | } 39 | 40 | TEST(PacketSerialiser, Null) 41 | { 42 | PacketSerialiser p(0xBB); 43 | p.append_null(); 44 | 45 | std::pair raw = p.raw_packet(); 46 | 47 | const unsigned char EXPECT[] = { 48 | 0xBB, 0x00, 0x00, 0x00, /* type */ 49 | 0x08, 0x00, 0x00, 0x00, /* value_length */ 50 | 51 | 0x00, 0x00, 0x00, 0x00, /* type */ 52 | 0x00, 0x00, 0x00, 0x00, /* value_length */ 53 | }; 54 | 55 | std::vector got((unsigned char*)(raw.first), (unsigned char*)(raw.first) + raw.second); 56 | std::vector expect(EXPECT, EXPECT + sizeof(EXPECT)); 57 | 58 | ASSERT_EQ(got, expect); 59 | } 60 | 61 | TEST(PacketSerialiser, DWORD) 62 | { 63 | PacketSerialiser p(0xAABBCCDD); 64 | p.append_dword(0xFFEEDDCC); 65 | 66 | std::pair raw = p.raw_packet(); 67 | 68 | const unsigned char EXPECT[] = { 69 | 0xDD, 0xCC, 0xBB, 0xAA, /* type */ 70 | 0x0C, 0x00, 0x00, 0x00, /* value_length */ 71 | 72 | 0x01, 0x00, 0x00, 0x00, /* type */ 73 | 0x04, 0x00, 0x00, 0x00, /* value_length */ 74 | 0xCC, 0xDD, 0xEE, 0xFF, /* value */ 75 | }; 76 | 77 | std::vector got((unsigned char*)(raw.first), (unsigned char*)(raw.first) + raw.second); 78 | std::vector expect(EXPECT, EXPECT + sizeof(EXPECT)); 79 | 80 | ASSERT_EQ(got, expect); 81 | } 82 | 83 | TEST(PacketSerialiser, Data) 84 | { 85 | PacketSerialiser p(0x1234); 86 | 87 | const unsigned char DATA[] = { 88 | 0x01, 0x23, 0x45, 0x67, 89 | 0x89, 0xAB, 0xCD, 0xEF, 90 | }; 91 | 92 | p.append_data(DATA, sizeof(DATA)); 93 | 94 | std::pair raw = p.raw_packet(); 95 | 96 | const unsigned char EXPECT[] = { 97 | 0x34, 0x12, 0x00, 0x00, /* type */ 98 | 0x10, 0x00, 0x00, 0x00, /* value_length */ 99 | 100 | 0x02, 0x00, 0x00, 0x00, /* type */ 101 | 0x08, 0x00, 0x00, 0x00, /* value_length */ 102 | 0x01, 0x23, 0x45, 0x67, /* value */ 103 | 0x89, 0xAB, 0xCD, 0xEF, 104 | }; 105 | 106 | std::vector got((unsigned char*)(raw.first), (unsigned char*)(raw.first) + raw.second); 107 | std::vector expect(EXPECT, EXPECT + sizeof(EXPECT)); 108 | 109 | ASSERT_EQ(got, expect); 110 | } 111 | 112 | TEST(PacketSerialiser, WString) 113 | { 114 | PacketSerialiser p(0x1234); 115 | 116 | p.append_wstring(L"Hello, I'm Gabe Newell"); 117 | 118 | std::pair raw = p.raw_packet(); 119 | 120 | const unsigned char EXPECT[] = { 121 | 0x34, 0x12, 0x00, 0x00, /* type */ 122 | 0x34, 0x00, 0x00, 0x00, /* value_length (52) */ 123 | 124 | 0x03, 0x00, 0x00, 0x00, /* type */ 125 | 0x2C, 0x00, 0x00, 0x00, /* value_length (44) */ 126 | 0x48, 0x00, 0x65, 0x00, /* value */ 127 | 0x6C, 0x00, 0x6C, 0x00, 128 | 0x6F, 0x00, 0x2C, 0x00, 129 | 0x20, 0x00, 0x49, 0x00, 130 | 0x27, 0x00, 0x6D, 0x00, 131 | 0x20, 0x00, 0x47, 0x00, 132 | 0x61, 0x00, 0x62, 0x00, 133 | 0x65, 0x00, 0x20, 0x00, 134 | 0x4E, 0x00, 0x65, 0x00, 135 | 0x77, 0x00, 0x65, 0x00, 136 | 0x6C, 0x00, 0x6C, 0x00 137 | }; 138 | 139 | std::vector got((unsigned char*)(raw.first), (unsigned char*)(raw.first) + raw.second); 140 | std::vector expect(EXPECT, EXPECT + sizeof(EXPECT)); 141 | 142 | ASSERT_EQ(got, expect); 143 | } 144 | 145 | TEST(PacketSerialiser, GUID) 146 | { 147 | const GUID guid = { 0x67452301, 0x1A89, 0xDEBC, { 0xF0, 0x12, 0x34, 0x56, 0x78, 0x91, 0xAB, 0xCD } }; 148 | 149 | PacketSerialiser p(0x1234); 150 | p.append_guid(guid); 151 | 152 | std::pair raw = p.raw_packet(); 153 | 154 | const unsigned char EXPECT[] = { 155 | 0x34, 0x12, 0x00, 0x00, /* type */ 156 | 0x18, 0x00, 0x00, 0x00, /* value_length */ 157 | 158 | 0x04, 0x00, 0x00, 0x00, /* type */ 159 | 0x10, 0x00, 0x00, 0x00, /* value_length */ 160 | 0x01, 0x23, 0x45, 0x67, /* value */ 161 | 0x89, 0x1A, 0xBC, 0xDE, 162 | 0xF0, 0x12, 0x34, 0x56, 163 | 0x78, 0x91, 0xAB, 0xCD, 164 | }; 165 | 166 | std::vector got((unsigned char*)(raw.first), (unsigned char*)(raw.first) + raw.second); 167 | std::vector expect(EXPECT, EXPECT + sizeof(EXPECT)); 168 | 169 | ASSERT_EQ(got, expect); 170 | } 171 | 172 | TEST(PacketSerialiser, NullDWORDDataWString) 173 | { 174 | PacketSerialiser p(0x1234); 175 | 176 | p.append_null(); 177 | p.append_dword(0xEDFE); 178 | 179 | const unsigned char DATA[] = { 0x01, 0x23, 0x45, 0x67, 0x89 }; 180 | p.append_data(DATA, sizeof(DATA)); 181 | 182 | p.append_wstring(L"WStr"); 183 | 184 | std::pair raw = p.raw_packet(); 185 | 186 | const unsigned char EXPECT[] = { 187 | 0x34, 0x12, 0x00, 0x00, /* type */ 188 | 0x31, 0x00, 0x00, 0x00, /* value_length (49) */ 189 | 190 | 0x00, 0x00, 0x00, 0x00, /* type */ 191 | 0x00, 0x00, 0x00, 0x00, /* value_length */ 192 | 193 | 0x01, 0x00, 0x00, 0x00, /* type */ 194 | 0x04, 0x00, 0x00, 0x00, /* value_length */ 195 | 0xFE, 0xED, 0x00, 0x00, /* value */ 196 | 197 | 0x02, 0x00, 0x00, 0x00, /* type */ 198 | 0x05, 0x00, 0x00, 0x00, /* value_length */ 199 | 0x01, 0x23, 0x45, 0x67, /* value */ 200 | 0x89, 201 | 202 | 0x03, 0x00, 0x00, 0x00, /* type */ 203 | 0x08, 0x00, 0x00, 0x00, /* value_length */ 204 | 0x57, 0x00, 0x53, 0x00, /* value */ 205 | 0x74, 0x00, 0x72, 0x00, 206 | }; 207 | 208 | std::vector got((unsigned char*)(raw.first), (unsigned char*)(raw.first) + raw.second); 209 | std::vector expect(EXPECT, EXPECT + sizeof(EXPECT)); 210 | 211 | ASSERT_EQ(got, expect); 212 | } 213 | -------------------------------------------------------------------------------- /tests/tests.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | {6243e219-3927-43f6-9b5f-e34164900687} 32 | 33 | 34 | 35 | 15.0 36 | {7DFB7CFB-C59A-44D8-A701-CA14D153EBF2} 37 | Win32Proj 38 | tests 39 | 10.0.17763.0 40 | 41 | 42 | 43 | Application 44 | true 45 | v141 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v141 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | false 69 | $(SolutionDir)include;$(SolutionDir)googletest\include;$(SolutionDir)googletest;$(IncludePath) 70 | 71 | 72 | true 73 | $(SolutionDir)include;$(SolutionDir)googletest\include;$(SolutionDir)googletest;$(IncludePath) 74 | 75 | 76 | 77 | NotUsing 78 | Level3 79 | MaxSpeed 80 | true 81 | true 82 | true 83 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 84 | true 85 | pch.h 86 | 87 | 88 | Console 89 | true 90 | true 91 | true 92 | dxguid.lib;iphlpapi.lib;ws2_32.lib;%(AdditionalDependencies) 93 | 94 | 95 | 96 | 97 | NotUsing 98 | Level3 99 | Disabled 100 | true 101 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 102 | true 103 | pch.h 104 | 105 | 106 | Console 107 | true 108 | dxguid.lib;iphlpapi.lib;ws2_32.lib;%(AdditionalDependencies) 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /tests/tests.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 47 | 48 | 49 | Source Files 50 | 51 | 52 | Source Files 53 | 54 | 55 | Source Files 56 | 57 | 58 | Source Files 59 | 60 | 61 | --------------------------------------------------------------------------------