├── .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 |
--------------------------------------------------------------------------------