├── .gitignore ├── Base ├── Base.vcxproj.user ├── Time.h ├── Time.cpp ├── Base.sln ├── stdafx.cpp ├── Debug.h ├── targetver.h ├── stdafx.h ├── Sync.h ├── Base.h ├── Types.h ├── Path.h ├── Task.h ├── Sync.cpp ├── Thread.h ├── Timer.h ├── Log.h ├── Mem.h ├── Macros.h ├── Mem.cpp ├── Str.h ├── Debug.cpp ├── Path.cpp ├── Task.cpp ├── Log.cpp ├── Base.vcxproj ├── Timer.cpp ├── Str.cpp ├── Thread.cpp ├── Hash.h └── List.h ├── Test ├── List │ ├── List.vcxproj.user │ ├── stdafx.cpp │ ├── targetver.h │ ├── stdafx.h │ ├── List.sln │ ├── List.vcxproj │ └── List.cpp ├── Service │ ├── Service.vcxproj.user │ ├── stdafx.cpp │ ├── targetver.h │ ├── stdafx.h │ ├── Service.sln │ ├── Main.cpp │ └── Service.vcxproj └── LogDeadlock │ ├── LogDeadlock │ ├── LogDeadlock.vcxproj.user │ ├── stdafx.cpp │ ├── targetver.h │ ├── stdafx.h │ ├── LogDeadlock.cpp │ └── LogDeadlock.vcxproj │ └── LogDeadlock.sln ├── Lib └── SrvLib │ ├── SrvLib.vcxproj.user │ ├── stdafx.cpp │ ├── targetver.h │ ├── Config.h │ ├── stdafx.h │ ├── MainWnd.h │ ├── SrvLib.h │ ├── SrvLib.vcxproj │ ├── MainWnd.cpp │ ├── Config.cpp │ └── SrvLib.cpp └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.vcxproj.filters 2 | *.opensdf 3 | *.sdf 4 | *.suo 5 | 6 | ipch/ 7 | Debug/ 8 | Release/ 9 | -------------------------------------------------------------------------------- /Base/Base.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Test/List/List.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Lib/SrvLib/SrvLib.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Test/Service/Service.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Test/LogDeadlock/LogDeadlock/LogDeadlock.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Lib/SrvLib/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // SrvLib.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /Test/List/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // List.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /Base/Time.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Time.h 4 | * 5 | * 6 | * By Patrick Wyatt - 11/19/2011 7 | * 8 | ***/ 9 | 10 | 11 | #ifdef TIME_H 12 | #error "Header included more than once" 13 | #endif 14 | #define TIME_H 15 | 16 | 17 | unsigned TimeGetMs (); 18 | -------------------------------------------------------------------------------- /Test/Service/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // Service.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /Lib/SrvLib/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /Test/List/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /Test/LogDeadlock/LogDeadlock/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // LogDeadlock.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /Test/Service/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /Test/LogDeadlock/LogDeadlock/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /Lib/SrvLib/Config.h: -------------------------------------------------------------------------------- 1 | /************************************ 2 | * 3 | * Config.h 4 | * 5 | * 6 | * By Patrick Wyatt - 5/19/2010 7 | * 8 | ***/ 9 | 10 | 11 | #ifdef CONFIG_H 12 | #error "Header included more than once" 13 | #endif 14 | #define CONFIG_H 15 | 16 | 17 | void ConfigInitialize (); 18 | void ConfigDestroy (); 19 | 20 | void ConfigMonitorFile (const wchar filename[]); 21 | 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | coho, for "Code of Honor" 2 | ================================= 3 | This library is a basic toolkit for writing C++ programs 4 | from scratch. Since I left my extensive coding libraries 5 | at previous companies, I'll be damned if I don't open 6 | source this version so I don't have to write the basics 7 | again. Perhaps you'll find them useful. 8 | 9 | Blog: www.CodeOfHonor.com/blog 10 | 11 | MIT License 12 | -------------------------------------------------------------------------------- /Test/LogDeadlock/LogDeadlock/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | // TODO: reference additional headers your program requires here 19 | -------------------------------------------------------------------------------- /Base/Time.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Time.cpp 4 | * 5 | * 6 | * By Patrick Wyatt - 11/19/2011 7 | * 8 | ***/ 9 | 10 | 11 | #include "stdafx.h" 12 | #pragma hdrstop 13 | 14 | 15 | /****************************************************************************** 16 | * 17 | * Exports 18 | * 19 | ***/ 20 | 21 | //============================================================================= 22 | unsigned TimeGetMs () { 23 | return GetTickCount(); 24 | } 25 | -------------------------------------------------------------------------------- /Test/List/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #include 11 | #include 12 | 13 | 14 | 15 | // TODO: reference additional headers your program requires here 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "../../Base/Base.h" 23 | -------------------------------------------------------------------------------- /Test/LogDeadlock/LogDeadlock/LogDeadlock.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "stdafx.h" 4 | 5 | 6 | //============================================================================= 7 | static unsigned __stdcall ThreadProc (void * param) { 8 | bool * shutdown = (bool *) param; 9 | while (!*shutdown) 10 | Sleep(1); 11 | return 0; 12 | } 13 | 14 | //============================================================================= 15 | int _tmain(int argc, _TCHAR* argv[]) { 16 | bool shutdown = false; 17 | ThreadInit(); 18 | Thread * mainThread = ThreadRegister("main"); 19 | Thread * childThread = ThreadCreate("test", 0, ThreadProc, &shutdown); 20 | 21 | ThreadLogAllThreads(); 22 | 23 | shutdown = true; 24 | ThreadDestroy(childThread); childThread = NULL; 25 | ThreadUnregister(mainThread); mainThread = NULL; 26 | ThreadDestroy(); 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /Base/Base.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Base", "Base.vcxproj", "{2E31A4E1-59F9-47ED-AC3B-C6A30E17C7B2}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {2E31A4E1-59F9-47ED-AC3B-C6A30E17C7B2}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {2E31A4E1-59F9-47ED-AC3B-C6A30E17C7B2}.Debug|Win32.Build.0 = Debug|Win32 14 | {2E31A4E1-59F9-47ED-AC3B-C6A30E17C7B2}.Release|Win32.ActiveCfg = Release|Win32 15 | {2E31A4E1-59F9-47ED-AC3B-C6A30E17C7B2}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /Test/Service/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | // Disable errors 9 | #pragma warning(disable:4514) // unreferenced inline function has been removed 10 | #pragma warning(disable:4530) // C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc 11 | #pragma warning(disable:4710) // function not inlined 12 | #pragma warning(disable:4820) // padding added after member 13 | #pragma warning(disable:4986) // exception specification does not match previous declaration 14 | 15 | 16 | #include "targetver.h" 17 | 18 | // System includes 19 | #pragma warning(push, 1) 20 | #define STRICT 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #pragma warning(pop) 31 | 32 | 33 | // Project includes 34 | #include "../../Base/Base.h" 35 | #include "../../Lib/SrvLib/SrvLib.h" 36 | -------------------------------------------------------------------------------- /Lib/SrvLib/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | // Disable errors 9 | #pragma warning(disable:4514) // unreferenced inline function has been removed 10 | #pragma warning(disable:4530) // C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc 11 | #pragma warning(disable:4710) // function not inlined 12 | #pragma warning(disable:4820) // padding added after member 13 | #pragma warning(disable:4986) // exception specification does not match previous declaration 14 | 15 | 16 | #include "targetver.h" 17 | 18 | // System includes 19 | #pragma warning(push, 1) 20 | #define STRICT 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #pragma warning(pop) 31 | 32 | 33 | // Project includes 34 | #include 35 | #include 36 | #include "MainWnd.h" 37 | #include "Config.h" -------------------------------------------------------------------------------- /Test/List/List.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "List", "List.vcxproj", "{E076C6AF-49DB-4E13-92F1-02A38D94ABAD}" 5 | EndProject 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Base", "..\..\Base\Base.vcxproj", "{2E31A4E1-59F9-47ED-AC3B-C6A30E17C7B2}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Release|Win32 = Release|Win32 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {E076C6AF-49DB-4E13-92F1-02A38D94ABAD}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {E076C6AF-49DB-4E13-92F1-02A38D94ABAD}.Debug|Win32.Build.0 = Debug|Win32 16 | {E076C6AF-49DB-4E13-92F1-02A38D94ABAD}.Release|Win32.ActiveCfg = Release|Win32 17 | {E076C6AF-49DB-4E13-92F1-02A38D94ABAD}.Release|Win32.Build.0 = Release|Win32 18 | {2E31A4E1-59F9-47ED-AC3B-C6A30E17C7B2}.Debug|Win32.ActiveCfg = Debug|Win32 19 | {2E31A4E1-59F9-47ED-AC3B-C6A30E17C7B2}.Debug|Win32.Build.0 = Debug|Win32 20 | {2E31A4E1-59F9-47ED-AC3B-C6A30E17C7B2}.Release|Win32.ActiveCfg = Release|Win32 21 | {2E31A4E1-59F9-47ED-AC3B-C6A30E17C7B2}.Release|Win32.Build.0 = Release|Win32 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | -------------------------------------------------------------------------------- /Base/stdafx.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * stdafx.cpp 4 | * 5 | * 6 | * By Patrick Wyatt - 5/16/2010 7 | * 8 | ***/ 9 | 10 | 11 | // reference any additional headers you need in STDAFX.H and not in this file 12 | #include "stdafx.h" 13 | 14 | 15 | //=================================== 16 | // MIT License 17 | // 18 | // Copyright (c) 2010 by Patrick Wyatt 19 | // 20 | // Permission is hereby granted, free of charge, to any person obtaining a copy 21 | // of this software and associated documentation files (the "Software"), to deal 22 | // in the Software without restriction, including without limitation the rights 23 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 24 | // copies of the Software, and to permit persons to whom the Software is 25 | // furnished to do so, subject to the following conditions: 26 | // 27 | // The above copyright notice and this permission notice shall be included in 28 | // all copies or substantial portions of the Software. 29 | // 30 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 31 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 32 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 33 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 34 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 35 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 36 | // THE SOFTWARE. 37 | //=================================== 38 | -------------------------------------------------------------------------------- /Test/LogDeadlock/LogDeadlock.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LogDeadlock", "LogDeadlock\LogDeadlock.vcxproj", "{204B37E9-92D1-4AF8-AA72-9547A4577FD0}" 5 | ProjectSection(ProjectDependencies) = postProject 6 | {2E31A4E1-59F9-47ED-AC3B-C6A30E17C7B2} = {2E31A4E1-59F9-47ED-AC3B-C6A30E17C7B2} 7 | EndProjectSection 8 | EndProject 9 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Base", "..\..\Base\Base.vcxproj", "{2E31A4E1-59F9-47ED-AC3B-C6A30E17C7B2}" 10 | EndProject 11 | Global 12 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 13 | Debug|Win32 = Debug|Win32 14 | Release|Win32 = Release|Win32 15 | EndGlobalSection 16 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 17 | {204B37E9-92D1-4AF8-AA72-9547A4577FD0}.Debug|Win32.ActiveCfg = Debug|Win32 18 | {204B37E9-92D1-4AF8-AA72-9547A4577FD0}.Debug|Win32.Build.0 = Debug|Win32 19 | {204B37E9-92D1-4AF8-AA72-9547A4577FD0}.Release|Win32.ActiveCfg = Release|Win32 20 | {204B37E9-92D1-4AF8-AA72-9547A4577FD0}.Release|Win32.Build.0 = Release|Win32 21 | {2E31A4E1-59F9-47ED-AC3B-C6A30E17C7B2}.Debug|Win32.ActiveCfg = Debug|Win32 22 | {2E31A4E1-59F9-47ED-AC3B-C6A30E17C7B2}.Debug|Win32.Build.0 = Debug|Win32 23 | {2E31A4E1-59F9-47ED-AC3B-C6A30E17C7B2}.Release|Win32.ActiveCfg = Release|Win32 24 | {2E31A4E1-59F9-47ED-AC3B-C6A30E17C7B2}.Release|Win32.Build.0 = Release|Win32 25 | EndGlobalSection 26 | GlobalSection(SolutionProperties) = preSolution 27 | HideSolutionNode = FALSE 28 | EndGlobalSection 29 | EndGlobal 30 | -------------------------------------------------------------------------------- /Lib/SrvLib/MainWnd.h: -------------------------------------------------------------------------------- 1 | /************************************ 2 | * 3 | * MainWnd.h 4 | * 5 | * 6 | * By Patrick Wyatt - 5/17/2010 7 | * 8 | ***/ 9 | 10 | 11 | #ifdef MAINWND_H 12 | #error "Header included more than once" 13 | #endif 14 | #define MAINWND_H 15 | 16 | 17 | void MainWndInitialize (const wchar name[]); 18 | void MainWndDestroy (); 19 | 20 | 21 | //=================================== 22 | // MIT License 23 | // 24 | // Copyright (c) 2010 by Patrick Wyatt 25 | // 26 | // Permission is hereby granted, free of charge, to any person obtaining a copy 27 | // of this software and associated documentation files (the "Software"), to deal 28 | // in the Software without restriction, including without limitation the rights 29 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 30 | // copies of the Software, and to permit persons to whom the Software is 31 | // furnished to do so, subject to the following conditions: 32 | // 33 | // The above copyright notice and this permission notice shall be included in 34 | // all copies or substantial portions of the Software. 35 | // 36 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 37 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 38 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 39 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 40 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 41 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 42 | // THE SOFTWARE. 43 | //=================================== 44 | -------------------------------------------------------------------------------- /Base/Debug.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Debug.h 4 | * 5 | * 6 | * By Patrick Wyatt - 5/20/2010 7 | * 8 | ***/ 9 | 10 | 11 | #ifdef DEBUG_H 12 | #error "Header included more than once" 13 | #endif 14 | #define DEBUG_H 15 | 16 | 17 | void __cdecl DebugMsg (const char fmt[], ...); 18 | void DebugMsgV (const char fmt[], va_list args); 19 | 20 | void DebugSetThreadName (const char name[], unsigned threadId = 0); 21 | 22 | 23 | //=================================== 24 | // MIT License 25 | // 26 | // Copyright (c) 2010 by Patrick Wyatt 27 | // 28 | // Permission is hereby granted, free of charge, to any person obtaining a copy 29 | // of this software and associated documentation files (the "Software"), to deal 30 | // in the Software without restriction, including without limitation the rights 31 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 32 | // copies of the Software, and to permit persons to whom the Software is 33 | // furnished to do so, subject to the following conditions: 34 | // 35 | // The above copyright notice and this permission notice shall be included in 36 | // all copies or substantial portions of the Software. 37 | // 38 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 39 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 40 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 41 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 42 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 43 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 44 | // THE SOFTWARE. 45 | //=================================== 46 | -------------------------------------------------------------------------------- /Base/targetver.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * targetver.h 4 | * 5 | * 6 | * By Patrick Wyatt - 5/16/2010 7 | * 8 | ***/ 9 | 10 | 11 | #pragma once 12 | 13 | // Including SDKDDKVer.h defines the highest available Windows platform. 14 | 15 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 16 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 17 | 18 | #include 19 | 20 | 21 | //=================================== 22 | // MIT License 23 | // 24 | // Copyright (c) 2010 by Patrick Wyatt 25 | // 26 | // Permission is hereby granted, free of charge, to any person obtaining a copy 27 | // of this software and associated documentation files (the "Software"), to deal 28 | // in the Software without restriction, including without limitation the rights 29 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 30 | // copies of the Software, and to permit persons to whom the Software is 31 | // furnished to do so, subject to the following conditions: 32 | // 33 | // The above copyright notice and this permission notice shall be included in 34 | // all copies or substantial portions of the Software. 35 | // 36 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 37 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 38 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 39 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 40 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 41 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 42 | // THE SOFTWARE. 43 | //=================================== 44 | -------------------------------------------------------------------------------- /Base/stdafx.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * stdafx.h 4 | * 5 | * 6 | * By Patrick Wyatt - 5/16/2010 7 | * 8 | ***/ 9 | 10 | 11 | #pragma once 12 | 13 | #include "targetver.h" 14 | 15 | // System includes 16 | #define STRICT 17 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | // Project includes 26 | #include "Base.h" 27 | 28 | 29 | //=================================== 30 | // MIT License 31 | // 32 | // Copyright (c) 2010 by Patrick Wyatt 33 | // 34 | // Permission is hereby granted, free of charge, to any person obtaining a copy 35 | // of this software and associated documentation files (the "Software"), to deal 36 | // in the Software without restriction, including without limitation the rights 37 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 38 | // copies of the Software, and to permit persons to whom the Software is 39 | // furnished to do so, subject to the following conditions: 40 | // 41 | // The above copyright notice and this permission notice shall be included in 42 | // all copies or substantial portions of the Software. 43 | // 44 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 45 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 46 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 47 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 48 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 49 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 50 | // THE SOFTWARE. 51 | //=================================== 52 | -------------------------------------------------------------------------------- /Test/Service/Service.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Service", "Service.vcxproj", "{7A017E47-91B5-4227-A84B-93948E6AA178}" 5 | EndProject 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Base", "..\..\Base\Base.vcxproj", "{2E31A4E1-59F9-47ED-AC3B-C6A30E17C7B2}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SrvLib", "..\..\Lib\SrvLib\SrvLib.vcxproj", "{7902CF80-F1D1-4066-890F-E02692454A89}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Win32 = Debug|Win32 13 | Release|Win32 = Release|Win32 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {7A017E47-91B5-4227-A84B-93948E6AA178}.Debug|Win32.ActiveCfg = Debug|Win32 17 | {7A017E47-91B5-4227-A84B-93948E6AA178}.Debug|Win32.Build.0 = Debug|Win32 18 | {7A017E47-91B5-4227-A84B-93948E6AA178}.Release|Win32.ActiveCfg = Release|Win32 19 | {7A017E47-91B5-4227-A84B-93948E6AA178}.Release|Win32.Build.0 = Release|Win32 20 | {2E31A4E1-59F9-47ED-AC3B-C6A30E17C7B2}.Debug|Win32.ActiveCfg = Debug|Win32 21 | {2E31A4E1-59F9-47ED-AC3B-C6A30E17C7B2}.Debug|Win32.Build.0 = Debug|Win32 22 | {2E31A4E1-59F9-47ED-AC3B-C6A30E17C7B2}.Release|Win32.ActiveCfg = Release|Win32 23 | {2E31A4E1-59F9-47ED-AC3B-C6A30E17C7B2}.Release|Win32.Build.0 = Release|Win32 24 | {7902CF80-F1D1-4066-890F-E02692454A89}.Debug|Win32.ActiveCfg = Debug|Win32 25 | {7902CF80-F1D1-4066-890F-E02692454A89}.Debug|Win32.Build.0 = Debug|Win32 26 | {7902CF80-F1D1-4066-890F-E02692454A89}.Release|Win32.ActiveCfg = Release|Win32 27 | {7902CF80-F1D1-4066-890F-E02692454A89}.Release|Win32.Build.0 = Release|Win32 28 | EndGlobalSection 29 | GlobalSection(SolutionProperties) = preSolution 30 | HideSolutionNode = FALSE 31 | EndGlobalSection 32 | EndGlobal 33 | -------------------------------------------------------------------------------- /Base/Sync.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Sync.h 4 | * 5 | * 6 | * By Patrick Wyatt - 5/20/2010 7 | * 8 | ***/ 9 | 10 | 11 | #ifdef SYNC_H 12 | #error "Header included more than once" 13 | #endif 14 | #define SYNC_H 15 | 16 | 17 | class CCritSect { 18 | private: 19 | CRITICAL_SECTION m_crit; 20 | 21 | // Hide copy-constructor and assignment operator 22 | CCritSect (const CCritSect &); 23 | CCritSect & operator= (const CCritSect &); 24 | 25 | public: 26 | CCritSect (); 27 | ~CCritSect (); 28 | void Enter (); 29 | void Leave (); 30 | }; 31 | 32 | 33 | //=================================== 34 | // MIT License 35 | // 36 | // Copyright (c) 2010 by Patrick Wyatt 37 | // 38 | // Permission is hereby granted, free of charge, to any person obtaining a copy 39 | // of this software and associated documentation files (the "Software"), to deal 40 | // in the Software without restriction, including without limitation the rights 41 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 42 | // copies of the Software, and to permit persons to whom the Software is 43 | // furnished to do so, subject to the following conditions: 44 | // 45 | // The above copyright notice and this permission notice shall be included in 46 | // all copies or substantial portions of the Software. 47 | // 48 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 49 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 50 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 51 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 52 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 53 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 54 | // THE SOFTWARE. 55 | //=================================== 56 | -------------------------------------------------------------------------------- /Base/Base.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Base.h 4 | * 5 | * 6 | * By Patrick Wyatt - 5/16/2010 7 | * 8 | ***/ 9 | 10 | // Not having access to offsetof causes all sorts of odd compilation errors 11 | // that take time to track down! 12 | #ifndef offsetof 13 | #error Include stddef.h please! 14 | #endif 15 | 16 | 17 | #include "Macros.h" 18 | #include "Types.h" 19 | #include "List.h" 20 | #include "Hash.h" 21 | #include "Debug.h" 22 | #include "Log.h" 23 | #include "Mem.h" 24 | #include "Path.h" 25 | #include "Str.h" 26 | #include "Sync.h" 27 | #include "Task.h" 28 | #include "Thread.h" 29 | #include "Time.h" 30 | 31 | 32 | //=================================== 33 | // MIT License 34 | // 35 | // Copyright (c) 2010 by Patrick Wyatt 36 | // 37 | // Permission is hereby granted, free of charge, to any person obtaining a copy 38 | // of this software and associated documentation files (the "Software"), to deal 39 | // in the Software without restriction, including without limitation the rights 40 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 41 | // copies of the Software, and to permit persons to whom the Software is 42 | // furnished to do so, subject to the following conditions: 43 | // 44 | // The above copyright notice and this permission notice shall be included in 45 | // all copies or substantial portions of the Software. 46 | // 47 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 48 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 49 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 50 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 51 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 52 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 53 | // THE SOFTWARE. 54 | //=================================== 55 | -------------------------------------------------------------------------------- /Base/Types.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Types.h 4 | * 5 | * 6 | * By Patrick Wyatt - 5/16/2010 7 | * 8 | ***/ 9 | 10 | 11 | #ifdef TYPES_H 12 | #error "Header included more than once" 13 | #endif 14 | #define TYPES_H 15 | 16 | 17 | typedef signed char i8; 18 | typedef unsigned char u8; 19 | 20 | typedef signed short i16; 21 | typedef unsigned short u16; 22 | 23 | typedef signed long i32; 24 | typedef unsigned long u32; 25 | 26 | typedef __int64 i64; 27 | typedef unsigned __int64 u64; 28 | 29 | 30 | #if _MSC_VER > 1000 31 | typedef wchar_t wchar; 32 | #else 33 | typedef unsigned short wchar; 34 | #endif 35 | 36 | 37 | //=================================== 38 | // MIT License 39 | // 40 | // Copyright (c) 2010 by Patrick Wyatt 41 | // 42 | // Permission is hereby granted, free of charge, to any person obtaining a copy 43 | // of this software and associated documentation files (the "Software"), to deal 44 | // in the Software without restriction, including without limitation the rights 45 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 46 | // copies of the Software, and to permit persons to whom the Software is 47 | // furnished to do so, subject to the following conditions: 48 | // 49 | // The above copyright notice and this permission notice shall be included in 50 | // all copies or substantial portions of the Software. 51 | // 52 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 53 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 54 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 55 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 56 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 57 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 58 | // THE SOFTWARE. 59 | //=================================== 60 | -------------------------------------------------------------------------------- /Base/Path.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Path.h 4 | * 5 | * 6 | * By Patrick Wyatt - 5/6/2010 7 | * 8 | ***/ 9 | 10 | 11 | #ifdef PATH_H 12 | #error "Header included more than once" 13 | #endif 14 | #define PATH_H 15 | 16 | 17 | void PathGetExeFullPath (wchar * path, unsigned chars); 18 | void PathGetExeFileName (wchar * path, unsigned chars); 19 | void PathRemoveFileName (wchar * path, unsigned chars, const wchar src[]); 20 | void PathRemovePath (wchar * path, unsigned chars, const wchar src[]); 21 | 22 | 23 | void PathGetProgramDirectory (wchar * path, unsigned chars); 24 | void PathSetProgramDirectory (); 25 | 26 | 27 | bool PathCreateDirectory (const wchar directory[]); 28 | 29 | 30 | //=================================== 31 | // MIT License 32 | // 33 | // Copyright (c) 2010 by Patrick Wyatt 34 | // 35 | // Permission is hereby granted, free of charge, to any person obtaining a copy 36 | // of this software and associated documentation files (the "Software"), to deal 37 | // in the Software without restriction, including without limitation the rights 38 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 39 | // copies of the Software, and to permit persons to whom the Software is 40 | // furnished to do so, subject to the following conditions: 41 | // 42 | // The above copyright notice and this permission notice shall be included in 43 | // all copies or substantial portions of the Software. 44 | // 45 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 46 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 47 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 48 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 49 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 50 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 51 | // THE SOFTWARE. 52 | //=================================== 53 | -------------------------------------------------------------------------------- /Base/Task.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Task.h 4 | * 5 | * 6 | * By Patrick Wyatt - 5/19/2010 7 | * 8 | ***/ 9 | 10 | 11 | #ifdef TASK_H 12 | #error "Header included more than once" 13 | #endif 14 | #define TASK_H 15 | 16 | 17 | /****************************************************************************** 18 | * 19 | * Types 20 | * 21 | ***/ 22 | 23 | class CTask { 24 | public: 25 | virtual void TaskComplete ( 26 | unsigned bytes, 27 | OVERLAPPED * olap 28 | ) = 0; 29 | }; 30 | 31 | 32 | /****************************************************************************** 33 | * 34 | * Functions 35 | * 36 | ***/ 37 | 38 | void TaskInitialize (); 39 | void TaskDestroy (); 40 | 41 | void TaskRegisterHandle ( 42 | CTask * task, 43 | HANDLE handle 44 | ); 45 | 46 | 47 | //=================================== 48 | // MIT License 49 | // 50 | // Copyright (c) 2010 by Patrick Wyatt 51 | // 52 | // Permission is hereby granted, free of charge, to any person obtaining a copy 53 | // of this software and associated documentation files (the "Software"), to deal 54 | // in the Software without restriction, including without limitation the rights 55 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 56 | // copies of the Software, and to permit persons to whom the Software is 57 | // furnished to do so, subject to the following conditions: 58 | // 59 | // The above copyright notice and this permission notice shall be included in 60 | // all copies or substantial portions of the Software. 61 | // 62 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 63 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 64 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 65 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 66 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 67 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 68 | // THE SOFTWARE. 69 | //=================================== 70 | -------------------------------------------------------------------------------- /Lib/SrvLib/SrvLib.h: -------------------------------------------------------------------------------- 1 | /************************************ 2 | * 3 | * SrvLib.h 4 | * 5 | * 6 | * By Patrick Wyatt - 5/14/2010 7 | * 8 | ***/ 9 | 10 | 11 | #ifdef APP_H 12 | #error "Header included more than once" 13 | #endif 14 | #define APP_H 15 | 16 | 17 | class CServiceStatus { 18 | public: 19 | virtual void UpdateStatus ( 20 | unsigned checkPoint, 21 | unsigned waitHintMs 22 | ) = 0; 23 | }; 24 | 25 | 26 | class CApplication { 27 | public: 28 | // Application config 29 | virtual const wchar * Name () const = 0; 30 | virtual const wchar * Description () const = 0; 31 | 32 | 33 | // Application run 34 | virtual void Start (CServiceStatus * status) = 0; 35 | virtual void Run (bool serviceMode) = 0; 36 | virtual void SignalStop () = 0; 37 | virtual void Stop () = 0; 38 | virtual int ExitCode () const = 0; 39 | }; 40 | 41 | 42 | int ServiceMain (CApplication * app); 43 | void ServiceSignalStop (); 44 | 45 | 46 | //=================================== 47 | // MIT License 48 | // 49 | // Copyright (c) 2010 by Patrick Wyatt 50 | // 51 | // Permission is hereby granted, free of charge, to any person obtaining a copy 52 | // of this software and associated documentation files (the "Software"), to deal 53 | // in the Software without restriction, including without limitation the rights 54 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 55 | // copies of the Software, and to permit persons to whom the Software is 56 | // furnished to do so, subject to the following conditions: 57 | // 58 | // The above copyright notice and this permission notice shall be included in 59 | // all copies or substantial portions of the Software. 60 | // 61 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 62 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 63 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 64 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 65 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 66 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 67 | // THE SOFTWARE. 68 | //=================================== 69 | -------------------------------------------------------------------------------- /Base/Sync.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Sync.cpp 4 | * 5 | * 6 | * By Patrick Wyatt - 5/20/2010 7 | * 8 | ***/ 9 | 10 | 11 | #include "stdafx.h" 12 | #pragma hdrstop 13 | 14 | 15 | /****************************************************************************** 16 | * 17 | * Exports 18 | * 19 | ***/ 20 | 21 | //============================================================================= 22 | CCritSect::CCritSect () { 23 | InitializeCriticalSection(&m_crit); 24 | } 25 | 26 | //============================================================================= 27 | CCritSect::~CCritSect () { 28 | DeleteCriticalSection(&m_crit); 29 | } 30 | 31 | //============================================================================= 32 | void CCritSect::Enter () { 33 | EnterCriticalSection(&m_crit); 34 | } 35 | 36 | //============================================================================= 37 | void CCritSect::Leave () { 38 | LeaveCriticalSection(&m_crit); 39 | } 40 | 41 | 42 | //=================================== 43 | // MIT License 44 | // 45 | // Copyright (c) 2010 by Patrick Wyatt 46 | // 47 | // Permission is hereby granted, free of charge, to any person obtaining a copy 48 | // of this software and associated documentation files (the "Software"), to deal 49 | // in the Software without restriction, including without limitation the rights 50 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 51 | // copies of the Software, and to permit persons to whom the Software is 52 | // furnished to do so, subject to the following conditions: 53 | // 54 | // The above copyright notice and this permission notice shall be included in 55 | // all copies or substantial portions of the Software. 56 | // 57 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 58 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 59 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 60 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 61 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 62 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 63 | // THE SOFTWARE. 64 | //=================================== 65 | -------------------------------------------------------------------------------- /Base/Thread.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Thread.h 4 | * 5 | * 6 | * By Patrick Wyatt 7 | * 8 | ***/ 9 | 10 | 11 | struct Thread; 12 | 13 | // Module functions 14 | void ThreadInit (); 15 | void ThreadDestroy (); 16 | void ThreadLogAllThreads (); 17 | 18 | 19 | // Thread functions 20 | Thread * ThreadCreate ( 21 | const char name[], 22 | unsigned stack_size, 23 | unsigned (__stdcall * start_address )(void *), 24 | void *arglist 25 | ); 26 | void ThreadDestroy (Thread * thread); 27 | 28 | // Register a thread that was created using an API other than ThreadCreate 29 | Thread * ThreadRegister (const char name[]); 30 | void ThreadUnregister (Thread * thread); 31 | 32 | // For each thread created with ThreadCreate, call this function 33 | // at least once per minute to mark it alive, otherwise deadlock 34 | // processor will mark it dead and crash the application. 35 | void ThreadMarkAlive (Thread * thread); 36 | 37 | 38 | //=================================== 39 | // MIT License 40 | // 41 | // Copyright (c) 2012 by Patrick Wyatt 42 | // 43 | // Permission is hereby granted, free of charge, to any person obtaining a copy 44 | // of this software and associated documentation files (the "Software"), to deal 45 | // in the Software without restriction, including without limitation the rights 46 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 47 | // copies of the Software, and to permit persons to whom the Software is 48 | // furnished to do so, subject to the following conditions: 49 | // 50 | // The above copyright notice and this permission notice shall be included in 51 | // all copies or substantial portions of the Software. 52 | // 53 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 54 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 55 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 56 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 57 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 58 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 59 | // THE SOFTWARE. 60 | //=================================== 61 | -------------------------------------------------------------------------------- /Base/Timer.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Timer.h 4 | * 5 | * 6 | * By Patrick Wyatt - 11/19/2011 7 | * 8 | ***/ 9 | 10 | 11 | #ifdef TIMER_H 12 | #error "Header included more than once" 13 | #endif 14 | #define TIMER_H 15 | 16 | 17 | /****************************************************************************** 18 | * 19 | * Exports 20 | * 21 | ***/ 22 | 23 | // Used for TimerCreate() and Timer::Set() 24 | const unsigned TIMER_INFINITE_MS = (unsigned) -1; 25 | 26 | // Your class should derive from this class to receive a callback 27 | APICLASS ITimerCallback { 28 | virtual unsigned OnTimer () = 0; 29 | }; 30 | 31 | // When you create a timer you get this timer management object 32 | APICLASS ITimer { 33 | virtual void Delete () = 0; 34 | virtual void Set (__in unsigned sleepMs) = 0; 35 | }; 36 | 37 | void TimerCreate ( 38 | __in ITimerCallback * callback, 39 | __in unsigned sleepMs, 40 | __out ITimer ** timer 41 | ); 42 | 43 | // Module creation/destruction 44 | void TimerInitialize (); 45 | void TimerDestroy (); 46 | 47 | 48 | //=================================== 49 | // MIT License 50 | // 51 | // Copyright (c) 2010 by Patrick Wyatt 52 | // 53 | // Permission is hereby granted, free of charge, to any person obtaining a copy 54 | // of this software and associated documentation files (the "Software"), to deal 55 | // in the Software without restriction, including without limitation the rights 56 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 57 | // copies of the Software, and to permit persons to whom the Software is 58 | // furnished to do so, subject to the following conditions: 59 | // 60 | // The above copyright notice and this permission notice shall be included in 61 | // all copies or substantial portions of the Software. 62 | // 63 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 64 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 65 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 66 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 67 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 68 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 69 | // THE SOFTWARE. 70 | //=================================== 71 | -------------------------------------------------------------------------------- /Base/Log.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Log.h 4 | * 5 | * 6 | * By Patrick Wyatt - 5/11/2010 7 | * 8 | ***/ 9 | 10 | 11 | #ifdef LOG_H 12 | #error "Header included more than once" 13 | #endif 14 | #define LOG_H 15 | 16 | 17 | // Module init 18 | void LogInitialize (const wchar appName[], const wchar subDir[] = L""); 19 | void LogDestroy (); 20 | 21 | 22 | // Write the error message and exit application 23 | void FatalError (); 24 | void __cdecl Fatal (const char fmt[], ...); 25 | void FatalAssert (const char msg[], const char file[], int line); 26 | 27 | 28 | // Write error message 29 | void __cdecl LogError (const char fmt[], ...); 30 | void LogErrorV (const char fmt[], va_list args); 31 | 32 | 33 | // Write operating system error 34 | #define LOG_OS_ERROR(msg, error) LogOsError(msg, error, __FILE__, __LINE__) 35 | void LogOsError ( 36 | const wchar msg[], 37 | unsigned error, 38 | const char file[], 39 | int line 40 | ); 41 | 42 | #define LOG_OS_LAST_ERROR(msg) LogOsLastError(msg, __FILE__, __LINE__) 43 | void LogOsLastError ( 44 | const wchar msg[], 45 | const char file[], 46 | int line 47 | ); 48 | 49 | 50 | //=================================== 51 | // MIT License 52 | // 53 | // Copyright (c) 2010 by Patrick Wyatt 54 | // 55 | // Permission is hereby granted, free of charge, to any person obtaining a copy 56 | // of this software and associated documentation files (the "Software"), to deal 57 | // in the Software without restriction, including without limitation the rights 58 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 59 | // copies of the Software, and to permit persons to whom the Software is 60 | // furnished to do so, subject to the following conditions: 61 | // 62 | // The above copyright notice and this permission notice shall be included in 63 | // all copies or substantial portions of the Software. 64 | // 65 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 66 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 67 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 68 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 69 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 70 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 71 | // THE SOFTWARE. 72 | //=================================== 73 | -------------------------------------------------------------------------------- /Base/Mem.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Mem.h 4 | * 5 | * 6 | * By Patrick Wyatt - 5/7/2010 7 | * 8 | ***/ 9 | 10 | 11 | #ifdef MEM_H 12 | #error "Header included more than once" 13 | #endif 14 | #define MEM_H 15 | 16 | 17 | // Memory clear 18 | #define ZERO(x) memset(&x, 0, sizeof(x)) 19 | #define ZEROPTR(x) memset(x, 0, sizeof(*x)) 20 | 21 | // Simplified allocation 22 | #define ALLOC(bytes) MemAlloc(bytes, __FILE__, __LINE__) 23 | #define REALLOC(ptr, bytes) MemRealloc(ptr, bytes, __FILE__, __LINE__) 24 | 25 | // Used to allocate a structure that contains a variable length text 26 | // string at the end. Use StrChars for the "chars" field, not StrLen! 27 | #define SIZEOF_STRUCT_STRING(type, field, chars) ( \ 28 | sizeof(type) \ 29 | - sizeof(((type *) 0)->field) \ 30 | + sizeof(((type *) 0)->field[0]) * chars \ 31 | ) // 32 | 33 | // Memory allocation 34 | void MemFree (void * ptr); 35 | void * MemAlloc (size_t bytes, const char file[], int line); 36 | void * MemRealloc (void * ptr, size_t bytes, const char file[], int line); 37 | 38 | 39 | //============================================================================= 40 | inline void * MemAlloc (size_t bytes, const char file[], int line) { 41 | void * MemAllocHelper (size_t bytes, const char file[], int line); 42 | void * result = MemAllocHelper(bytes, file, line); 43 | __assume(result); 44 | return result; 45 | } 46 | 47 | //============================================================================= 48 | // new/delete 49 | inline void * operator new (unsigned bytes) { 50 | void * MemAllocHelper (size_t bytes, const char file[], int line); 51 | void * result = MemAllocHelper(bytes, __FILE__, __LINE__); 52 | __assume(result); 53 | return result; 54 | } 55 | inline void operator delete (void * p) { 56 | MemFree(p); 57 | } 58 | 59 | 60 | //=================================== 61 | // MIT License 62 | // 63 | // Copyright (c) 2010 by Patrick Wyatt 64 | // 65 | // Permission is hereby granted, free of charge, to any person obtaining a copy 66 | // of this software and associated documentation files (the "Software"), to deal 67 | // in the Software without restriction, including without limitation the rights 68 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 69 | // copies of the Software, and to permit persons to whom the Software is 70 | // furnished to do so, subject to the following conditions: 71 | // 72 | // The above copyright notice and this permission notice shall be included in 73 | // all copies or substantial portions of the Software. 74 | // 75 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 76 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 77 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 78 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 79 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 80 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 81 | // THE SOFTWARE. 82 | //=================================== 83 | -------------------------------------------------------------------------------- /Base/Macros.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Macros.h 4 | * 5 | * 6 | * By Patrick Wyatt - 5/16/2010 7 | * 8 | ***/ 9 | 10 | 11 | #ifdef MACROS_H 12 | #error "Header included more than once" 13 | #endif 14 | #define MACROS_H 15 | 16 | 17 | /****************************************************************************** 18 | * 19 | * Defines 20 | * 21 | ***/ 22 | 23 | #ifdef _DEBUG 24 | #define ASSERTIONS_ENABLED 25 | #endif 26 | 27 | 28 | /****************************************************************************** 29 | * 30 | * Utility macros 31 | * 32 | ***/ 33 | 34 | // number of elements in an array 35 | // _countof(array) -- defined in MSVC headers 36 | 37 | // size of field in a structure 38 | #define sizeof_field(type, field) sizeof(((type *) 0)->field) 39 | 40 | 41 | // Do nothing 42 | #define NULL_STMT ((void) 0) 43 | 44 | 45 | // shorter version of UNREFERENCED_PARAMETER 46 | #define REF(arg) (arg) 47 | 48 | 49 | // type definition for API classes with no implementation 50 | #define APICLASS struct __declspec(novtable) 51 | 52 | 53 | // Run-time assertion 54 | #ifdef ASSERTIONS_ENABLED 55 | #define ASSERT(x) ((x) ? 0 : FatalAssert(#x, __FILE__, __LINE__)) 56 | #define ASSERTFAST(x) ASSERT(x) 57 | #else 58 | #define ASSERT(x) ((void) 0) 59 | #define ASSERTFAST(x) __assume(x) 60 | #endif 61 | 62 | 63 | // Compile-time assertion 64 | #define CCASSERT(predicate) _x_CCASSERT_LINE(predicate, __LINE__) 65 | #define _x_CCASSERT_LINE(predicate, line) typedef char constraint_violated_on_line_##line[2*((predicate)!=0)-1]; 66 | 67 | 68 | // Output WARNINGS and NOTES during compilation 69 | #define STRING2_(x) #x 70 | #define STRING_(x) STRING2_(x) 71 | #define NOTE(msg) message (__FILE__ "[" STRING_(__LINE__) "] : note: " msg) 72 | #define WARN(msg) message (__FILE__ "[" STRING_(__LINE__) "] : warning C0000: " msg) 73 | 74 | 75 | // Swap two values 76 | template 77 | inline void swap (T & a, T & b) { 78 | T temp(a); 79 | a = b; 80 | b = temp; 81 | } 82 | 83 | 84 | //=================================== 85 | // MIT License 86 | // 87 | // Copyright (c) 2010 by Patrick Wyatt 88 | // 89 | // Permission is hereby granted, free of charge, to any person obtaining a copy 90 | // of this software and associated documentation files (the "Software"), to deal 91 | // in the Software without restriction, including without limitation the rights 92 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 93 | // copies of the Software, and to permit persons to whom the Software is 94 | // furnished to do so, subject to the following conditions: 95 | // 96 | // The above copyright notice and this permission notice shall be included in 97 | // all copies or substantial portions of the Software. 98 | // 99 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 100 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 101 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 102 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 103 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 104 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 105 | // THE SOFTWARE. 106 | //=================================== 107 | -------------------------------------------------------------------------------- /Base/Mem.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Mem.cpp 4 | * 5 | * 6 | * By Patrick Wyatt - 5/7/2010 7 | * 8 | ***/ 9 | 10 | 11 | #include "stdafx.h" 12 | #pragma hdrstop 13 | 14 | 15 | #define USE_MALLOC 16 | 17 | 18 | /****************************************************************************** 19 | * 20 | * Private 21 | * 22 | ***/ 23 | 24 | #ifndef USE_MALLOC 25 | static HANDLE s_heap; 26 | #endif 27 | 28 | //============================================================================= 29 | static void OutOfMemory () { 30 | Fatal("Out of memory"); 31 | } 32 | 33 | 34 | /****************************************************************************** 35 | * 36 | * Exports 37 | * 38 | ***/ 39 | 40 | //============================================================================= 41 | void MemFree (void * ptr) { 42 | #ifdef USE_MALLOC 43 | _free_dbg(ptr, _NORMAL_BLOCK); 44 | #else 45 | HeapFree(s_heap, 0, ptr); 46 | #endif 47 | } 48 | 49 | //============================================================================= 50 | void * MemAllocHelper (size_t bytes, const char file[], int line) { 51 | #ifdef USE_MALLOC 52 | if (void * result = _malloc_dbg(bytes, _NORMAL_BLOCK, file, line)) 53 | return result; 54 | #else 55 | REF(file); 56 | REF(line); 57 | if (!s_heap) 58 | s_heap = GetProcessHeap(); 59 | 60 | if (void * result = HeapAlloc(s_heap, 0, bytes)) 61 | return result; 62 | #endif 63 | 64 | OutOfMemory(); 65 | return NULL; 66 | } 67 | 68 | //============================================================================= 69 | void * MemRealloc (void * ptr, size_t bytes, const char file[], int line) { 70 | #ifdef USE_MALLOC 71 | if (void * result = _realloc_dbg(ptr, bytes, _NORMAL_BLOCK, file, line)) 72 | return result; 73 | #else 74 | REF(file); 75 | REF(line); 76 | if (!s_heap) 77 | s_heap = GetProcessHeap(); 78 | 79 | if (void * result = HeapReAlloc(s_heap, 0, ptr, bytes)) 80 | return result; 81 | #endif 82 | OutOfMemory(); 83 | return NULL; 84 | } 85 | 86 | 87 | //=================================== 88 | // MIT License 89 | // 90 | // Copyright (c) 2010 by Patrick Wyatt 91 | // 92 | // Permission is hereby granted, free of charge, to any person obtaining a copy 93 | // of this software and associated documentation files (the "Software"), to deal 94 | // in the Software without restriction, including without limitation the rights 95 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 96 | // copies of the Software, and to permit persons to whom the Software is 97 | // furnished to do so, subject to the following conditions: 98 | // 99 | // The above copyright notice and this permission notice shall be included in 100 | // all copies or substantial portions of the Software. 101 | // 102 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 103 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 104 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 105 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 106 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 107 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 108 | // THE SOFTWARE. 109 | //=================================== 110 | -------------------------------------------------------------------------------- /Base/Str.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Str.h 4 | * 5 | * 6 | * By Patrick Wyatt - 5/6/2010 7 | * 8 | ***/ 9 | 10 | 11 | #ifdef MYSTR_H 12 | #error "Header included more than once" 13 | #endif 14 | #define MYSTR_H 15 | 16 | 17 | void __cdecl StrPrintf ( 18 | char * dstBuf, 19 | size_t dstChars, 20 | const char format[], 21 | ... 22 | ); 23 | void __cdecl StrPrintf ( 24 | wchar * dstBuf, 25 | size_t dstChars, 26 | const wchar format[], 27 | ... 28 | ); 29 | 30 | 31 | void StrPrintfV ( 32 | char * dstBuf, 33 | size_t dstChars, 34 | const char format[], 35 | va_list args 36 | ); 37 | void StrPrintfV ( 38 | wchar * dstBuf, 39 | size_t dstChars, 40 | const wchar format[], 41 | va_list args 42 | ); 43 | 44 | 45 | // String copy 46 | void StrCopy ( char * dstBuf, size_t dstChars, const char srcBuf[]); 47 | void StrCopy (wchar * dstBuf, size_t dstChars, const wchar srcBuf[]); 48 | 49 | size_t StrCopyLen ( char * dstBuf, size_t dstChars, const char srcBuf[]); 50 | size_t StrCopyLen (wchar * dstBuf, size_t dstChars, const wchar srcBuf[]); 51 | 52 | 53 | // Number of characters of string *EXCLUDING* the terminating NULL: strlen() 54 | size_t StrLen (const char str[]); 55 | size_t StrLen (const wchar str[]); 56 | 57 | // Number of characters of string *INCLUDING* the terminating NULL: strlen() + 1 58 | size_t StrChars (const char str[]); 59 | size_t StrChars (const wchar str[]); 60 | 61 | // Number of characters of string *INCLUDING* the terminating NULL: (strlen() + 1) * sizeof(str[0]) 62 | size_t StrBytes (const char str[]); 63 | size_t StrBytes (const wchar str[]); 64 | 65 | 66 | // Unicode <-> Ansi conversion 67 | void StrUnicodeToAnsi (char * dstBuf, size_t dstChars, const wchar srcBuf[]); 68 | void StrAnsiToUnicode (wchar * dstBuf, size_t dstChars, const char srcBuf[]); 69 | 70 | 71 | // String duplication functions 72 | char * StrDupAnsi (const char str[]); // use MemFree to relase 73 | wchar * StrDupWide (const wchar str[]); // use MemFree to relase 74 | 75 | wchar * StrDupAnsiToWide (const char str[]); // use MemFree to relase 76 | char * StrDupWideToAnsi (const wchar str[]); // use MemFree to relase 77 | 78 | 79 | //=================================== 80 | // MIT License 81 | // 82 | // Copyright (c) 2010 by Patrick Wyatt 83 | // 84 | // Permission is hereby granted, free of charge, to any person obtaining a copy 85 | // of this software and associated documentation files (the "Software"), to deal 86 | // in the Software without restriction, including without limitation the rights 87 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 88 | // copies of the Software, and to permit persons to whom the Software is 89 | // furnished to do so, subject to the following conditions: 90 | // 91 | // The above copyright notice and this permission notice shall be included in 92 | // all copies or substantial portions of the Software. 93 | // 94 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 95 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 96 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 97 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 98 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 99 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 100 | // THE SOFTWARE. 101 | //=================================== 102 | -------------------------------------------------------------------------------- /Base/Debug.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Debug.cpp 4 | * 5 | * 6 | * By Patrick Wyatt - 5/20/2010 7 | * 8 | ***/ 9 | 10 | 11 | #include "stdafx.h" 12 | #pragma hdrstop 13 | 14 | 15 | /****************************************************************************** 16 | * 17 | * Private 18 | * 19 | ***/ 20 | 21 | // Validate Types.h definitions 22 | CCASSERT(sizeof(i8) == 1); 23 | CCASSERT(sizeof(u8) == 1); 24 | CCASSERT(sizeof(i16) == 2); 25 | CCASSERT(sizeof(u16) == 2); 26 | CCASSERT(sizeof(i32) == 4); 27 | CCASSERT(sizeof(u32) == 4); 28 | CCASSERT(sizeof(i64) == 8); 29 | CCASSERT(sizeof(u64) == 8); 30 | 31 | 32 | // Definitions for DebugSetThreadName 33 | #define MS_VC_EXCEPTION 0x406D1388 34 | 35 | #pragma pack(push,8) 36 | typedef struct { 37 | DWORD dwType; // Must be 0x1000. 38 | LPCSTR szName; // Pointer to name (in user addr space). 39 | DWORD dwThreadID; // Thread ID (-1=caller thread). 40 | DWORD dwFlags; // Reserved for future use, must be zero. 41 | } THREADNAME_INFO; 42 | #pragma pack(pop) 43 | 44 | 45 | /****************************************************************************** 46 | * 47 | * Exports 48 | * 49 | ***/ 50 | 51 | //============================================================================= 52 | void __cdecl DebugMsg (const char fmt[], ...) { 53 | va_list args; 54 | va_start(args, fmt); 55 | DebugMsgV(fmt, args); 56 | va_end(args); 57 | } 58 | 59 | //============================================================================= 60 | void DebugMsgV (const char fmt[], va_list args) { 61 | char msg[512]; 62 | StrPrintfV(msg, _countof(msg), fmt, args); 63 | OutputDebugStringA(msg); 64 | } 65 | 66 | //============================================================================= 67 | void DebugSetThreadName (const char name[], unsigned threadId) { 68 | THREADNAME_INFO info; 69 | info.dwType = 0x1000; 70 | info.szName = name; 71 | info.dwThreadID = threadId ? threadId : GetCurrentThreadId(); 72 | info.dwFlags = 0; 73 | 74 | __try { 75 | RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(unsigned long *), (unsigned long *) &info); 76 | } 77 | __except(EXCEPTION_EXECUTE_HANDLER) { 78 | // oh well ... 79 | } 80 | } 81 | 82 | 83 | //=================================== 84 | // MIT License 85 | // 86 | // Copyright (c) 2010 by Patrick Wyatt 87 | // 88 | // Permission is hereby granted, free of charge, to any person obtaining a copy 89 | // of this software and associated documentation files (the "Software"), to deal 90 | // in the Software without restriction, including without limitation the rights 91 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 92 | // copies of the Software, and to permit persons to whom the Software is 93 | // furnished to do so, subject to the following conditions: 94 | // 95 | // The above copyright notice and this permission notice shall be included in 96 | // all copies or substantial portions of the Software. 97 | // 98 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 99 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 100 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 101 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 102 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 103 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 104 | // THE SOFTWARE. 105 | //=================================== 106 | -------------------------------------------------------------------------------- /Base/Path.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Path.cpp 4 | * 5 | * 6 | * By Patrick Wyatt - 5/6/2010 7 | * 8 | ***/ 9 | 10 | 11 | #include "stdafx.h" 12 | #pragma hdrstop 13 | 14 | 15 | /****************************************************************************** 16 | * 17 | * Private 18 | * 19 | ***/ 20 | 21 | #pragma comment(lib, "shlwapi") 22 | 23 | 24 | /****************************************************************************** 25 | * 26 | * Exports 27 | * 28 | ***/ 29 | 30 | //============================================================================= 31 | void PathGetExeFullPath (wchar * path, unsigned chars) { 32 | unsigned result = GetModuleFileNameW(NULL, path, chars); 33 | if (result >= chars) 34 | path[0] = 0; 35 | } 36 | 37 | //============================================================================= 38 | void PathGetExeFileName (wchar * path, unsigned chars) { 39 | PathGetExeFullPath(path, chars); 40 | 41 | wchar * filename = PathFindFileNameW(path); 42 | if (filename != path) 43 | memmove(path, filename, StrBytes(filename)); 44 | } 45 | 46 | //============================================================================= 47 | void PathRemoveFileName (wchar * path, unsigned chars, const wchar src[]) { 48 | ASSERT(chars >= MAX_PATH); 49 | 50 | if (path != src) 51 | StrCopy(path, chars, src); 52 | PathRemoveFileSpecW(path); 53 | } 54 | 55 | //============================================================================= 56 | void PathRemovePath (wchar * path, unsigned chars, const wchar src[]) { 57 | ASSERT(chars >= MAX_PATH); 58 | 59 | if (path != src) 60 | StrCopy(path, chars, src); 61 | PathStripPathW(path); 62 | } 63 | 64 | //============================================================================= 65 | void PathGetProgramDirectory (wchar * path, unsigned chars) { 66 | PathGetExeFullPath(path, chars); 67 | 68 | // Trim the filename from path to get the directory 69 | wchar * filename = PathFindFileNameW(path); 70 | if (filename != path) 71 | filename[0] = 0; 72 | } 73 | 74 | //============================================================================= 75 | void PathSetProgramDirectory () { 76 | wchar path[MAX_PATH]; 77 | PathGetProgramDirectory(path, _countof(path)); 78 | if (!SetCurrentDirectoryW(path)) { 79 | LOG_OS_LAST_ERROR(L"SetCurrentDirectoryW"); 80 | FatalError(); 81 | } 82 | } 83 | 84 | //============================================================================= 85 | bool PathCreateDirectory (const wchar directory[]) { 86 | for (;;) { 87 | if (CreateDirectoryW(directory, NULL)) 88 | break; 89 | 90 | if (GetLastError() == ERROR_ALREADY_EXISTS) { 91 | if (PathIsDirectoryW(directory)) 92 | break; 93 | } 94 | 95 | LOG_OS_LAST_ERROR(L"CreateDirectoryW"); 96 | return false; 97 | } 98 | 99 | return true; 100 | } 101 | 102 | 103 | //=================================== 104 | // MIT License 105 | // 106 | // Copyright (c) 2010 by Patrick Wyatt 107 | // 108 | // Permission is hereby granted, free of charge, to any person obtaining a copy 109 | // of this software and associated documentation files (the "Software"), to deal 110 | // in the Software without restriction, including without limitation the rights 111 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 112 | // copies of the Software, and to permit persons to whom the Software is 113 | // furnished to do so, subject to the following conditions: 114 | // 115 | // The above copyright notice and this permission notice shall be included in 116 | // all copies or substantial portions of the Software. 117 | // 118 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 119 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 120 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 121 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 122 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 123 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 124 | // THE SOFTWARE. 125 | //=================================== 126 | -------------------------------------------------------------------------------- /Test/Service/Main.cpp: -------------------------------------------------------------------------------- 1 | /************************************ 2 | * 3 | * App.cpp 4 | * 5 | * 6 | * By Patrick Wyatt - 5/14/2010 7 | * 8 | ***/ 9 | 10 | 11 | #include "stdafx.h" 12 | #pragma hdrstop 13 | 14 | #pragma comment(lib, "base.lib") 15 | #pragma comment(lib, "srvlib.lib") 16 | 17 | 18 | /************************************ 19 | * 20 | * Private 21 | * 22 | ***/ 23 | 24 | class CServiceApp : public CApplication { 25 | private: 26 | HANDLE m_shutdownEvt; 27 | 28 | public: 29 | CServiceApp (); 30 | virtual ~CServiceApp (); 31 | 32 | // Application config 33 | const wchar * Name () const; 34 | const wchar * Description () const; 35 | 36 | 37 | // Application run 38 | void Start (CServiceStatus * status); 39 | void Run (bool serviceMode); 40 | void SignalStop (); 41 | void Stop (); 42 | int ExitCode () const; 43 | }; 44 | 45 | 46 | static CServiceApp s_app; 47 | 48 | 49 | //=================================== 50 | CServiceApp::CServiceApp () 51 | : m_shutdownEvt(NULL) 52 | {} 53 | 54 | 55 | //=================================== 56 | CServiceApp::~CServiceApp () { 57 | if (m_shutdownEvt) 58 | CloseHandle(m_shutdownEvt); 59 | } 60 | 61 | 62 | //=================================== 63 | const wchar * CServiceApp::Name () const { 64 | return L"aSrv"; 65 | } 66 | 67 | 68 | //=================================== 69 | const wchar * CServiceApp::Description () const { 70 | return L"A sample server"; 71 | } 72 | 73 | 74 | //=================================== 75 | void CServiceApp::Start (CServiceStatus *) { 76 | m_shutdownEvt = CreateEvent(NULL, true, false, NULL); 77 | } 78 | 79 | 80 | //=================================== 81 | void CServiceApp::Run (bool serviceMode) { 82 | LogError("Running as %s\n", serviceMode ? "service" : "application"); 83 | WaitForSingleObject(m_shutdownEvt, INFINITE); 84 | } 85 | 86 | 87 | //=================================== 88 | void CServiceApp::SignalStop () { 89 | SetEvent(m_shutdownEvt); 90 | } 91 | 92 | 93 | //=================================== 94 | // An alternate implementation of the game loop 95 | // static bool s_shutdown; 96 | // void CServiceApp::Start (CServiceStatus *) { 97 | // s_shutdown = false; 98 | // } 99 | // void CServiceApp::Run (bool serviceMode) { 100 | // LogError("Running as %s\n", serviceMode ? "service" : "application"); 101 | // while (!s_shutdown) 102 | // DoImportantGameRelatedStuff(); 103 | // } 104 | // void CServiceApp::SignalStop () { 105 | // s_shutdown = true; 106 | // } 107 | 108 | 109 | //=================================== 110 | void CServiceApp::Stop () { 111 | // empty 112 | } 113 | 114 | 115 | //=================================== 116 | int CServiceApp::ExitCode () const { 117 | // Success! 118 | return 0; 119 | } 120 | 121 | 122 | /************************************ 123 | * 124 | * Exports 125 | * 126 | ***/ 127 | 128 | //=================================== 129 | #ifdef _CONSOLE 130 | int __cdecl _tmain(int, _TCHAR**) { 131 | return ServiceMain(&s_app); 132 | } 133 | #else 134 | int WINAPI WinMain (HINSTANCE, HINSTANCE, LPSTR, int) { 135 | return ServiceMain(&s_app); 136 | } 137 | #endif 138 | 139 | 140 | //=================================== 141 | // MIT License 142 | // 143 | // Copyright (c) 2010 by Patrick Wyatt 144 | // 145 | // Permission is hereby granted, free of charge, to any person obtaining a copy 146 | // of this software and associated documentation files (the "Software"), to deal 147 | // in the Software without restriction, including without limitation the rights 148 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 149 | // copies of the Software, and to permit persons to whom the Software is 150 | // furnished to do so, subject to the following conditions: 151 | // 152 | // The above copyright notice and this permission notice shall be included in 153 | // all copies or substantial portions of the Software. 154 | // 155 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 156 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 157 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 158 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 159 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 160 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 161 | // THE SOFTWARE. 162 | //=================================== 163 | -------------------------------------------------------------------------------- /Lib/SrvLib/SrvLib.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {7902CF80-F1D1-4066-890F-E02692454A89} 15 | Win32Proj 16 | SrvLib 17 | 18 | 19 | 20 | StaticLibrary 21 | true 22 | Unicode 23 | 24 | 25 | StaticLibrary 26 | false 27 | true 28 | Unicode 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | Use 44 | Level3 45 | Disabled 46 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) 47 | ../.. 48 | 49 | 50 | Windows 51 | true 52 | 53 | 54 | 55 | 56 | Level3 57 | Use 58 | MaxSpeed 59 | true 60 | true 61 | WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) 62 | ../.. 63 | 64 | 65 | Windows 66 | true 67 | true 68 | true 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | Create 87 | Create 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /Base/Task.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Task.cpp 4 | * 5 | * 6 | * By Patrick Wyatt - 5/19/2010 7 | * 8 | ***/ 9 | 10 | 11 | #include "stdafx.h" 12 | #pragma hdrstop 13 | 14 | 15 | /****************************************************************************** 16 | * 17 | * Private 18 | * 19 | ***/ 20 | 21 | 22 | static HANDLE s_completionPort; 23 | static long s_taskThreads; 24 | 25 | 26 | //============================================================================= 27 | static unsigned __stdcall TaskThreadProc (void *) { 28 | DebugSetThreadName("Task"); 29 | 30 | for (;;) { 31 | // Get the next task completion 32 | DWORD bytes; 33 | DWORD key; 34 | OVERLAPPED * olap; 35 | if (!GetQueuedCompletionStatus( 36 | s_completionPort, 37 | &bytes, 38 | &key, 39 | &olap, 40 | INFINITE 41 | )) { 42 | LOG_OS_LAST_ERROR(L"GetQueuedCompletionStatus"); 43 | continue; 44 | } 45 | 46 | // If the task is NULL this is a thread-quit notification 47 | if (!key) 48 | break; 49 | 50 | // Dispatch event 51 | CTask * task = (CTask *) key; 52 | task->TaskComplete(bytes, olap); 53 | } 54 | 55 | InterlockedDecrement(&s_taskThreads); 56 | return 0; 57 | } 58 | 59 | 60 | /****************************************************************************** 61 | * 62 | * Exports 63 | * 64 | ***/ 65 | 66 | //============================================================================= 67 | void TaskInitialize () { 68 | if (NULL == (s_completionPort = CreateIoCompletionPort( 69 | INVALID_HANDLE_VALUE, 70 | NULL, 71 | NULL, 72 | 0 73 | ))) { 74 | LOG_OS_LAST_ERROR(L"CreateIoCompletionPort"); 75 | FatalError(); 76 | } 77 | 78 | HANDLE thread; 79 | unsigned threadId; 80 | if (NULL == (thread = (HANDLE) _beginthreadex( 81 | (LPSECURITY_ATTRIBUTES) NULL, 82 | 0, // default stack size 83 | TaskThreadProc, 84 | NULL, 85 | 0, // flags 86 | &threadId 87 | ))) { 88 | LOG_OS_LAST_ERROR(L"_beginthreadex"); 89 | FatalError(); 90 | } 91 | CloseHandle(thread); // TODO: Keep in an array and use instead of sleeping on s_taskThreads on exit 92 | InterlockedIncrement(&s_taskThreads); 93 | } 94 | 95 | //============================================================================= 96 | void TaskDestroy () { 97 | while (volatile long count = s_taskThreads) { 98 | PostQueuedCompletionStatus(s_completionPort, 0, 0, 0); 99 | while (count == s_taskThreads) 100 | Sleep(1); 101 | } 102 | 103 | if (s_completionPort) { 104 | CloseHandle(s_completionPort); 105 | s_completionPort = NULL; 106 | } 107 | } 108 | 109 | //============================================================================= 110 | void TaskRegisterHandle ( 111 | CTask * task, 112 | HANDLE handle 113 | ) { 114 | ASSERT(task); 115 | if (task && !CreateIoCompletionPort(handle, s_completionPort, (DWORD) task, 0)) { 116 | LOG_OS_LAST_ERROR(L"CreateIoCompletionPort"); 117 | FatalError(); 118 | } 119 | } 120 | 121 | 122 | //=================================== 123 | // MIT License 124 | // 125 | // Copyright (c) 2010 by Patrick Wyatt 126 | // 127 | // Permission is hereby granted, free of charge, to any person obtaining a copy 128 | // of this software and associated documentation files (the "Software"), to deal 129 | // in the Software without restriction, including without limitation the rights 130 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 131 | // copies of the Software, and to permit persons to whom the Software is 132 | // furnished to do so, subject to the following conditions: 133 | // 134 | // The above copyright notice and this permission notice shall be included in 135 | // all copies or substantial portions of the Software. 136 | // 137 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 138 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 139 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 140 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 141 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 142 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 143 | // THE SOFTWARE. 144 | //=================================== 145 | -------------------------------------------------------------------------------- /Test/List/List.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {E076C6AF-49DB-4E13-92F1-02A38D94ABAD} 15 | Win32Proj 16 | List 17 | 18 | 19 | 20 | Application 21 | true 22 | Unicode 23 | 24 | 25 | Application 26 | false 27 | true 28 | Unicode 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | true 42 | 43 | 44 | false 45 | 46 | 47 | 48 | Use 49 | Level3 50 | Disabled 51 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 52 | 53 | 54 | Console 55 | true 56 | 57 | 58 | 59 | 60 | Level3 61 | Use 62 | MaxSpeed 63 | true 64 | true 65 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 66 | 67 | 68 | Console 69 | true 70 | true 71 | true 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | Create 85 | Create 86 | 87 | 88 | 89 | 90 | {2e31a4e1-59f9-47ed-ac3b-c6a30e17c7b2} 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /Test/Service/Service.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {7A017E47-91B5-4227-A84B-93948E6AA178} 15 | Win32Proj 16 | Service 17 | 18 | 19 | 20 | Application 21 | true 22 | Unicode 23 | 24 | 25 | Application 26 | false 27 | true 28 | Unicode 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | true 42 | 43 | 44 | false 45 | 46 | 47 | 48 | Use 49 | Level3 50 | Disabled 51 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 52 | 53 | 54 | Windows 55 | true 56 | 57 | 58 | 59 | 60 | Level3 61 | Use 62 | MaxSpeed 63 | true 64 | true 65 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 66 | 67 | 68 | Windows 69 | true 70 | true 71 | true 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | Create 82 | Create 83 | 84 | 85 | 86 | 87 | {2e31a4e1-59f9-47ed-ac3b-c6a30e17c7b2} 88 | 89 | 90 | {7902cf80-f1d1-4066-890f-e02692454a89} 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /Base/Log.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Log.cpp 4 | * 5 | * 6 | * By Patrick Wyatt - 5/11/2010 7 | * 8 | ***/ 9 | 10 | 11 | #include "stdafx.h" 12 | #pragma hdrstop 13 | 14 | 15 | /****************************************************************************** 16 | * 17 | * Private 18 | * 19 | ***/ 20 | 21 | static FILE * s_log; 22 | 23 | 24 | /****************************************************************************** 25 | * 26 | * Logging 27 | * 28 | ***/ 29 | 30 | //============================================================================= 31 | void LogInitialize (const wchar appName[], const wchar subDir[]) { 32 | wchar path[MAX_PATH]; 33 | PathGetProgramDirectory(path, _countof(path)); 34 | PathAppendW(path, subDir); 35 | if (!PathCreateDirectory(path)) 36 | FatalError(); 37 | 38 | PathAppendW(path, L"Error.log"); 39 | _wfopen_s(&s_log, path, L"a+"); 40 | LogError( 41 | "Log opened, %S, %d\n", 42 | appName, 43 | GetCurrentProcessId() 44 | ); 45 | } 46 | 47 | //============================================================================= 48 | void LogDestroy () { 49 | if (s_log) { 50 | fclose(s_log); 51 | s_log = NULL; 52 | } 53 | } 54 | 55 | //============================================================================= 56 | void FatalError () { 57 | if (_set_error_mode(_REPORT_ERRMODE) == _OUT_TO_MSGBOX) { 58 | wchar path[MAX_PATH]; 59 | PathGetExeFileName(path, _countof(path)); 60 | if (IDCANCEL == MessageBoxW( 61 | NULL, 62 | L"Fatal error", 63 | path, 64 | MB_OKCANCEL | MB_ICONHAND | MB_TASKMODAL)) 65 | DebugBreak(); 66 | } 67 | 68 | LogDestroy(); 69 | ExitProcess(1); 70 | } 71 | 72 | //============================================================================= 73 | void __cdecl Fatal (const char fmt[], ...) { 74 | va_list args; 75 | va_start(args, fmt); 76 | LogErrorV(fmt, args); 77 | va_end(args); 78 | FatalError(); 79 | } 80 | 81 | //============================================================================= 82 | void FatalAssert (const char msg[], const char file[], int line) { 83 | Fatal("Assert failed (%s:%d): %s\n", file, line, msg); 84 | } 85 | 86 | //============================================================================= 87 | void LogErrorV (const char fmt[], va_list args) { 88 | if (!s_log) 89 | return; 90 | 91 | SYSTEMTIME time; 92 | GetSystemTime(&time); 93 | fprintf( 94 | s_log, 95 | "%02u:%02u:%02u ", 96 | time.wHour, 97 | time.wMinute, 98 | time.wSecond 99 | ); 100 | vfprintf( 101 | s_log, 102 | fmt, 103 | args 104 | ); 105 | } 106 | 107 | //============================================================================= 108 | void __cdecl LogError (const char fmt[], ...) { 109 | va_list args; 110 | va_start(args, fmt); 111 | LogErrorV(fmt, args); 112 | va_end(args); 113 | } 114 | 115 | //============================================================================= 116 | void LogOsError (const wchar msg[], unsigned error, const char file[], int line) { 117 | LogError("Err, %S, %u, %s, %d\n", msg, error, file, line); 118 | } 119 | 120 | //============================================================================= 121 | void LogOsLastError (const wchar msg[], const char file[], int line) { 122 | LogOsError(msg, GetLastError(), file, line); 123 | } 124 | 125 | 126 | //=================================== 127 | // MIT License 128 | // 129 | // Copyright (c) 2010 by Patrick Wyatt 130 | // 131 | // Permission is hereby granted, free of charge, to any person obtaining a copy 132 | // of this software and associated documentation files (the "Software"), to deal 133 | // in the Software without restriction, including without limitation the rights 134 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 135 | // copies of the Software, and to permit persons to whom the Software is 136 | // furnished to do so, subject to the following conditions: 137 | // 138 | // The above copyright notice and this permission notice shall be included in 139 | // all copies or substantial portions of the Software. 140 | // 141 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 142 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 143 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 144 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 145 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 146 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 147 | // THE SOFTWARE. 148 | //=================================== 149 | -------------------------------------------------------------------------------- /Test/LogDeadlock/LogDeadlock/LogDeadlock.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {204B37E9-92D1-4AF8-AA72-9547A4577FD0} 15 | Win32Proj 16 | LogDeadlock 17 | 18 | 19 | 20 | Application 21 | true 22 | Unicode 23 | 24 | 25 | Application 26 | false 27 | true 28 | Unicode 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | true 42 | 43 | 44 | false 45 | 46 | 47 | 48 | Use 49 | Level3 50 | Disabled 51 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 52 | $(SolutionDir)\..\..\Base 53 | 54 | 55 | Console 56 | true 57 | 58 | 59 | 60 | 61 | Level3 62 | Use 63 | MaxSpeed 64 | true 65 | true 66 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 67 | $(SolutionDir)\..\..\Base 68 | 69 | 70 | Console 71 | true 72 | true 73 | true 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | Create 87 | Create 88 | 89 | 90 | 91 | 92 | {2e31a4e1-59f9-47ed-ac3b-c6a30e17c7b2} 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /Base/Base.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {2E31A4E1-59F9-47ED-AC3B-C6A30E17C7B2} 15 | Win32Proj 16 | Base 17 | 18 | 19 | 20 | StaticLibrary 21 | true 22 | Unicode 23 | 24 | 25 | StaticLibrary 26 | false 27 | true 28 | Unicode 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | Use 44 | Level3 45 | Disabled 46 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) 47 | 48 | 49 | 50 | 51 | Windows 52 | true 53 | 54 | 55 | 56 | 57 | Level3 58 | Use 59 | MaxSpeed 60 | true 61 | true 62 | WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) 63 | 64 | 65 | Windows 66 | true 67 | true 68 | true 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | Create 96 | Create 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /Lib/SrvLib/MainWnd.cpp: -------------------------------------------------------------------------------- 1 | /************************************ 2 | * 3 | * MainWnd.cpp 4 | * 5 | * 6 | * By Patrick Wyatt - 5/17/2010 7 | * 8 | ***/ 9 | 10 | 11 | #include "stdafx.h" 12 | #pragma hdrstop 13 | 14 | 15 | /************************************ 16 | * 17 | * Private 18 | * 19 | ***/ 20 | 21 | 22 | struct MainWndParam { 23 | HANDLE shutdownEvt; 24 | wchar wndCaption[64]; 25 | }; 26 | 27 | 28 | static HANDLE s_msgThread; 29 | static HANDLE s_shutdownEvt; 30 | 31 | 32 | //=================================== 33 | static LRESULT CALLBACK MainWndProc ( 34 | HWND wnd, 35 | UINT msg, 36 | WPARAM wp, 37 | LPARAM lp 38 | ) { 39 | switch (msg) { 40 | case WM_CLOSE: 41 | DestroyWindow(wnd); 42 | break; 43 | 44 | case WM_DESTROY: 45 | ServiceSignalStop(); 46 | break; 47 | 48 | default: 49 | return DefWindowProc(wnd, msg, wp, lp); 50 | } 51 | 52 | return 0; 53 | } 54 | 55 | 56 | //=================================== 57 | static void MainWndCreate (const wchar name[]) { 58 | // Register window class 59 | WNDCLASSW wc; 60 | ZERO(wc); 61 | wc.style = CS_HREDRAW | CS_VREDRAW; 62 | wc.lpfnWndProc = MainWndProc; 63 | wc.hInstance = GetModuleHandle(NULL); 64 | wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); 65 | wc.lpszClassName = name; 66 | if (!RegisterClassW(&wc)) { 67 | LOG_OS_LAST_ERROR(L"RegisterClassW"); 68 | FatalError(); 69 | } 70 | 71 | // Create window 72 | HWND wnd; 73 | if (NULL == (wnd = CreateWindowW( 74 | name, 75 | name, 76 | WS_OVERLAPPEDWINDOW, 77 | CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 78 | (HWND) NULL, 79 | (HMENU) NULL, 80 | wc.hInstance, 81 | NULL 82 | ))) { 83 | LOG_OS_LAST_ERROR(L"CreateWindowW"); 84 | FatalError(); 85 | } 86 | 87 | ShowWindow(wnd, SW_SHOWNORMAL); 88 | } 89 | 90 | 91 | //=================================== 92 | static unsigned __stdcall MainWndThreadProc (void * p) { 93 | DebugSetThreadName("MainWnd"); 94 | 95 | // Initialize window from parameter 96 | HANDLE shutdownEvt; 97 | { 98 | const MainWndParam & param = * (MainWndParam *) p; 99 | shutdownEvt = param.shutdownEvt; 100 | MainWndCreate(param.wndCaption); 101 | MemFree(p); 102 | p = NULL; 103 | } 104 | 105 | for (;;) { 106 | // Wait for a message or shutdown-signal 107 | switch (MsgWaitForMultipleObjects( 108 | 1, 109 | &shutdownEvt, 110 | false, 111 | INFINITE, 112 | QS_ALLINPUT 113 | )) { 114 | case WAIT_FAILED: 115 | LOG_OS_LAST_ERROR(L"MsgWaitForMultipleObjects"); 116 | return 0; 117 | 118 | case WAIT_OBJECT_0: 119 | // shutdown event fired 120 | return 0; 121 | 122 | default: 123 | break; 124 | } 125 | 126 | // Process all messages in the queue 127 | MSG msg; 128 | while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { 129 | TranslateMessage(&msg); 130 | DispatchMessage(&msg); 131 | } 132 | } 133 | } 134 | 135 | 136 | /************************************ 137 | * 138 | * Exports 139 | * 140 | ***/ 141 | 142 | 143 | //=================================== 144 | void MainWndInitialize (const wchar name[]) { 145 | // Allocate window parameter 146 | unsigned chars = StrChars(name); 147 | MainWndParam * param = (MainWndParam *) ALLOC(sizeof(*param)); 148 | StrCopy(param->wndCaption, _countof(param->wndCaption), name); 149 | 150 | // Create an event to signal shutdown 151 | s_shutdownEvt = param->shutdownEvt = CreateEvent( 152 | (LPSECURITY_ATTRIBUTES) NULL, 153 | true, // manual reset event 154 | false, // initial state 155 | NULL // name 156 | ); 157 | if (!param->shutdownEvt) { 158 | LOG_OS_LAST_ERROR(L"CreateEvent"); 159 | FatalError(); 160 | } 161 | 162 | // Create event pump thread 163 | unsigned threadId; 164 | if (NULL == (s_msgThread = (HANDLE) _beginthreadex( 165 | (LPSECURITY_ATTRIBUTES) NULL, 166 | 0, // default stack size 167 | MainWndThreadProc, 168 | param, 169 | 0, // flags 170 | &threadId 171 | ))) { 172 | LOG_OS_LAST_ERROR(L"_beginthreadex"); 173 | FatalError(); 174 | } 175 | } 176 | 177 | 178 | //=================================== 179 | void MainWndDestroy () { 180 | // Signal the message thread to shut down 181 | if (s_shutdownEvt) { 182 | SetEvent(s_shutdownEvt); 183 | s_shutdownEvt = NULL; 184 | } 185 | 186 | // Wait for message thread 187 | if (s_msgThread) { 188 | WaitForSingleObject(s_msgThread, INFINITE); 189 | CloseHandle(s_msgThread); 190 | s_msgThread = NULL; 191 | } 192 | } 193 | 194 | 195 | //=================================== 196 | // MIT License 197 | // 198 | // Copyright (c) 2010 by Patrick Wyatt 199 | // 200 | // Permission is hereby granted, free of charge, to any person obtaining a copy 201 | // of this software and associated documentation files (the "Software"), to deal 202 | // in the Software without restriction, including without limitation the rights 203 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 204 | // copies of the Software, and to permit persons to whom the Software is 205 | // furnished to do so, subject to the following conditions: 206 | // 207 | // The above copyright notice and this permission notice shall be included in 208 | // all copies or substantial portions of the Software. 209 | // 210 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 211 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 212 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 213 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 214 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 215 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 216 | // THE SOFTWARE. 217 | //=================================== 218 | -------------------------------------------------------------------------------- /Base/Timer.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Timer.cpp 4 | * 5 | * 6 | * By Patrick Wyatt - 11/19/2011 7 | * 8 | ***/ 9 | 10 | 11 | #include "stdafx.h" 12 | #pragma hdrstop 13 | 14 | #if 0 15 | 16 | 17 | /****************************************************************************** 18 | * 19 | * Private 20 | * 21 | ***/ 22 | 23 | static const unsigned MAX_SLEEP_MS = 5 * 1000; 24 | 25 | static const unsigned TIMER_FLAG_QUEUED = 1; 26 | 27 | 28 | struct Timer : public ITimer { 29 | ITimerCallback * m_callback; 30 | unsigned m_nextTimeMs; 31 | unsigned m_flags; 32 | 33 | virtual void Delete (); 34 | virtual void Set (__in unsigned sleepMs); 35 | 36 | bool operator < (const Timer & t) const; 37 | }; 38 | 39 | 40 | static HANDLE s_completionPort; 41 | static HANDLE s_timerThread; 42 | static CCritSect s_critsect; 43 | 44 | static SOME_PRIORITY_QUEUE_THING s_timerQ; 45 | 46 | 47 | 48 | /****************************************************************************** 49 | * 50 | * Timer object 51 | * 52 | ***/ 53 | 54 | //============================================================================= 55 | void Timer::Delete () { 56 | s_critsect.Enter(); 57 | if (m_flags & TIMER_FLAG_QUEUED) { 58 | m_flags &= ~TIMER_FLAG_QUEUED; 59 | s_timerQ._Get_container().erase(*this); 60 | } 61 | s_critsect.Leave(); 62 | } 63 | 64 | //============================================================================= 65 | void Timer::Set (__in unsigned sleepMs) { 66 | unsigned nextTimeMs = TimeGetMs() + sleepMs; 67 | 68 | s_critsect.Enter(); 69 | { 70 | if (m_flags & TIMER_FLAG_QUEUED) { 71 | m_flags &= ~TIMER_FLAG_QUEUED; 72 | s_timerQ.remove(*this); 73 | } 74 | if (sleepMs != TIMER_INFINITE_MS) { 75 | m_flags |= TIMER_FLAG_QUEUED; 76 | s_timerQ.add(*this); 77 | } 78 | } 79 | s_critsect.Leave(); 80 | } 81 | 82 | //============================================================================= 83 | bool Timer::operator< (const Timer & t) const { 84 | return (m_nextTimeMs - t.m_nextTimeMs) < 0; 85 | } 86 | 87 | 88 | /****************************************************************************** 89 | * 90 | * Timer thread 91 | * 92 | ***/ 93 | 94 | //============================================================================= 95 | static unsigned __stdcall TimerThreadProc (void *) { 96 | DebugSetThreadName("Timer"); 97 | 98 | unsigned sleepMs = MAX_SLEEP_MS; 99 | for (;;) { 100 | // Get the next task completion 101 | DWORD bytes; 102 | DWORD key; 103 | OVERLAPPED * olap; 104 | if (!GetQueuedCompletionStatus( 105 | s_completionPort, 106 | &bytes, 107 | &key, 108 | &olap, 109 | sleepMs 110 | )) { 111 | LOG_OS_LAST_ERROR(L"GetQueuedCompletionStatus"); 112 | FatalError(); 113 | } 114 | 115 | // If the task is NULL this is a thread-quit notification 116 | if (!key) 117 | break; 118 | 119 | } 120 | 121 | return 0; 122 | } 123 | 124 | 125 | /****************************************************************************** 126 | * 127 | * Exports 128 | * 129 | ***/ 130 | 131 | //============================================================================= 132 | void TimerInitialize () { 133 | if (NULL == (s_completionPort = CreateIoCompletionPort( 134 | INVALID_HANDLE_VALUE, 135 | NULL, 136 | NULL, 137 | 0 138 | ))) { 139 | LOG_OS_LAST_ERROR(L"CreateIoCompletionPort"); 140 | FatalError(); 141 | } 142 | 143 | unsigned threadId; 144 | if (NULL == (s_timerThread = (HANDLE) _beginthreadex( 145 | (LPSECURITY_ATTRIBUTES) NULL, 146 | 0, // default stack size 147 | TimerThreadProc, 148 | NULL, 149 | 0, // flags 150 | &threadId 151 | ))) { 152 | LOG_OS_LAST_ERROR(L"_beginthreadex"); 153 | FatalError(); 154 | } 155 | } 156 | 157 | //============================================================================= 158 | void TimerDestroy () { 159 | if (s_timerThread) { 160 | PostQueuedCompletionStatus(s_completionPort, 0, 0, 0); 161 | WaitForSingleObject(s_timerThread, INFINITE); 162 | CloseHandle(s_timerThread); 163 | s_timerThread = NULL; 164 | } 165 | 166 | if (s_completionPort) { 167 | CloseHandle(s_completionPort); 168 | s_completionPort = NULL; 169 | } 170 | } 171 | 172 | //============================================================================= 173 | void TimerCreate ( 174 | __in ITimerCallback * callback, 175 | __in unsigned sleepMs, 176 | __out ITimer ** timer 177 | ) { 178 | Timer * t = new Timer; 179 | t->m_callback = callback; 180 | t->m_nextTimeMs = TimeGetMs() + sleepMs; 181 | t->m_flags = 0; 182 | 183 | // Set the timer *before* adding it to the queue to avoid a race 184 | // condition where a callback occurs before the parameter is set. 185 | *timer = t; 186 | 187 | if (sleepMs == TIMER_INFINITE_MS) 188 | return; 189 | 190 | s_critsect.Enter(); 191 | { 192 | t->m_flags |= TIMER_FLAG_QUEUED; 193 | s_timerQ.add(t); 194 | } 195 | s_critsect.Leave(); 196 | } 197 | 198 | #endif 199 | 200 | 201 | //=================================== 202 | // MIT License 203 | // 204 | // Copyright (c) 2010 by Patrick Wyatt 205 | // 206 | // Permission is hereby granted, free of charge, to any person obtaining a copy 207 | // of this software and associated documentation files (the "Software"), to deal 208 | // in the Software without restriction, including without limitation the rights 209 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 210 | // copies of the Software, and to permit persons to whom the Software is 211 | // furnished to do so, subject to the following conditions: 212 | // 213 | // The above copyright notice and this permission notice shall be included in 214 | // all copies or substantial portions of the Software. 215 | // 216 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 217 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 218 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 219 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 220 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 221 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 222 | // THE SOFTWARE. 223 | //=================================== 224 | -------------------------------------------------------------------------------- /Base/Str.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Str.cpp 4 | * 5 | * 6 | * By Patrick Wyatt - 5/6/2010 7 | * 8 | ***/ 9 | 10 | 11 | #include "stdafx.h" 12 | #pragma hdrstop 13 | 14 | 15 | /****************************************************************************** 16 | * 17 | * Exports 18 | * 19 | ***/ 20 | 21 | //============================================================================= 22 | void __cdecl StrPrintf ( 23 | char * dstBuf, 24 | size_t dstChars, 25 | const char format[], 26 | ... 27 | ) { 28 | va_list args; 29 | va_start(args, format); 30 | StrPrintfV(dstBuf, dstChars, format, args); 31 | va_end(args); 32 | } 33 | 34 | //============================================================================= 35 | void __cdecl StrPrintf ( 36 | wchar * dstBuf, 37 | size_t dstChars, 38 | const wchar format[], 39 | ... 40 | ) { 41 | va_list args; 42 | va_start(args, format); 43 | StrPrintfV(dstBuf, dstChars, format, args); 44 | va_end(args); 45 | } 46 | 47 | //============================================================================= 48 | void StrPrintfV ( 49 | char * dstBuf, 50 | size_t dstChars, 51 | const char format[], 52 | va_list args 53 | ) { 54 | #pragma warning(disable:4996) // unsafe function 55 | int result = _vsnprintf( 56 | dstBuf, 57 | dstChars, 58 | format, 59 | args 60 | ); 61 | // Properly NULL-terminate the string 62 | if (dstChars && (unsigned) result >= dstChars) 63 | dstBuf[dstChars - 1] = 0; 64 | #pragma warning(default:4996) // unsafe function 65 | } 66 | 67 | //============================================================================= 68 | void StrPrintfV ( 69 | wchar * dstBuf, 70 | size_t dstChars, 71 | const wchar format[], 72 | va_list args 73 | ) { 74 | #pragma warning(disable:4996) // unsafe function 75 | int result = _vsnwprintf( 76 | dstBuf, 77 | dstChars, 78 | format, 79 | args 80 | ); 81 | // Properly NULL-terminate the string 82 | if (dstChars && (unsigned) result >= dstChars) 83 | dstBuf[dstChars - 1] = 0; 84 | #pragma warning(default:4996) // unsafe function 85 | } 86 | 87 | //============================================================================= 88 | void StrCopy ( 89 | char * dstBuf, 90 | size_t dstChars, 91 | const char srcBuf[] 92 | ) { 93 | if (!dstChars) 94 | return; 95 | 96 | while (--dstChars) { 97 | if (0 == (*dstBuf = *srcBuf)) 98 | return; 99 | ++dstBuf; 100 | ++srcBuf; 101 | } 102 | 103 | // Ensure string is always terminated 104 | *dstBuf = 0; 105 | } 106 | 107 | //============================================================================= 108 | void StrCopy ( 109 | wchar * dstBuf, 110 | size_t dstChars, 111 | const wchar srcBuf[] 112 | ) { 113 | if (!dstChars) 114 | return; 115 | 116 | while (--dstChars) { 117 | if (0 == (*dstBuf = *srcBuf)) 118 | return; 119 | ++dstBuf; 120 | ++srcBuf; 121 | } 122 | 123 | // Ensure string is always terminated 124 | *dstBuf = 0; 125 | } 126 | 127 | //============================================================================= 128 | size_t StrCopyLen (char * dstBuf, size_t dstChars, const char srcBuf[]) { 129 | if (!dstChars) 130 | return 0; 131 | 132 | char * dstBase = dstBuf; 133 | while (--dstChars) { 134 | if (0 == (*dstBuf = *srcBuf)) 135 | return (size_t) (dstBuf - dstBase); 136 | ++dstBuf; 137 | ++srcBuf; 138 | } 139 | 140 | // Ensure string is always terminated 141 | *dstBuf = 0; 142 | return (size_t) (dstBuf - dstBase); 143 | } 144 | 145 | //============================================================================= 146 | size_t StrCopyLen (wchar * dstBuf, size_t dstChars, const wchar srcBuf[]) { 147 | if (!dstChars) 148 | return 0; 149 | 150 | wchar * dstBase = dstBuf; 151 | while (--dstChars) { 152 | if (0 == (*dstBuf = *srcBuf)) 153 | return (size_t) (dstBuf - dstBase); 154 | ++dstBuf; 155 | ++srcBuf; 156 | } 157 | 158 | // Ensure string is always terminated 159 | *dstBuf = 0; 160 | return (size_t) (dstBuf - dstBase); 161 | } 162 | 163 | //============================================================================= 164 | size_t StrLen (const char str[]) { 165 | return (size_t) lstrlenA(str); 166 | } 167 | size_t StrLen (const wchar str[]) { 168 | return (size_t) lstrlenW(str); 169 | } 170 | 171 | //============================================================================= 172 | size_t StrChars (const char str[]) { 173 | return (size_t) lstrlenA(str) + 1; 174 | } 175 | size_t StrChars (const wchar str[]) { 176 | return (size_t) lstrlenW(str) + 1; 177 | } 178 | 179 | //============================================================================= 180 | size_t StrBytes (const char str[]) { 181 | return StrChars(str) * sizeof(str[0]); 182 | } 183 | size_t StrBytes (const wchar str[]) { 184 | return StrChars(str) * sizeof(str[0]); 185 | } 186 | 187 | //============================================================================= 188 | void StrUnicodeToAnsi (char * dstBuf, size_t dstChars, const wchar srcBuf[]) { 189 | if (!WideCharToMultiByte( 190 | CP_ACP, 191 | 0, 192 | srcBuf, 193 | -1, 194 | dstBuf, 195 | (int) (dstChars * sizeof(dstBuf[0])), 196 | NULL, 197 | NULL 198 | )) { 199 | LOG_OS_LAST_ERROR(L"WideCharToMultiByte"); 200 | if (dstChars) 201 | dstBuf[0] = 0; 202 | } 203 | } 204 | 205 | //============================================================================= 206 | void StrAnsiToUnicode (wchar * dstBuf, size_t dstChars, const char srcBuf[]) { 207 | if (!MultiByteToWideChar( 208 | CP_ACP, 209 | MB_PRECOMPOSED, 210 | srcBuf, 211 | -1, 212 | dstBuf, 213 | (int) dstChars 214 | )) { 215 | LOG_OS_LAST_ERROR(L"MultiByteToWideChar"); 216 | if (dstChars) 217 | dstBuf[0] = 0; 218 | } 219 | } 220 | 221 | //============================================================================= 222 | char * StrDupAnsi (const char str[]) { 223 | unsigned bytes = StrBytes(str); 224 | char * dup = (char *) ALLOC(bytes); 225 | memcpy(dup, str, bytes); 226 | return dup; 227 | } 228 | wchar * StrDupWide (const wchar str[]) { 229 | unsigned bytes = StrBytes(str); 230 | wchar * dup = (wchar *) ALLOC(bytes); 231 | memcpy(dup, str, bytes); 232 | return dup; 233 | } 234 | 235 | //============================================================================= 236 | wchar * StrDupAnsiToWide (const char str[]) { 237 | unsigned chars = StrChars(str); 238 | wchar * dup = (wchar *) ALLOC(chars * sizeof(dup[0])); 239 | StrAnsiToUnicode(dup, chars, str); 240 | return dup; 241 | } 242 | char * StrDupWideToAnsi (const wchar str[]) { 243 | unsigned chars = StrChars(str); 244 | char * dup = (char *) ALLOC(chars * sizeof(dup[0])); 245 | StrUnicodeToAnsi(dup, chars, str); 246 | return dup; 247 | } 248 | 249 | 250 | //=================================== 251 | // MIT License 252 | // 253 | // Copyright (c) 2010 by Patrick Wyatt 254 | // 255 | // Permission is hereby granted, free of charge, to any person obtaining a copy 256 | // of this software and associated documentation files (the "Software"), to deal 257 | // in the Software without restriction, including without limitation the rights 258 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 259 | // copies of the Software, and to permit persons to whom the Software is 260 | // furnished to do so, subject to the following conditions: 261 | // 262 | // The above copyright notice and this permission notice shall be included in 263 | // all copies or substantial portions of the Software. 264 | // 265 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 266 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 267 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 268 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 269 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 270 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 271 | // THE SOFTWARE. 272 | //=================================== 273 | -------------------------------------------------------------------------------- /Base/Thread.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Thread.cpp 4 | * 5 | * 6 | * By Patrick Wyatt 7 | * 8 | ***/ 9 | 10 | 11 | #include "stdafx.h" 12 | 13 | 14 | /****************************************************************************** 15 | * 16 | * Private 17 | * 18 | ***/ 19 | 20 | struct Thread { 21 | LIST_LINK(Thread) m_link; 22 | unsigned m_id; 23 | HANDLE m_handle; 24 | unsigned m_lastTimeMs; 25 | char * m_name; 26 | 27 | Thread (const char name[]) 28 | :m_id(0) 29 | ,m_handle(NULL) 30 | ,m_lastTimeMs(GetTickCount()) 31 | ,m_name(StrDupAnsi(name)) 32 | {} 33 | 34 | ~Thread() { 35 | MemFree(m_name); 36 | } 37 | }; 38 | 39 | // Check all threads every minute to ensure they haven't gotten "stuck" 40 | static const unsigned DEADLOCK_CHECK_FREQUENCY_MS = 60 * 1000; 41 | 42 | static HANDLE s_deadlockThread; 43 | static HANDLE s_deadlockEvent; 44 | static CCritSect s_critsect; 45 | static LIST_DECLARE(Thread, m_link) s_threads; 46 | 47 | 48 | //============================================================================= 49 | static void __cdecl Out (const char fmt[], ...) { 50 | va_list args; 51 | va_start(args, fmt); 52 | vprintf(fmt, args); 53 | va_end(args); 54 | } 55 | 56 | //============================================================================= 57 | static void LogThread_CS (const Thread & t) { 58 | // TODO: this function is a little... thin. Replace with Matt Pietrek's code: 59 | // http://www.microsoft.com/msj/0497/hood/hood0497.aspx 60 | Out("Thread: %u [%s]\n", t.m_id, t.m_name); 61 | 62 | CONTEXT ctx; 63 | ctx.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; 64 | if (!GetThreadContext(t.m_handle, &ctx)) { 65 | Out(" ERR: no thread context (%u)\n\n", GetLastError()); 66 | } 67 | 68 | Out(" EIP: %0x\n\n", ctx.Eip); 69 | } 70 | 71 | //============================================================================= 72 | static void LogThreads_CS () { 73 | unsigned threadId = GetCurrentThreadId(); 74 | for (const Thread * t = s_threads.Head(); t; t = t->m_link.Next()) { 75 | // Suspending the current thread is a bad idea 76 | if (t->m_id == threadId) 77 | continue; 78 | 79 | SuspendThread(t->m_handle); 80 | LogThread_CS(*t); 81 | ResumeThread(t->m_handle); 82 | } 83 | } 84 | 85 | //============================================================================= 86 | static void CheckForDeadlocks_CS () { 87 | unsigned timeMs = GetTickCount(); 88 | for (const Thread * t = s_threads.Head(); t; t = t->m_link.Next()) { 89 | // delta might be less than zero because of an inherent 90 | // race condition with ThreadMarkAlive; that's okay, but 91 | // requires that we use a signed comparison below. 92 | signed delta = (signed) (timeMs - t->m_lastTimeMs); 93 | if (delta < (signed) DEADLOCK_CHECK_FREQUENCY_MS) 94 | continue; 95 | 96 | // Deadlock! 97 | LogThreads_CS(); 98 | DebugBreak(); 99 | * (int *) 0 = 0; 100 | break; 101 | } 102 | } 103 | 104 | //============================================================================= 105 | static unsigned __stdcall DeadlockThreadProc (void *) { 106 | for (;;) { 107 | DWORD result = WaitForSingleObject( 108 | s_deadlockEvent, 109 | DEADLOCK_CHECK_FREQUENCY_MS 110 | ); 111 | if (result != WAIT_TIMEOUT) 112 | break; 113 | 114 | s_critsect.Enter(); 115 | { 116 | CheckForDeadlocks_CS(); 117 | } 118 | s_critsect.Leave(); 119 | } 120 | 121 | return 0; 122 | } 123 | 124 | 125 | /****************************************************************************** 126 | * 127 | * Public 128 | * 129 | ***/ 130 | 131 | //============================================================================= 132 | void ThreadInit () { 133 | s_deadlockEvent = CreateEvent(NULL, true, false, NULL); 134 | ASSERT(s_deadlockEvent); 135 | 136 | unsigned threadId; 137 | s_deadlockThread = (HANDLE) _beginthreadex( 138 | NULL, 139 | 0, 140 | DeadlockThreadProc, 141 | NULL, 142 | 0, 143 | &threadId 144 | ); 145 | ASSERT(s_deadlockThread); 146 | } 147 | 148 | //============================================================================= 149 | void ThreadDestroy () { 150 | ASSERT(!s_threads.Head()); 151 | 152 | if (s_deadlockThread) { 153 | SetEvent(s_deadlockEvent); 154 | WaitForSingleObject(s_deadlockThread, INFINITE); 155 | CloseHandle(s_deadlockThread); 156 | s_deadlockThread = NULL; 157 | } 158 | 159 | if (s_deadlockEvent) { 160 | CloseHandle(s_deadlockEvent); 161 | s_deadlockEvent = NULL; 162 | } 163 | } 164 | 165 | //============================================================================= 166 | Thread * ThreadCreate ( 167 | const char name[], 168 | unsigned stack_size, 169 | unsigned (__stdcall * start_address )( void * ), 170 | void *arglist 171 | ) { 172 | // Create thread suspended so we have a chance to register 173 | // it before starting it running 174 | Thread * t = new Thread(name); 175 | t->m_handle = (HANDLE) _beginthreadex( 176 | NULL, 177 | stack_size, 178 | start_address, 179 | arglist, 180 | CREATE_SUSPENDED, 181 | &t->m_id 182 | ); 183 | ASSERT(t->m_handle); 184 | DebugSetThreadName(name, t->m_id); 185 | 186 | // Register thread 187 | s_critsect.Enter(); 188 | { 189 | s_threads.InsertTail(t); 190 | } 191 | s_critsect.Leave(); 192 | 193 | // *Now* start it 194 | ResumeThread(t->m_handle); 195 | return t; 196 | } 197 | 198 | //============================================================================= 199 | void ThreadDestroy (Thread * t) { 200 | ASSERT(t->m_handle); 201 | 202 | // Wait for thread to exit and cleanup 203 | WaitForSingleObject(t->m_handle, INFINITE); 204 | CloseHandle(t->m_handle); 205 | t->m_handle = NULL; 206 | 207 | ThreadUnregister(t); 208 | } 209 | 210 | //============================================================================= 211 | Thread * ThreadRegister (const char name[]) { 212 | // Create thread record with empty thread handle 213 | Thread * t = new Thread(name); 214 | t->m_id = GetCurrentThreadId(); 215 | DebugSetThreadName(name, t->m_id); 216 | 217 | // Register thread 218 | s_critsect.Enter(); 219 | { 220 | s_threads.InsertTail(t); 221 | } 222 | s_critsect.Leave(); 223 | 224 | return t; 225 | } 226 | 227 | //============================================================================= 228 | void ThreadUnregister (Thread * t) { 229 | ASSERT(!t->m_handle); 230 | 231 | // Safely unlink from thread list 232 | s_critsect.Enter(); 233 | { 234 | t->m_link.Unlink(); 235 | } 236 | s_critsect.Leave(); 237 | 238 | delete t; 239 | } 240 | 241 | //============================================================================= 242 | void ThreadMarkAlive (Thread * thread) { 243 | thread->m_lastTimeMs = GetTickCount(); 244 | } 245 | 246 | //============================================================================= 247 | void ThreadLogAllThreads () { 248 | s_critsect.Enter(); 249 | { 250 | LogThreads_CS(); 251 | } 252 | s_critsect.Leave(); 253 | } 254 | 255 | 256 | //=================================== 257 | // MIT License 258 | // 259 | // Copyright (c) 2012 by Patrick Wyatt 260 | // 261 | // Permission is hereby granted, free of charge, to any person obtaining a copy 262 | // of this software and associated documentation files (the "Software"), to deal 263 | // in the Software without restriction, including without limitation the rights 264 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 265 | // copies of the Software, and to permit persons to whom the Software is 266 | // furnished to do so, subject to the following conditions: 267 | // 268 | // The above copyright notice and this permission notice shall be included in 269 | // all copies or substantial portions of the Software. 270 | // 271 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 272 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 273 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 274 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 275 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 276 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 277 | // THE SOFTWARE. 278 | //=================================== 279 | -------------------------------------------------------------------------------- /Test/List/List.cpp: -------------------------------------------------------------------------------- 1 | // List.cpp : Defines the entry point for the console application. 2 | // 3 | 4 | #include "stdafx.h" 5 | #pragma hdrstop 6 | 7 | 8 | /****************************************************************************** 9 | * 10 | * List tests 11 | * 12 | ***/ 13 | 14 | namespace ListTest { 15 | 16 | //============================================================================= 17 | struct Data { 18 | LIST_LINK(Data) forward; 19 | LIST_LINK(Data) reverse; 20 | unsigned value; 21 | }; 22 | 23 | //============================================================================= 24 | static void TestList () { 25 | LIST_DECLARE(Data, forward) forward; 26 | LIST_DECLARE(Data, reverse) reverse; 27 | 28 | for (unsigned j = 0; j < 100; ++j) { 29 | 30 | const unsigned COUNT = 10; 31 | ASSERT(forward.Empty()); 32 | ASSERT(reverse.Empty()); 33 | Data * last = NULL; 34 | for (unsigned i = 0; i < COUNT; ++i){ 35 | Data * data = new Data; 36 | data->value = i; 37 | forward.InsertTail(data); 38 | reverse.InsertHead(data); 39 | ASSERT(forward.Prev(data) == last); 40 | ASSERT(reverse.Next(data) == last); 41 | last = data; 42 | } 43 | ASSERT(!forward.Empty()); 44 | ASSERT(!reverse.Empty()); 45 | 46 | Data * f = forward.Head(); 47 | Data * r = reverse.Head(); 48 | for (unsigned i = 0; i < COUNT; ++i) { 49 | ASSERT(f->value == i); 50 | ASSERT(r->value == COUNT - 1 - i); 51 | ASSERT(f->forward.Next() == forward.Next(f)); 52 | ASSERT(r->reverse.Next() == reverse.Next(r)); 53 | f = f->forward.Next(); 54 | r = r->reverse.Next(); 55 | } 56 | ASSERT(!f); 57 | ASSERT(!r); 58 | 59 | f = forward.Tail(); 60 | r = reverse.Tail(); 61 | for (unsigned i = 0; i < COUNT; ++i) { 62 | ASSERT(f->value == COUNT - 1 - i); 63 | ASSERT(r->value == i); 64 | ASSERT(f->forward.Prev() == forward.Prev(f)); 65 | ASSERT(r->reverse.Prev() == reverse.Prev(r)); 66 | f = f->forward.Prev(); 67 | r = r->reverse.Prev(); 68 | } 69 | ASSERT(!f); 70 | ASSERT(!r); 71 | 72 | forward.UnlinkAll(); 73 | ASSERT(forward.Empty()); 74 | 75 | ASSERT(!reverse.Empty()); 76 | reverse.DeleteAll(); 77 | ASSERT(reverse.Empty()); 78 | } 79 | } 80 | 81 | //============================================================================= 82 | static void InsertIntoBefore (LIST_PTR(Data) list, Data * data) { 83 | Data * before = list->Head(); 84 | while (before) { 85 | if (before->value >= data->value) 86 | break; 87 | before = list->Next(before); 88 | } 89 | list->InsertBefore(data, before); 90 | } 91 | 92 | //============================================================================= 93 | static void InsertIntoAfter (LIST_PTR(Data) list, Data * data) { 94 | Data * after = list->Tail(); 95 | while (after) { 96 | if (after->value <= data->value) 97 | break; 98 | after = list->Prev(after); 99 | } 100 | list->InsertAfter(data, after); 101 | } 102 | 103 | //============================================================================= 104 | static void TestRandom () { 105 | srand(GetTickCount()); 106 | for (unsigned j = 0; j < 10000; ++j){ 107 | LIST_DECLARE(Data, forward) forward; 108 | LIST_DECLARE(Data, reverse) reverse; 109 | 110 | // Insert random items sequentially 111 | for (unsigned i = 0; i < 20; ++i){ 112 | Data * data = new Data; 113 | data->value = (unsigned) rand(); 114 | InsertIntoBefore(&forward, data); 115 | InsertIntoAfter(&reverse, data); 116 | } 117 | 118 | // Ensure all items were inserted in order 119 | for (const Data * f = forward.Head(); const Data * next = forward.Next(f); f = next) 120 | ASSERT(f->value <= next->value); 121 | for (const Data * r = reverse.Tail(); const Data * prev = reverse.Prev(r); r = prev) 122 | ASSERT(r->value >= prev->value); 123 | 124 | // Cleanup 125 | forward.DeleteAll(); 126 | ASSERT(reverse.Empty()); 127 | } 128 | } 129 | 130 | } // namespace ListTest 131 | 132 | 133 | /****************************************************************************** 134 | * 135 | * Hash tests 136 | * 137 | ***/ 138 | 139 | namespace HashTest { 140 | 141 | //============================================================================= 142 | struct DataKey { 143 | DataKey (unsigned value); 144 | unsigned GetHashValue () const; 145 | bool operator== (const struct Obj & obj) const; 146 | unsigned m_data; 147 | }; 148 | 149 | struct TypeKey { 150 | TypeKey (unsigned value); 151 | unsigned GetHashValue () const; 152 | bool operator== (const struct Obj & obj) const; 153 | unsigned m_type; 154 | }; 155 | 156 | struct Obj { 157 | Obj (unsigned value) : data(value), type(value) {} 158 | HASH_LINK(Obj) byData; 159 | HASH_LINK(Obj) byType; 160 | DataKey data; 161 | TypeKey type; 162 | }; 163 | 164 | 165 | DataKey::DataKey (unsigned value) : m_data(value) {} 166 | unsigned DataKey::GetHashValue () const { return m_data; } 167 | bool DataKey::operator== (const Obj & obj) const { return obj.data.m_data == m_data; } 168 | 169 | TypeKey::TypeKey (unsigned value) : m_type(value) {} 170 | unsigned TypeKey::GetHashValue () const { return m_type; } 171 | bool TypeKey::operator== (const Obj & obj) const { return obj.type.m_type == m_type; } 172 | 173 | 174 | //============================================================================= 175 | static void TestHash () { 176 | HASH_DECLARE(Obj, DataKey, byData) dataHash(32); 177 | HASH_DECLARE(Obj, TypeKey, byType) typeHash(17); 178 | 179 | for (unsigned j = 0; j < 100; ++j) { 180 | const unsigned COUNT = 10; 181 | ASSERT(dataHash.AllRowsEmpty()); 182 | ASSERT(typeHash.AllRowsEmpty()); 183 | for (unsigned i = 0; i < COUNT; ++i) { 184 | Obj * obj = new Obj(i); 185 | dataHash.Add(obj, obj->data.GetHashValue()); 186 | typeHash.Add(obj, obj->type.GetHashValue()); 187 | } 188 | ASSERT(!dataHash.AllRowsEmpty()); 189 | ASSERT(!typeHash.AllRowsEmpty()); 190 | 191 | for (unsigned i = 0; i < COUNT; ++i) { 192 | const Obj * obj; 193 | 194 | DataKey data(i); 195 | obj = dataHash.Find(data); 196 | ASSERT(obj); 197 | ASSERT(!dataHash.FindNext(data, obj)); 198 | 199 | TypeKey type(i); 200 | obj = typeHash.Find(type); 201 | ASSERT(obj); 202 | ASSERT(!typeHash.FindNext(type, obj)); 203 | } 204 | 205 | dataHash.UnlinkAll(); 206 | ASSERT(dataHash.AllRowsEmpty()); 207 | 208 | ASSERT(!typeHash.AllRowsEmpty()); 209 | typeHash.DeleteAll(); 210 | ASSERT(typeHash.AllRowsEmpty()); 211 | } 212 | } 213 | 214 | //============================================================================= 215 | static void TestRandom () { 216 | HASH_DECLARE(Obj, DataKey, byData) dataHash(16 * 1024); 217 | 218 | int seed = GetTickCount(); 219 | srand(seed); 220 | for (unsigned j = 0; j < 10000; ++j) { 221 | Obj * obj = new Obj((unsigned) rand()); 222 | dataHash.Add(obj, obj->data.GetHashValue()); 223 | } 224 | 225 | srand(seed); 226 | for (unsigned j = 0; j < 10000; ++j) { 227 | unsigned value = (unsigned) rand(); 228 | DataKey data(value); 229 | Obj * obj = dataHash.Find(data); 230 | delete obj; 231 | } 232 | 233 | ASSERT(dataHash.AllRowsEmpty()); 234 | } 235 | 236 | 237 | } // namespace HashTest 238 | 239 | 240 | //============================================================================= 241 | static void SetErrMode () { 242 | // Report to message box 243 | _set_error_mode(_OUT_TO_MSGBOX); 244 | 245 | // Send all errors to stdout 246 | _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_WNDW); 247 | _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT); 248 | _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_WNDW); 249 | _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT); 250 | _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_WNDW); 251 | _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT); 252 | } 253 | 254 | 255 | /****************************************************************************** 256 | * 257 | * Main 258 | * 259 | ***/ 260 | 261 | //============================================================================= 262 | int _tmain(int argc, _TCHAR* argv[]) { 263 | SetErrMode(); 264 | 265 | // Test lists 266 | { 267 | #ifdef _DEBUG 268 | _CrtMemState before, after, delta; 269 | #endif 270 | _CrtMemCheckpoint(&before); 271 | ListTest::TestList(); 272 | ListTest::TestRandom(); 273 | _CrtMemCheckpoint(&after); 274 | if (_CrtMemDifference(&delta, &before, &after)) { 275 | printf("\n\nMemory leak in lists!\n\n"); 276 | _CrtMemDumpStatistics(&delta); 277 | DebugBreak(); 278 | return 1; 279 | } 280 | } 281 | 282 | // Test hashes 283 | { 284 | #ifdef _DEBUG 285 | _CrtMemState before, after, delta; 286 | #endif 287 | _CrtMemCheckpoint(&before); 288 | HashTest::TestHash(); 289 | HashTest::TestRandom(); 290 | _CrtMemCheckpoint(&after); 291 | if (_CrtMemDifference(&delta, &before, &after)) { 292 | printf("\n\nMemory leak in hashes!\n\n"); 293 | _CrtMemDumpStatistics(&delta); 294 | DebugBreak(); 295 | return 1; 296 | } 297 | } 298 | 299 | return 0; 300 | } 301 | 302 | 303 | //=================================== 304 | // MIT License 305 | // 306 | // Copyright (c) 2010 by Patrick Wyatt 307 | // 308 | // Permission is hereby granted, free of charge, to any person obtaining a copy 309 | // of this software and associated documentation files (the "Software"), to deal 310 | // in the Software without restriction, including without limitation the rights 311 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 312 | // copies of the Software, and to permit persons to whom the Software is 313 | // furnished to do so, subject to the following conditions: 314 | // 315 | // The above copyright notice and this permission notice shall be included in 316 | // all copies or substantial portions of the Software. 317 | // 318 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 319 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 320 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 321 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 322 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 323 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 324 | // THE SOFTWARE. 325 | //=================================== 326 | -------------------------------------------------------------------------------- /Base/Hash.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Hash.h 4 | * 5 | * 6 | * By Patrick Wyatt - 5/16/2010 7 | * 8 | ***/ 9 | 10 | 11 | // WARNING: A proper hash table should be able to grow the row-count, but this 12 | // version doesn't yet have that functionality yet. 13 | 14 | 15 | /****************************************************************************** 16 | * 17 | * WHAT IT IS 18 | * 19 | * This module defines a hash-table implementation that uses "embedded" 20 | * links rather than separately allocated link-nodes as does STL and 21 | * more or less all other hash-table implementations. 22 | * 23 | * Why is this cool: 24 | * 1. No additional memory allocations (malloc) required to link 25 | * an object into a hash table. 26 | * 2. Not necessary to traverse an additional pointer references 27 | * to get to the object being dereferenced. 28 | * 3. Probably most importantly, when objects get deleted, they 29 | * automatically unlink themselves from the tables they're 30 | * linked to, eliminating many common types of bugs. 31 | * 32 | * HOW TO USE IT 33 | * 34 | * Declare a structure that will be contained in one or more hash tables: 35 | * 36 | * class CFooDataKey { 37 | * unsigned GetHashValue () const; 38 | * bool operator== (const class CFoo &) const; 39 | * unsigned m_data; 40 | * }; 41 | * 42 | * class CFooTypeKey { 43 | * unsigned GetHashValue () const; 44 | * bool operator== (const class CFoo &) const; 45 | * unsigned m_type; 46 | * }; 47 | * 48 | * class CFoo { 49 | * HASH_LINK(CFoo) m_hashByData; 50 | * HASH_LINK(CFoo) m_hashByType; 51 | * CFooDataKey m_data; 52 | * CFooTypeKey m_type; 53 | * ... 54 | * }; 55 | * 56 | * Declare hash variables: 57 | * HASH_DECLARE(CFoo, CFooDataKey, m_linkByData) hashByData(1024); 58 | * HASH_DECLARE(CFoo, CFooTypeKey, m_linkByType) hashByType(32); 59 | * HASH_PTR(CFoo, CFooTypeKey) hashPtr = foo ? &hashByData : &hashByType; 60 | * 61 | * Insert into table 62 | * hashByData.Add(someVar, someVar->m_data.GetHashValue()); 63 | * hashByType.Add(someVar, someVar->m_type.GetHashValue()); 64 | * 65 | * Operations on links: 66 | * T * Prev (); 67 | * T * Next (); 68 | * void Unlink (); 69 | * bool IsLinked () const; 70 | * 71 | * Operations on hashes: 72 | * bool AllRowsEmpty () const; 73 | * void UnlinkAll (); 74 | * void DeleteAll (); 75 | * 76 | * T * Prev (T * node); 77 | * T * Next (T * node); 78 | * const T * Prev (const T * node) const; 79 | * const T * Next (const T * node) const; 80 | * 81 | * void Add (T * node); 82 | * void Add (T * node, unsigned hashVal); 83 | * 84 | * T * Find (const TKey & key); 85 | * const T * Find (const TKey & key) const; 86 | * 87 | * T * FindNext (const TKey & key, const T * node); 88 | * const T * FindNext (const TKey & key, const T * node) const; 89 | * 90 | * NOTES 91 | * 92 | * Limitations: 93 | * All nodes must be allocated on (at least) two-byte boundaries 94 | * because the low bit is used as a sentinel to signal end-of-list. 95 | * 96 | * Thanks to: 97 | * Something like this code was originally implemented by Mike 98 | * O'Brien in storm.dll for Diablo in 1995, and again at ArenaNet 99 | * for Guild Wars. 100 | * 101 | ***/ 102 | 103 | 104 | #ifdef HASH_H 105 | #error "Header included more than once" 106 | #endif 107 | #define HASH_H 108 | 109 | 110 | /****************************************************************************** 111 | * 112 | * Hash definition macros 113 | * 114 | ***/ 115 | 116 | // Define a hash table: 117 | // T = type of object being hashed 118 | // link = member within object which is the link field 119 | #define HASH_DECLARE(TObj, TKey, link) THashDeclare 120 | 121 | // Define a field within a structure that will be used to link it into a table 122 | #define HASH_LINK(T) TLink 123 | 124 | // Define a pointer to a list 125 | #define HASH_PTR(T,TKey) THash * 126 | 127 | 128 | /****************************************************************************** 129 | * 130 | * THash 131 | * 132 | ***/ 133 | 134 | //============================================================================= 135 | template 136 | class THash { 137 | public: 138 | ~THash (); 139 | THash (unsigned rows); 140 | 141 | bool AllRowsEmpty () const; 142 | void UnlinkAll (); 143 | void DeleteAll (); 144 | 145 | void Add (T * node); 146 | void Add (T * node, unsigned hashVal); 147 | 148 | T * Find (const TKey & key); 149 | const T * Find (const TKey & key) const; 150 | 151 | T * FindNext (const TKey & key, const T * node); 152 | const T * FindNext (const TKey & key, const T * node) const; 153 | 154 | private: 155 | unsigned m_rows; 156 | size_t m_offset; 157 | TLink * m_buckets; 158 | 159 | T * Next (T * node); 160 | const T * Next (const T * node) const; 161 | const T * FindInternal (const TKey & key, const T * node) const; 162 | 163 | THash (unsigned rows, size_t offset); 164 | TLink * GetLinkFromNode (const T * node) const; 165 | template friend class THashDeclare; 166 | 167 | // Hide copy-constructor and assignment operator 168 | THash (const THash &); 169 | THash & operator= (const THash &); 170 | }; 171 | 172 | //============================================================================= 173 | template 174 | THash::~THash () { 175 | delete [] m_buckets; 176 | } 177 | 178 | //============================================================================= 179 | template 180 | THash::THash (unsigned rows) : THash(rows, 0) 181 | {} 182 | 183 | //============================================================================= 184 | template 185 | THash::THash (unsigned rows, size_t offset) : 186 | m_rows(rows), 187 | m_offset(offset) 188 | { 189 | ASSERT(rows); 190 | m_buckets = new TLink[rows]; 191 | for (unsigned i = 0; i < m_rows; ++i) 192 | m_buckets[i].SetOffset(offset); 193 | } 194 | 195 | //============================================================================= 196 | template 197 | bool THash::AllRowsEmpty () const { 198 | for (unsigned i = 0; i < m_rows; ++i) { 199 | if (m_buckets[i].Next() != NULL) 200 | return false; 201 | } 202 | return true; 203 | } 204 | 205 | //============================================================================= 206 | template 207 | void THash::UnlinkAll () { 208 | for (unsigned i = 0; i < m_rows; ++i) { 209 | for (;;) { 210 | TLink * link = m_buckets[i].PrevLink(); 211 | if (link == &m_buckets[i]) 212 | break; 213 | link->Unlink(); 214 | } 215 | } 216 | } 217 | 218 | //============================================================================= 219 | template 220 | void THash::DeleteAll () { 221 | for (unsigned i = 0; i < m_rows; ++i) { 222 | while (T * node = m_buckets[i].Next()) 223 | delete node; 224 | } 225 | } 226 | 227 | //============================================================================= 228 | template 229 | void THash::Add (T * node) { 230 | Add(node, node->GetHashVal()); 231 | } 232 | 233 | //============================================================================= 234 | template 235 | void THash::Add (T * node, unsigned hashVal) { 236 | ASSERT(!((size_t) node & 1)); 237 | GetLinkFromNode(node)->InsertBefore( 238 | node, 239 | &m_buckets[hashVal % m_rows] 240 | ); 241 | } 242 | 243 | //============================================================================= 244 | template 245 | T * THash::Find (const TKey & key) { 246 | TLink & link = m_buckets[key.GetHashValue() % m_rows]; 247 | return (T *) FindInternal(key, link.Next()); 248 | } 249 | 250 | //============================================================================= 251 | template 252 | const T * THash::Find (const TKey & key) const { 253 | const TLink & link = m_buckets[key.GetHashValue() % m_rows]; 254 | return FindInternal(key, link.Next()); 255 | } 256 | 257 | //============================================================================= 258 | template 259 | T * THash::FindNext (const TKey & key, const T * node) { 260 | return (T *) FindInternal(key, Next(node)); 261 | } 262 | 263 | //============================================================================= 264 | template 265 | const T * THash::FindNext (const TKey & key, const T * node) const { 266 | return FindInternal(key, Next(node)); 267 | } 268 | 269 | //============================================================================= 270 | template 271 | const T * THash::FindInternal (const TKey & key, const T * node) const { 272 | while (node) { 273 | if (key == *node) 274 | return node; 275 | node = Next(node); 276 | } 277 | return NULL; 278 | } 279 | 280 | //============================================================================= 281 | template 282 | T * THash::Next (T * node) { 283 | return GetLinkFromNode(node)->Next(); 284 | } 285 | 286 | //============================================================================= 287 | template 288 | const T * THash::Next (const T * node) const { 289 | return GetLinkFromNode(node)->Next(); 290 | } 291 | 292 | //============================================================================= 293 | template 294 | TLink * THash::GetLinkFromNode (const T * node) const { 295 | ASSERT(m_offset != (size_t) -1); 296 | return (TLink *) ((size_t) node + m_offset); 297 | } 298 | 299 | 300 | /****************************************************************************** 301 | * 302 | * THashDeclare - declare a list with a known link offset 303 | * 304 | ***/ 305 | 306 | //============================================================================= 307 | template 308 | class THashDeclare : public THash { 309 | public: 310 | THashDeclare (unsigned rows); 311 | }; 312 | 313 | //============================================================================= 314 | template 315 | THashDeclare::THashDeclare (unsigned rows) : 316 | THash(rows, offset) 317 | {} 318 | 319 | //=================================== 320 | // MIT License 321 | // 322 | // Copyright (c) 2010 by Patrick Wyatt 323 | // 324 | // Permission is hereby granted, free of charge, to any person obtaining a copy 325 | // of this software and associated documentation files (the "Software"), to deal 326 | // in the Software without restriction, including without limitation the rights 327 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 328 | // copies of the Software, and to permit persons to whom the Software is 329 | // furnished to do so, subject to the following conditions: 330 | // 331 | // The above copyright notice and this permission notice shall be included in 332 | // all copies or substantial portions of the Software. 333 | // 334 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 335 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 336 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 337 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 338 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 339 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 340 | // THE SOFTWARE. 341 | //=================================== 342 | -------------------------------------------------------------------------------- /Lib/SrvLib/Config.cpp: -------------------------------------------------------------------------------- 1 | /************************************ 2 | * 3 | * Config.cpp 4 | * 5 | * 6 | * By Patrick Wyatt - 5/19/2010 7 | * 8 | ***/ 9 | 10 | 11 | #include "stdafx.h" 12 | #pragma hdrstop 13 | #include 14 | #include 15 | 16 | 17 | // http://github.com/etexteditor/e/blob/811bf09e31f26b2c86101448087fb264a26cca74/src/DirWatcher.cpp 18 | 19 | 20 | /************************************ 21 | * 22 | * Private 23 | * 24 | ***/ 25 | 26 | 27 | struct WCmpStrI { 28 | bool operator()(const wchar * a, const wchar * b) const { 29 | return _wcsicmp(a, b) < 0; 30 | } 31 | }; 32 | 33 | 34 | struct ConfigFile { 35 | ConfigFile (const wchar filename[]); 36 | 37 | u64 m_lastWriteTime; 38 | wchar * m_filename; // points into m_fullpath 39 | wchar m_fullpath[MAX_PATH]; 40 | }; 41 | 42 | 43 | typedef std::hash_map< 44 | const wchar *, 45 | ConfigFile *, 46 | std::hash_compare 47 | > ConfigFileMap; 48 | 49 | 50 | typedef std::pair< 51 | const wchar *, 52 | ConfigFile * 53 | > ConfigFilePair; 54 | 55 | 56 | struct DirMonitor : public CTask { 57 | ConfigFileMap m_files; 58 | OVERLAPPED m_olap; 59 | HANDLE m_handle; 60 | wchar m_directory[MAX_PATH]; 61 | byte m_buffer[2*1024]; 62 | 63 | DirMonitor (const wchar directory[]); 64 | virtual ~DirMonitor (); 65 | void Destroy_CS (); 66 | void WatchDirectory_CS (); 67 | void ScanDirectoryForChanges_CS (); 68 | void CheckReparseFile_CS (const wchar filename[]); 69 | 70 | // From CTask 71 | void TaskComplete ( 72 | unsigned bytes, 73 | OVERLAPPED * olap 74 | ); 75 | }; 76 | 77 | 78 | typedef std::hash_map< 79 | const wchar *, 80 | DirMonitor *, 81 | std::hash_compare 82 | > DirMonitorMap; 83 | 84 | 85 | typedef std::pair< 86 | const wchar *, 87 | DirMonitor * 88 | > DirMonitorPair; 89 | 90 | 91 | static DirMonitorMap s_dirMonitors; 92 | static unsigned s_dirCount; 93 | static CCritSect s_critsect; 94 | 95 | 96 | //=================================== 97 | static void ReparseFile (ConfigFile * file) { 98 | // TODO 99 | (void) file; 100 | } 101 | 102 | 103 | //=================================== 104 | ConfigFile::ConfigFile (const wchar filename[]) { 105 | m_lastWriteTime = 0; 106 | StrCopy(m_fullpath, _countof(m_fullpath), filename); 107 | m_filename = PathFindFileNameW(m_fullpath); 108 | } 109 | 110 | 111 | //=================================== 112 | struct DeleteConfigFile { 113 | bool operator()(ConfigFilePair x) const 114 | { 115 | delete x.second; 116 | return true; 117 | } 118 | }; 119 | 120 | 121 | //=================================== 122 | DirMonitor::DirMonitor (const wchar directory[]) 123 | : m_handle(INVALID_HANDLE_VALUE) 124 | { 125 | StrCopy(m_directory, _countof(m_directory), directory); 126 | ZERO(m_olap); 127 | ++s_dirCount; 128 | } 129 | 130 | 131 | //=================================== 132 | DirMonitor::~DirMonitor () { 133 | ASSERT(m_handle == INVALID_HANDLE_VALUE); 134 | for_each(m_files.begin(), m_files.end(), DeleteConfigFile()); 135 | m_files.clear(); 136 | --s_dirCount; 137 | } 138 | 139 | 140 | //=================================== 141 | struct DestroyDirMonitor_CS { 142 | bool operator()(DirMonitorPair x) const 143 | { 144 | x.second->Destroy_CS(); 145 | return true; 146 | } 147 | }; 148 | 149 | 150 | //=================================== 151 | void DirMonitor::Destroy_CS () { 152 | // Closing the handle will initiate an asynchronous callback 153 | HANDLE handle = m_handle; 154 | m_handle = INVALID_HANDLE_VALUE; 155 | CloseHandle(handle); 156 | } 157 | 158 | 159 | //=================================== 160 | void DirMonitor::WatchDirectory_CS () { 161 | if (m_handle == INVALID_HANDLE_VALUE) { 162 | delete this; 163 | } 164 | else if (!ReadDirectoryChangesW( 165 | m_handle, 166 | m_buffer, 167 | sizeof(m_buffer), 168 | false, // bWatchSubtree 169 | FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE, 170 | NULL, 171 | &m_olap, 172 | NULL 173 | )) { 174 | LOG_OS_LAST_ERROR(L"ReadDirectoryChangesW"); 175 | FatalError(); 176 | } 177 | } 178 | 179 | 180 | //=================================== 181 | static bool CheckFileWriteTime (const wchar filename[], u64 * lastWriteTime) { 182 | // Get the file attributes 183 | WIN32_FILE_ATTRIBUTE_DATA info; 184 | if (!GetFileAttributesExW(filename, GetFileExInfoStandard, &info)) { 185 | LOG_OS_LAST_ERROR(L"GetFileAttributesExW"); 186 | return true; 187 | } 188 | 189 | // Did the file write time change? 190 | if (*lastWriteTime >= * (u64 *) &info.ftLastWriteTime) 191 | return false; 192 | 193 | // Update last write time 194 | // DebugMsg("%S changed\n", filename); 195 | *lastWriteTime = * (u64 *) &info.ftLastWriteTime; 196 | return true; 197 | } 198 | 199 | 200 | //=================================== 201 | void DirMonitor::CheckReparseFile_CS (const wchar filename[]) { 202 | // Is this a file being watched? 203 | ConfigFileMap::iterator pair = m_files.find(filename); 204 | if (pair == m_files.end()) 205 | return; 206 | 207 | // Did the file change? 208 | ConfigFile * file = pair->second; 209 | if (!CheckFileWriteTime(file->m_fullpath, &file->m_lastWriteTime)) 210 | return; 211 | 212 | ReparseFile(file); 213 | } 214 | 215 | 216 | //=================================== 217 | void DirMonitor::ScanDirectoryForChanges_CS () { 218 | // Search for all files in this directory 219 | wchar filespec[MAX_PATH]; 220 | PathCombineW(filespec, m_directory, L"*"); 221 | 222 | // Start search 223 | WIN32_FIND_DATAW data; 224 | HANDLE find = FindFirstFileW(filespec, &data); 225 | if (find == INVALID_HANDLE_VALUE) { 226 | LOG_OS_LAST_ERROR(L"FindFirstFileW"); 227 | return; 228 | } 229 | 230 | // Search for watched files 231 | do { 232 | // Ignore directories 233 | if (data.dwFileAttributes & (FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_DIRECTORY)) 234 | continue; 235 | 236 | // Convert to lowercase for hash matching 237 | wchar * filename = PathFindFileNameW(data.cFileName); 238 | CharLowerW(filename); 239 | 240 | // Reparse if file changed 241 | CheckReparseFile_CS(filename); 242 | 243 | } while (FindNextFileW(find, &data)); 244 | 245 | // Cleanup 246 | FindClose(find); 247 | } 248 | 249 | 250 | //=================================== 251 | void DirMonitor::TaskComplete ( 252 | unsigned bytes, 253 | OVERLAPPED * 254 | ) { 255 | s_critsect.Enter(); 256 | { 257 | if (m_handle == INVALID_HANDLE_VALUE) { 258 | // The monitor is ready to be deleted 259 | } 260 | // If no bytes read then m_buffer wasn't large enough to hold all the 261 | // updates; scan the directory to see which files need to be updated 262 | else if (!bytes) { 263 | ScanDirectoryForChanges_CS(); 264 | } 265 | // Otherwise process the file notifications 266 | else for (const FILE_NOTIFY_INFORMATION * info = (const FILE_NOTIFY_INFORMATION *) m_buffer;;) { 267 | // Validate the structure 268 | // DebugMsg(" %u: %.*S\n", info->Action, info->FileNameLength / sizeof(info->FileName[0]), info->FileName); 269 | #ifdef ASSERTIONS_ENABLED 270 | size_t offset = (size_t) ((const byte *) info - (const byte *) m_buffer); 271 | ASSERT(offset < bytes); 272 | ASSERT(offset < sizeof_field(DirMonitor, m_buffer)); 273 | #endif 274 | 275 | // Deleting or renaming a file does not cause re-parsing 276 | if ((info->Action == FILE_ACTION_REMOVED) || (info->Action == FILE_ACTION_RENAMED_OLD_NAME)) { 277 | // DebugMsg("%.*S deleted\n", info->FileNameLength / sizeof(info->FileName[0]), filename); 278 | } 279 | else { 280 | // Convert to lowercase for hash matching 281 | wchar filename[MAX_PATH]; 282 | StrCopy(filename, min(_countof(filename), info->FileNameLength / sizeof(info->FileName[0]) + 1), info->FileName); 283 | CharLowerW(filename); 284 | 285 | // Reparse if file changed 286 | CheckReparseFile_CS(filename); 287 | } 288 | 289 | // Move to next entry 290 | if (!info->NextEntryOffset) 291 | break; 292 | info = (const FILE_NOTIFY_INFORMATION *) ((const byte *) info + info->NextEntryOffset); 293 | } 294 | 295 | WatchDirectory_CS(); 296 | } 297 | s_critsect.Leave(); 298 | } 299 | 300 | 301 | //=================================== 302 | static DirMonitor * FindOrCreateDirectoryMonitor_CS (const wchar directory[]) { 303 | // Does this directory already exist in the monitor list? 304 | DirMonitorMap::iterator pair = s_dirMonitors.find(directory); 305 | if (pair != s_dirMonitors.end()) 306 | return pair->second; 307 | 308 | // Create the directory monitor 309 | DirMonitor * dir = new DirMonitor(directory); 310 | s_dirMonitors.insert(DirMonitorPair(dir->m_directory, dir)); 311 | 312 | // Open the directory handle 313 | if (INVALID_HANDLE_VALUE == (dir->m_handle = CreateFileW( 314 | directory, 315 | FILE_LIST_DIRECTORY, 316 | FILE_SHARE_READ | FILE_SHARE_WRITE, 317 | (LPSECURITY_ATTRIBUTES) NULL, 318 | OPEN_EXISTING, 319 | FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, 320 | NULL 321 | ))) { 322 | LOG_OS_LAST_ERROR(L"CreateFileW"); 323 | FatalError(); 324 | } 325 | 326 | // Start watching for notifications 327 | TaskRegisterHandle(dir, dir->m_handle); 328 | dir->WatchDirectory_CS(); 329 | 330 | return dir; 331 | } 332 | 333 | 334 | /************************************ 335 | * 336 | * Exports 337 | * 338 | ***/ 339 | 340 | 341 | //=================================== 342 | void ConfigInitialize () { 343 | // empty 344 | } 345 | 346 | 347 | //=================================== 348 | void ConfigDestroy () { 349 | s_critsect.Enter(); 350 | { 351 | for_each(s_dirMonitors.begin(), s_dirMonitors.end(), DestroyDirMonitor_CS()); 352 | s_dirMonitors.clear(); 353 | } 354 | s_critsect.Leave(); 355 | 356 | // Wait until all directory monitors are deleted asynchronously 357 | while (s_dirCount) 358 | Sleep(1); 359 | } 360 | 361 | 362 | //=================================== 363 | void ConfigMonitorFile (const wchar filename[]) { 364 | // Convert to canonical lowercase form 365 | wchar fullpath[MAX_PATH]; 366 | if (!GetFullPathNameW(filename, _countof(fullpath), fullpath, NULL)) { 367 | LOG_OS_LAST_ERROR(L"GetFullPathNameW"); 368 | FatalError(); 369 | } 370 | CharLowerW(fullpath); 371 | 372 | // Create the directory that contains the file to be watched 373 | wchar directory[MAX_PATH]; 374 | PathRemoveFileName(directory, _countof(directory), fullpath); 375 | if (!PathCreateDirectory(directory)) 376 | FatalError(); 377 | 378 | // Get the filename part 379 | filename = PathFindFileNameW(fullpath); 380 | 381 | s_critsect.Enter(); 382 | { 383 | // Create a monitor for this directory 384 | DirMonitor * dir = FindOrCreateDirectoryMonitor_CS(directory); 385 | 386 | // Does this file already exist in the monitor's file list? 387 | ConfigFile * file; 388 | ConfigFileMap::iterator pair = dir->m_files.find(filename); 389 | if (pair == dir->m_files.end()) { 390 | file = new ConfigFile(fullpath); 391 | dir->m_files.insert(ConfigFilePair(file->m_filename, file)); 392 | } 393 | else { 394 | file = pair->second; 395 | } 396 | 397 | // TODO: signal file for reparsing so the callback gets called. 398 | } 399 | s_critsect.Leave(); 400 | } 401 | 402 | 403 | //=================================== 404 | // MIT License 405 | // 406 | // Copyright (c) 2010 by Patrick Wyatt 407 | // 408 | // Permission is hereby granted, free of charge, to any person obtaining a copy 409 | // of this software and associated documentation files (the "Software"), to deal 410 | // in the Software without restriction, including without limitation the rights 411 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 412 | // copies of the Software, and to permit persons to whom the Software is 413 | // furnished to do so, subject to the following conditions: 414 | // 415 | // The above copyright notice and this permission notice shall be included in 416 | // all copies or substantial portions of the Software. 417 | // 418 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 419 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 420 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 421 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 422 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 423 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 424 | // THE SOFTWARE. 425 | //=================================== 426 | -------------------------------------------------------------------------------- /Base/List.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * List.h 4 | * 5 | * 6 | * By Patrick Wyatt - 5/16/2010 7 | * 8 | ***/ 9 | 10 | 11 | /****************************************************************************** 12 | * 13 | * WHAT IT IS 14 | * 15 | * This module defines a linked-list implementation that uses "embedded" 16 | * links rather than separately allocated link-nodes as does STL and 17 | * more or less all other linked-list implementations. 18 | * 19 | * Why is this cool: 20 | * 1. No additional memory allocations (malloc) required to link 21 | * an object into a linked list. 22 | * 2. Not necessary to traverse an additional pointer references 23 | * to get to the object being dereferenced. 24 | * 3. Probably most importantly, when objects get deleted, they 25 | * automatically unlink themselves from the lists they're 26 | * linked to, eliminating many common types of bugs. 27 | * 28 | * HOW TO USE IT 29 | * 30 | * Declare a structure that will be contained in one or more linked lists: 31 | * class CFoo { 32 | * LIST_LINK(CFoo) m_linkByData; 33 | * LIST_LINK(CFoo) m_linkByType; 34 | * int m_data; 35 | * int m_type; 36 | * ... 37 | * }; 38 | * 39 | * Declare list variables: 40 | * LIST_DECLARE(CFoo, m_linkByData) listByData; 41 | * LIST_DECLARE(CFoo, m_linkByType) listByType; 42 | * LIST_PTR(CFoo) m_listPtr = foo ? &listByData : &listByType; 43 | * 44 | * Operations on links: 45 | * T * Prev (); 46 | * T * Next (); 47 | * void Unlink (); 48 | * bool IsLinked () const; 49 | * 50 | * Operations on lists: 51 | * bool Empty () const; 52 | * void UnlinkAll (); 53 | * void DeleteAll (); 54 | * 55 | * T * Head (); 56 | * T * Tail (); 57 | * T * Prev (T * node); 58 | * T * Next (T * node); 59 | * 60 | * void InsertHead (T * node); 61 | * void InsertTail (T * node); 62 | * void InsertBefore (T * node, T * before); 63 | * void InsertAfter (T * node, T * after); 64 | * 65 | * NOTES 66 | * 67 | * Limitations: 68 | * All nodes must be allocated on (at least) two-byte boundaries 69 | * because the low bit is used as a sentinel to signal end-of-list. 70 | * 71 | * Thanks to: 72 | * Something like this code was originally implemented by Mike 73 | * O'Brien in storm.dll for Diablo in 1995, and again at ArenaNet 74 | * for Guild Wars. 75 | * 76 | ***/ 77 | 78 | 79 | #ifdef LIST_H 80 | #error "Header included more than once" 81 | #endif 82 | #define LIST_H 83 | 84 | 85 | /****************************************************************************** 86 | * 87 | * List definition macros 88 | * 89 | ***/ 90 | 91 | // Define a linked list: 92 | // T = type of object being linked 93 | // link = member within object which is the link field 94 | #define LIST_DECLARE(T, link) TListDeclare 95 | 96 | // Define a field within a structure that will be used to link it into a list 97 | #define LIST_LINK(T) TLink 98 | 99 | // Define a pointer to a list 100 | #define LIST_PTR(T) TList * 101 | 102 | 103 | /****************************************************************************** 104 | * 105 | * TLink 106 | * 107 | ***/ 108 | 109 | //============================================================================= 110 | template 111 | class TLink { 112 | public: 113 | ~TLink (); 114 | TLink (); 115 | 116 | bool IsLinked () const; 117 | void Unlink (); 118 | 119 | T * Prev (); 120 | T * Next (); 121 | const T * Prev () const; 122 | const T * Next () const; 123 | 124 | // For use by list-type classes, not user code; 125 | // the alternative is to friend TList, THash, 126 | // and (eventually) many other structures. 127 | TLink (size_t offset); 128 | void SetOffset (size_t offset); 129 | TLink * NextLink (); 130 | TLink * PrevLink (); 131 | void InsertBefore (T * node, TLink * nextLink); 132 | void InsertAfter (T * node, TLink * prevLink); 133 | 134 | private: 135 | T * m_nextNode; // pointer to the next >object< 136 | TLink * m_prevLink; // pointer to the previous >link field< 137 | void RemoveFromList (); 138 | 139 | // Hide copy-constructor and assignment operator 140 | TLink (const TLink &); 141 | TLink & operator= (const TLink &); 142 | }; 143 | 144 | //============================================================================= 145 | template 146 | TLink::~TLink () { 147 | RemoveFromList(); 148 | } 149 | 150 | //============================================================================= 151 | template 152 | TLink::TLink () { 153 | // Mark this node as the end of the list, with no link offset 154 | m_nextNode = (T *) ((size_t) this + 1 - 0); 155 | m_prevLink = this; 156 | } 157 | 158 | //============================================================================= 159 | template 160 | TLink::TLink (size_t offset) { 161 | // Mark this node as the end of the list, with the link offset set 162 | m_nextNode = (T *) ((size_t) this + 1 - offset); 163 | m_prevLink = this; 164 | } 165 | 166 | //============================================================================= 167 | template 168 | void TLink::SetOffset (size_t offset) { 169 | // Mark this node as the end of the list, with the link offset set 170 | m_nextNode = (T *) ((size_t) this + 1 - offset); 171 | m_prevLink = this; 172 | } 173 | 174 | //============================================================================= 175 | template 176 | TLink * TLink::NextLink () { 177 | // Calculate the offset from a node pointer to a link structure 178 | size_t offset = (size_t) this - ((size_t) m_prevLink->m_nextNode & ~1); 179 | 180 | // Get the link field for the next node 181 | return (TLink *) (((size_t) m_nextNode & ~1) + offset); 182 | } 183 | 184 | //============================================================================= 185 | template 186 | void TLink::RemoveFromList () { 187 | NextLink()->m_prevLink = m_prevLink; 188 | m_prevLink->m_nextNode = m_nextNode; 189 | } 190 | 191 | //============================================================================= 192 | template 193 | void TLink::InsertBefore (T * node, TLink * nextLink) { 194 | RemoveFromList(); 195 | 196 | m_prevLink = nextLink->m_prevLink; 197 | m_nextNode = m_prevLink->m_nextNode; 198 | 199 | nextLink->m_prevLink->m_nextNode = node; 200 | nextLink->m_prevLink = this; 201 | } 202 | 203 | //============================================================================= 204 | template 205 | void TLink::InsertAfter (T * node, TLink * prevLink) { 206 | RemoveFromList(); 207 | 208 | m_prevLink = prevLink; 209 | m_nextNode = prevLink->m_nextNode; 210 | 211 | prevLink->NextLink()->m_prevLink = this; 212 | prevLink->m_nextNode = node; 213 | } 214 | 215 | //============================================================================= 216 | template 217 | bool TLink::IsLinked () const { 218 | return m_prevLink != this; 219 | } 220 | 221 | //============================================================================= 222 | template 223 | void TLink::Unlink () { 224 | RemoveFromList(); 225 | 226 | // Mark this node as the end of the list with no link offset 227 | m_nextNode = (T *) ((size_t) this + 1); 228 | m_prevLink = this; 229 | } 230 | 231 | //============================================================================= 232 | template 233 | TLink * TLink::PrevLink () { 234 | return m_prevLink; 235 | } 236 | 237 | //============================================================================= 238 | template 239 | T * TLink::Prev () { 240 | T * prevNode = m_prevLink->m_prevLink->m_nextNode; 241 | if ((size_t) prevNode & 1) 242 | return NULL; 243 | return prevNode; 244 | } 245 | 246 | //============================================================================= 247 | template 248 | const T * TLink::Prev () const { 249 | const T * prevNode = m_prevLink->m_prevLink->m_nextNode; 250 | if ((size_t) prevNode & 1) 251 | return NULL; 252 | return prevNode; 253 | } 254 | 255 | //============================================================================= 256 | template 257 | T * TLink::Next () { 258 | if ((size_t) m_nextNode & 1) 259 | return NULL; 260 | return m_nextNode; 261 | } 262 | 263 | //============================================================================= 264 | template 265 | const T * TLink::Next () const { 266 | if ((size_t) m_nextNode & 1) 267 | return NULL; 268 | return m_nextNode; 269 | } 270 | 271 | 272 | /****************************************************************************** 273 | * 274 | * TList 275 | * 276 | ***/ 277 | 278 | //============================================================================= 279 | template 280 | class TList { 281 | public: 282 | ~TList (); 283 | TList (); 284 | 285 | bool Empty () const; 286 | void UnlinkAll (); 287 | void DeleteAll (); 288 | 289 | T * Head (); 290 | T * Tail (); 291 | const T * Head () const; 292 | const T * Tail () const; 293 | 294 | T * Prev (T * node); 295 | T * Next (T * node); 296 | const T * Prev (const T * node) const; 297 | const T * Next (const T * node) const; 298 | 299 | void InsertHead (T * node); 300 | void InsertTail (T * node); 301 | void InsertBefore (T * node, T * before); 302 | void InsertAfter (T * node, T * after); 303 | 304 | private: 305 | TLink m_link; 306 | size_t m_offset; 307 | 308 | TList (size_t offset); 309 | TLink * GetLinkFromNode (const T * node) const; 310 | template friend class TListDeclare; 311 | 312 | // Hide copy-constructor and assignment operator 313 | TList (const TList &); 314 | TList & operator= (const TList &); 315 | }; 316 | 317 | //============================================================================= 318 | template 319 | TList::~TList () { 320 | UnlinkAll(); 321 | } 322 | 323 | //============================================================================= 324 | template 325 | TList::TList () : 326 | m_link(), 327 | m_offset((size_t) -1) 328 | {} 329 | 330 | //============================================================================= 331 | template 332 | TList::TList (size_t offset) : 333 | m_link(offset), 334 | m_offset(offset) 335 | {} 336 | 337 | //============================================================================= 338 | template 339 | bool TList::Empty () const { 340 | return m_link.Next() == NULL; 341 | } 342 | 343 | //============================================================================= 344 | template 345 | void TList::UnlinkAll () { 346 | for (;;) { 347 | TLink * link = m_link.PrevLink(); 348 | if (link == &m_link) 349 | break; 350 | link->Unlink(); 351 | } 352 | } 353 | 354 | //============================================================================= 355 | template 356 | void TList::DeleteAll () { 357 | while (T * node = m_link.Next()) 358 | delete node; 359 | } 360 | 361 | //============================================================================= 362 | template 363 | T * TList::Head () { 364 | return m_link.Next(); 365 | } 366 | 367 | //============================================================================= 368 | template 369 | T * TList::Tail () { 370 | return m_link.Prev(); 371 | } 372 | 373 | //============================================================================= 374 | template 375 | const T * TList::Head () const { 376 | return m_link.Next(); 377 | } 378 | 379 | //============================================================================= 380 | template 381 | const T * TList::Tail () const { 382 | return m_link.Prev(); 383 | } 384 | 385 | //============================================================================= 386 | template 387 | T * TList::Prev (T * node) { 388 | return GetLinkFromNode(node)->Prev(); 389 | } 390 | 391 | //============================================================================= 392 | template 393 | const T * TList::Prev (const T * node) const { 394 | return GetLinkFromNode(node)->Prev(); 395 | } 396 | 397 | //============================================================================= 398 | template 399 | T * TList::Next (T * node) { 400 | return GetLinkFromNode(node)->Next(); 401 | } 402 | 403 | //============================================================================= 404 | template 405 | const T * TList::Next (const T * node) const { 406 | return GetLinkFromNode(node)->Next(); 407 | } 408 | 409 | //============================================================================= 410 | template 411 | void TList::InsertHead (T * node) { 412 | InsertAfter(node, NULL); 413 | } 414 | 415 | //============================================================================= 416 | template 417 | void TList::InsertTail (T * node) { 418 | InsertBefore(node, NULL); 419 | } 420 | 421 | //============================================================================= 422 | template 423 | void TList::InsertBefore (T * node, T * before) { 424 | ASSERT(!((size_t) node & 1)); 425 | GetLinkFromNode(node)->InsertBefore( 426 | node, 427 | before ? GetLinkFromNode(before) : &m_link 428 | ); 429 | } 430 | 431 | //============================================================================= 432 | template 433 | void TList::InsertAfter (T * node, T * after) { 434 | ASSERT(!((size_t) node & 1)); 435 | GetLinkFromNode(node)->InsertAfter( 436 | node, 437 | after ? GetLinkFromNode(after) : &m_link 438 | ); 439 | } 440 | 441 | //============================================================================= 442 | template 443 | TLink * TList::GetLinkFromNode (const T * node) const { 444 | ASSERT(m_offset != (size_t) -1); 445 | return (TLink *) ((size_t) node + m_offset); 446 | } 447 | 448 | /****************************************************************************** 449 | * 450 | * TListDeclare - declare a list with a known link offset 451 | * 452 | ***/ 453 | 454 | //============================================================================= 455 | template 456 | class TListDeclare : public TList { 457 | public: 458 | TListDeclare (); 459 | }; 460 | 461 | //============================================================================= 462 | template 463 | TListDeclare::TListDeclare () : TList(offset) 464 | {} 465 | 466 | 467 | //=================================== 468 | // MIT License 469 | // 470 | // Copyright (c) 2010 by Patrick Wyatt 471 | // 472 | // Permission is hereby granted, free of charge, to any person obtaining a copy 473 | // of this software and associated documentation files (the "Software"), to deal 474 | // in the Software without restriction, including without limitation the rights 475 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 476 | // copies of the Software, and to permit persons to whom the Software is 477 | // furnished to do so, subject to the following conditions: 478 | // 479 | // The above copyright notice and this permission notice shall be included in 480 | // all copies or substantial portions of the Software. 481 | // 482 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 483 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 484 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 485 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 486 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 487 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 488 | // THE SOFTWARE. 489 | //=================================== 490 | -------------------------------------------------------------------------------- /Lib/SrvLib/SrvLib.cpp: -------------------------------------------------------------------------------- 1 | /************************************ 2 | * 3 | * SrvLib.cpp 4 | * 5 | * 6 | * By Patrick Wyatt - 5/6/2010 7 | * 8 | ***/ 9 | 10 | 11 | #include "stdafx.h" 12 | #pragma hdrstop 13 | 14 | 15 | /************************************ 16 | * 17 | * Private 18 | * 19 | ***/ 20 | 21 | 22 | static CApplication * s_app; 23 | 24 | 25 | /************************************ 26 | * 27 | * Command line parser 28 | * 29 | ***/ 30 | 31 | 32 | enum EAppMode { 33 | APP_RUN_APPLICATION, 34 | APP_RUN_SERVICE, 35 | APP_INSTALL_SERVICE, 36 | APP_USAGE_SHOW, 37 | APP_FAILED_ERROR, 38 | }; 39 | 40 | 41 | struct CmdLineOptions { 42 | private: 43 | bool m_error; 44 | 45 | void ParseOpt (const wchar arg[]); 46 | void ParseArg (const wchar arg[]); 47 | void __cdecl CmdLineError (const char fmt[], ...); 48 | 49 | public: 50 | EAppMode m_appMode; 51 | wchar m_username[64]; 52 | wchar m_password[64]; 53 | 54 | CmdLineOptions (const wchar cmdLine[]); 55 | }; 56 | 57 | 58 | //=================================== 59 | static void Usage () { 60 | wchar message[512]; 61 | StrPrintf( 62 | message, 63 | _countof(message), 64 | L"Usage:\n" 65 | L" %s [options]\n" 66 | L"\n" 67 | L"Options:\n" 68 | L" /?\t\t\tOutput this help\n" 69 | L" /install\t\t\tInstall as service\n" 70 | L" /username:\tInstallation username\n" 71 | L" /password:\tInstallation password\n" 72 | L"\n" 73 | , // end of format string 74 | s_app->Name() 75 | ); 76 | 77 | #ifdef _CONSOLE 78 | fputws(message, stderr); 79 | #else 80 | wchar caption[MAX_PATH]; 81 | PathGetExeFileName(caption, _countof(caption)); 82 | MessageBoxW(NULL, message, caption, MB_OK); 83 | #endif 84 | } 85 | 86 | 87 | //=================================== 88 | CmdLineOptions::CmdLineOptions (const wchar cmdLine[]) { 89 | // Initialize options 90 | m_error = false; 91 | m_appMode = APP_RUN_APPLICATION; 92 | m_username[0] = 0; 93 | m_password[0] = 0; 94 | 95 | // Tokenize the command line 96 | int argc = 0; 97 | wchar ** argv = CommandLineToArgvW(cmdLine, &argc); 98 | if (!argv) { 99 | LOG_OS_LAST_ERROR(L"CommandLineToArgvW"); 100 | m_appMode = APP_FAILED_ERROR; 101 | return; 102 | } 103 | 104 | // Parse arguments 105 | for (int i = 1; i < argc; ++i) { 106 | wchar first = argv[i][0]; 107 | if (first == '/' || first == '-') 108 | ParseOpt(argv[i] + 1); 109 | else 110 | ParseArg(argv[i]); 111 | if (m_error) 112 | break; 113 | } 114 | 115 | if (m_error) 116 | m_appMode = APP_FAILED_ERROR; 117 | LocalFree(argv); 118 | } 119 | 120 | 121 | //=================================== 122 | void CmdLineOptions::ParseOpt (const wchar arg[]) { 123 | static const wchar ARG_USERNAME[] = L"username:"; 124 | static const wchar ARG_PASSWORD[] = L"password:"; 125 | 126 | // NOTE: the "/service" argument isn't listed in the command-line usage 127 | // because it should only be used by the service control manager 128 | if (!wcscmp(arg, L"service")) 129 | m_appMode = APP_RUN_SERVICE; 130 | else if (!wcscmp(arg, L"install")) 131 | m_appMode = APP_INSTALL_SERVICE; 132 | else if (!wcscmp(arg, L"?")) 133 | m_appMode = APP_USAGE_SHOW; 134 | else if (!wcsncmp(arg, ARG_USERNAME, _countof(ARG_USERNAME) - 1)) 135 | StrCopy(m_username, _countof(m_username), arg + _countof(ARG_USERNAME) - 1); 136 | else if (!wcsncmp(arg, ARG_PASSWORD, _countof(ARG_PASSWORD) - 1)) 137 | StrCopy(m_password, _countof(m_password), arg + _countof(ARG_PASSWORD) - 1); 138 | else 139 | CmdLineError("ERROR: unknown command-line option -'%S'\n", arg); 140 | } 141 | 142 | 143 | //=================================== 144 | void CmdLineOptions::ParseArg (const wchar arg[]) { 145 | CmdLineError("ERROR: unknown command-line argument '%S'\n", arg); 146 | } 147 | 148 | 149 | //=================================== 150 | void __cdecl CmdLineOptions::CmdLineError (const char fmt[], ...) { 151 | va_list args; 152 | va_start(args, fmt); 153 | #ifdef _CONSOLE 154 | vfprintf(stderr, fmt, args); 155 | #else 156 | LogErrorV(fmt, args); 157 | #endif 158 | va_end(args); 159 | m_error = true; 160 | } 161 | 162 | 163 | /************************************ 164 | * 165 | * Service run 166 | * 167 | ***/ 168 | 169 | 170 | struct ServiceParam : public CServiceStatus { 171 | SERVICE_STATUS_HANDLE handle; 172 | SERVICE_STATUS status; 173 | 174 | void SetState (DWORD state); 175 | 176 | // From CServiceStatus 177 | virtual void UpdateStatus ( 178 | unsigned checkPoint, 179 | unsigned waitHintMs 180 | ); 181 | }; 182 | 183 | 184 | //=================================== 185 | void ServiceParam::SetState (DWORD state) { 186 | status.dwCurrentState = state; 187 | if (handle && !SetServiceStatus(handle, &status)) 188 | LOG_OS_LAST_ERROR(L"SetServiceStatus"); 189 | } 190 | 191 | 192 | //=================================== 193 | void ServiceParam::UpdateStatus ( 194 | unsigned checkPoint, 195 | unsigned waitHintMs 196 | ) { 197 | if (handle) { 198 | status.dwCheckPoint = checkPoint; 199 | status.dwWaitHint = waitHintMs; 200 | SetServiceStatus(handle, &status); 201 | } 202 | } 203 | 204 | 205 | //=================================== 206 | static DWORD WINAPI ServiceHandlerEx ( 207 | DWORD dwControl, 208 | DWORD , // dwEventType, 209 | LPVOID , // lpEventData, 210 | LPVOID lpContext 211 | ) { 212 | ServiceParam & sp = * (ServiceParam *) lpContext; 213 | switch (dwControl) { 214 | case SERVICE_CONTROL_STOP: 215 | case SERVICE_CONTROL_SHUTDOWN: 216 | sp.SetState(SERVICE_STOP_PENDING); 217 | s_app->SignalStop(); 218 | return NO_ERROR; 219 | 220 | case SERVICE_CONTROL_INTERROGATE: 221 | SetServiceStatus(sp.handle, &sp.status); 222 | return NO_ERROR; 223 | } 224 | 225 | return ERROR_CALL_NOT_IMPLEMENTED; 226 | } 227 | 228 | 229 | //=================================== 230 | // This section is only necessary because Visual Studio 6 doesn't have bindings 231 | // for RegisterServiceCtrlHandlerExW so I have to manually load the library 232 | // that contains the function. Time to upgrade to VS10! 233 | static SERVICE_STATUS_HANDLE RegisterService (ServiceParam * sp) { 234 | HMODULE lib = NULL; 235 | SERVICE_STATUS_HANDLE handle = NULL; 236 | for (;;) { 237 | // Load service library 238 | lib = LoadLibraryW(L"AdvApi32.dll"); 239 | if (!lib) { 240 | LOG_OS_LAST_ERROR(L"LoadLibraryW"); 241 | break; 242 | } 243 | 244 | // Bind to RegisterServiceCtrlHandlerExW 245 | typedef DWORD (WINAPI * LPHANDLER_FUNCTION_EX)(DWORD,DWORD,LPVOID,LPVOID); 246 | typedef SERVICE_STATUS_HANDLE (WINAPI * FRegisterServiceCtrlHandlerExW)( 247 | LPCWSTR lpServiceName, 248 | LPHANDLER_FUNCTION_EX lpHandlerProc, 249 | LPVOID lpContext 250 | ); 251 | FRegisterServiceCtrlHandlerExW RegisterServiceCtrlHandlerExW; 252 | * (FARPROC *) &RegisterServiceCtrlHandlerExW = GetProcAddress(lib, "RegisterServiceCtrlHandlerExW"); 253 | if (!RegisterServiceCtrlHandlerExW) { 254 | LOG_OS_LAST_ERROR(L"GetProcAddress"); 255 | break; 256 | } 257 | 258 | // Register service handler 259 | handle = RegisterServiceCtrlHandlerExW(s_app->Name(), ServiceHandlerEx, sp); 260 | if (!handle) { 261 | LOG_OS_LAST_ERROR(L"RegisterServiceCtrlHandlerExW"); 262 | break; 263 | } 264 | 265 | // Success! 266 | break; 267 | } 268 | if (lib) 269 | FreeLibrary(lib); 270 | return handle; 271 | } 272 | 273 | 274 | //=================================== 275 | static int ApplicationRun (bool serviceMode) { 276 | // Initialize service parameters 277 | ServiceParam sp; 278 | sp.handle = NULL; 279 | memset(&sp.status, 0, sizeof(sp.status)); 280 | sp.status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; 281 | sp.status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; 282 | 283 | // Register service application 284 | if (serviceMode) { 285 | if (NULL == (sp.handle = RegisterService(&sp))) 286 | FatalError(); 287 | } 288 | 289 | // Start service 290 | sp.SetState(SERVICE_START_PENDING); 291 | if (!serviceMode) 292 | MainWndInitialize(s_app->Name()); 293 | TaskInitialize(); 294 | ConfigInitialize(); 295 | ConfigMonitorFile(L"Config\\Srv.ini"); 296 | s_app->Start(&sp); 297 | 298 | // Service is running 299 | sp.SetState(SERVICE_RUNNING); 300 | s_app->Run(serviceMode); 301 | 302 | // Stop service 303 | sp.SetState(SERVICE_STOP_PENDING); 304 | s_app->Stop(); 305 | ConfigDestroy(); 306 | TaskDestroy(); 307 | MainWndDestroy(); 308 | 309 | // Service is stopped 310 | int exitCode = s_app->ExitCode(); 311 | sp.status.dwWin32ExitCode = (DWORD) exitCode; 312 | sp.SetState(SERVICE_STOPPED); 313 | return exitCode; 314 | } 315 | 316 | 317 | //=================================== 318 | static void WINAPI ServiceMain (DWORD, LPWSTR *) { 319 | (void) ApplicationRun(true); 320 | } 321 | 322 | 323 | //=================================== 324 | static int ServiceRun () { 325 | // Get the application name in a non-const buffer 326 | const wchar * name = s_app->Name(); 327 | unsigned chars = StrChars(name); 328 | wchar * nameBuf = (wchar *) _alloca(chars * sizeof(nameBuf[0])); 329 | StrCopy(nameBuf, chars, name); 330 | 331 | // Start the application 332 | SERVICE_TABLE_ENTRYW services[] = { 333 | { nameBuf, ServiceMain }, 334 | { NULL, NULL } 335 | }; 336 | 337 | // If this function fails with error 1063 it means that a user is attempting to start the 338 | // service from the command line using the "/service" argument; this doesn't work. Services 339 | // must be started using the service control manager; for example: sc start 340 | // (after the service has been installed using /install). 341 | if (!StartServiceCtrlDispatcherW(services)) { 342 | LOG_OS_LAST_ERROR(L"StartServiceCtrlDispatcherW"); 343 | return 1; 344 | } 345 | 346 | // Success! 347 | return s_app->ExitCode(); 348 | } 349 | 350 | 351 | /************************************ 352 | * 353 | * Service install 354 | * 355 | ***/ 356 | 357 | 358 | //=================================== 359 | static bool ValidateInstallationDrive (const wchar path[]) { 360 | // Get the root directory of the path including trailing slash 361 | wchar root[MAX_PATH]; 362 | StrCopy(root, _countof(root), path); 363 | PathStripToRootW(root); 364 | 365 | // Validate the drive type; services can only run from "FIXED" drives 366 | UINT type = GetDriveTypeW(root); 367 | if (type != DRIVE_FIXED) { 368 | wchar err[128]; 369 | StrPrintf( 370 | err, 371 | _countof(err), 372 | L"Cannot install service on drive type %u", 373 | type 374 | ); 375 | LOG_OS_ERROR(err, ERROR_INVALID_DRIVE); 376 | return false; 377 | } 378 | 379 | // QueryDosDeviceW doesn't like trailing backslash 380 | wchar * slash = PathRemoveBackslashW(root); 381 | if (slash && *slash == '\\') 382 | *slash = 0; 383 | 384 | // Is this a SUBST drive? 385 | wchar drive[MAX_PATH]; 386 | if (!QueryDosDeviceW(root, drive, _countof(drive))) { 387 | LOG_OS_LAST_ERROR(L"QueryDosDeviceW"); 388 | return false; 389 | } 390 | 391 | // FRAGILE: surely there is a better way to detect a SUBST! 392 | if (drive[0] == '\\' 393 | && drive[1] == '?' 394 | && drive[2] == '?' 395 | && drive[3] == '\\' 396 | && drive[4] != 0 397 | && drive[5] == ':' 398 | ) { 399 | LOG_OS_ERROR(L"Cannot install service on subst drive", ERROR_INVALID_DRIVE); 400 | return false; 401 | } 402 | 403 | return true; 404 | } 405 | 406 | 407 | //=================================== 408 | static int ServiceInstall ( 409 | const wchar username[], 410 | const wchar password[] 411 | ) { 412 | int exitCode = 1; 413 | SC_HANDLE hManager = NULL; 414 | SC_HANDLE hService = NULL; 415 | for (;;) { 416 | // Find the path to the executable 417 | wchar path[MAX_PATH]; 418 | PathGetExeFullPath(path, _countof(path)); 419 | 420 | // If username is specified, password must be specified 421 | // If password is specified, username must be specified 422 | if (username && !username[0]) 423 | username = NULL; 424 | if (password && !password[0]) 425 | password = NULL; 426 | if (!username != !password) { 427 | LOG_OS_ERROR(L"Incorrect username/password usage", ERROR_ACCESS_DENIED); 428 | break; 429 | } 430 | 431 | // Is this a valid installation drive for a service application? 432 | if (!ValidateInstallationDrive(path)) 433 | break; 434 | 435 | // Open the service control manager 436 | if (NULL == (hManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE))) { 437 | LOG_OS_LAST_ERROR(L"OpenSCManager"); 438 | break; 439 | } 440 | 441 | // Create the service 442 | wchar cmdLine[MAX_PATH + 100]; 443 | StrPrintf(cmdLine, _countof(cmdLine), L"\"%s\" /service", path); 444 | const wchar * name = s_app->Name(); 445 | if (NULL == (hService = CreateServiceW( 446 | hManager, 447 | name, 448 | name, 449 | SERVICE_ALL_ACCESS, 450 | SERVICE_WIN32_OWN_PROCESS, 451 | SERVICE_AUTO_START, 452 | SERVICE_ERROR_NORMAL, 453 | cmdLine, 454 | NULL, // no load ordering group 455 | NULL, // no tag identifier 456 | NULL, // no dependencies 457 | username, 458 | password 459 | ))) { 460 | LOG_OS_LAST_ERROR(L"CreateServiceW"); 461 | break; 462 | } 463 | 464 | // Set service restart time after crash 465 | SC_ACTION actions[3] = { 466 | { SC_ACTION_RESTART, 5 * 1000 }, 467 | { SC_ACTION_RESTART, 15 * 1000 }, 468 | { SC_ACTION_RESTART, 30 * 1000 }, 469 | }; 470 | SERVICE_FAILURE_ACTIONSW failureActions; 471 | failureActions.dwResetPeriod = 1 * 60 * 60; // 1 hour in seconds 472 | failureActions.lpRebootMsg = L""; 473 | failureActions.lpCommand = L""; 474 | failureActions.cActions = _countof(actions); 475 | failureActions.lpsaActions = actions; 476 | if (!ChangeServiceConfig2W( 477 | hService, 478 | SERVICE_CONFIG_FAILURE_ACTIONS, 479 | &failureActions 480 | )) { 481 | LOG_OS_LAST_ERROR(L"ChangeServiceConfig2W"); 482 | break; 483 | } 484 | 485 | // Set service description 486 | SERVICE_DESCRIPTIONW descrip; 487 | descrip.lpDescription = const_cast(s_app->Description()); 488 | if (!ChangeServiceConfig2W( 489 | hService, 490 | SERVICE_CONFIG_DESCRIPTION, 491 | &descrip 492 | )) { 493 | LOG_OS_LAST_ERROR(L"ChangeServiceConfig2W"); 494 | break; 495 | } 496 | 497 | // Success! 498 | exitCode = 0; 499 | break; 500 | } 501 | if (hService) 502 | CloseServiceHandle(hService); 503 | if (hManager) 504 | CloseServiceHandle(hManager); 505 | return exitCode; 506 | } 507 | 508 | 509 | /************************************ 510 | * 511 | * Exports 512 | * 513 | ***/ 514 | 515 | 516 | //=================================== 517 | void ServiceSignalStop () { 518 | s_app->SignalStop(); 519 | } 520 | 521 | 522 | //=================================== 523 | int ServiceMain (CApplication * app) { 524 | // Service applications run out of system directory; 525 | // reset to application directory to normalize behavior 526 | // running as a service and as an application 527 | s_app = app; 528 | PathSetProgramDirectory(); 529 | LogInitialize(s_app->Name()); 530 | DebugSetThreadName("Main"); 531 | 532 | // Parse the command line 533 | CmdLineOptions opt(GetCommandLineW()); 534 | 535 | // Run the application 536 | int exitCode = 1; 537 | switch (opt.m_appMode) { 538 | case APP_RUN_APPLICATION: 539 | exitCode = ApplicationRun(false); 540 | break; 541 | 542 | case APP_RUN_SERVICE: 543 | exitCode = ServiceRun(); 544 | break; 545 | 546 | case APP_INSTALL_SERVICE: 547 | exitCode = ServiceInstall(opt.m_username, opt.m_password); 548 | break; 549 | 550 | case APP_USAGE_SHOW: 551 | Usage(); 552 | break; 553 | 554 | case APP_FAILED_ERROR: 555 | break; 556 | } 557 | 558 | // Complete! 559 | LogError("Exit code %u\n", exitCode); 560 | LogDestroy(); 561 | return exitCode; 562 | } 563 | 564 | 565 | //=================================== 566 | // MIT License 567 | // 568 | // Copyright (c) 2010 by Patrick Wyatt 569 | // 570 | // Permission is hereby granted, free of charge, to any person obtaining a copy 571 | // of this software and associated documentation files (the "Software"), to deal 572 | // in the Software without restriction, including without limitation the rights 573 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 574 | // copies of the Software, and to permit persons to whom the Software is 575 | // furnished to do so, subject to the following conditions: 576 | // 577 | // The above copyright notice and this permission notice shall be included in 578 | // all copies or substantial portions of the Software. 579 | // 580 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 581 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 582 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 583 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 584 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 585 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 586 | // THE SOFTWARE. 587 | //=================================== 588 | --------------------------------------------------------------------------------