├── .gitignore ├── LICENSE ├── README.md ├── bin ├── plugin1.dll ├── plugin1.exp ├── plugin1.lib ├── plugin1d.dll ├── plugin1d.exp ├── plugin1d.ilk └── plugin1d.lib ├── demo ├── customcomponent1 │ ├── CustomComponent1.cpp │ ├── CustomComponent1.h │ ├── CustomComponent1Activator.cpp │ ├── customcomponent1.vcxproj │ └── customcomponent1.vcxproj.filters ├── demo.sln ├── demo.v12.suo ├── demo │ ├── DemoActivator.cpp │ ├── DemoGame.cpp │ ├── DemoGame.h │ ├── demo.vcxproj │ └── demo.vcxproj.filters ├── gameengine.contract │ ├── component.h │ ├── contract.cpp │ ├── contract.h │ ├── game.h │ ├── gameengine.contract.vcxproj │ ├── gameengine.contract.vcxproj.filters │ └── gameengine.contract.vcxproj.user └── gameengine │ ├── gameengine.vcxproj │ ├── gameengine.vcxproj.filters │ └── main.cpp ├── plugin └── plugin │ ├── contract.h │ ├── core │ ├── moduleloader.cpp │ ├── moduleloader.h │ ├── plugincontext.cpp │ └── plugincontext.h │ ├── defines.h │ └── pluginobject1.h └── projects └── vs2013 ├── plugin.sln ├── plugin.v12.suo ├── plugin.vcxproj ├── plugin.vcxproj.filters └── plugin.vcxproj.user /.gitignore: -------------------------------------------------------------------------------- 1 | **/*.sdf 2 | **/*.opensdf 3 | **/*.suo 4 | **/*.obj 5 | **/*.pdb 6 | **/*.vsp 7 | **/Debug/* 8 | **/Release/* 9 | projects/vs2013/ipch/* 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Per Andersson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | plugin 2 | ====== 3 | 4 | This project is a C++ plugin system heavily influensed of Component Object Model released by Microsoft. 5 | 6 | Please read the [wiki](https://github.com/perandersson/plugin/wiki) for more information. 7 | 8 | ### Credits 9 | 10 | http://msdn.microsoft.com/en-us/library/windows/desktop/ee663262(v=vs.85).aspx - Microsoft -------------------------------------------------------------------------------- /bin/plugin1.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perandersson/plugin/1602fa6cd97fcacb62d72084c03f22bd7117951a/bin/plugin1.dll -------------------------------------------------------------------------------- /bin/plugin1.exp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perandersson/plugin/1602fa6cd97fcacb62d72084c03f22bd7117951a/bin/plugin1.exp -------------------------------------------------------------------------------- /bin/plugin1.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perandersson/plugin/1602fa6cd97fcacb62d72084c03f22bd7117951a/bin/plugin1.lib -------------------------------------------------------------------------------- /bin/plugin1d.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perandersson/plugin/1602fa6cd97fcacb62d72084c03f22bd7117951a/bin/plugin1d.dll -------------------------------------------------------------------------------- /bin/plugin1d.exp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perandersson/plugin/1602fa6cd97fcacb62d72084c03f22bd7117951a/bin/plugin1d.exp -------------------------------------------------------------------------------- /bin/plugin1d.ilk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perandersson/plugin/1602fa6cd97fcacb62d72084c03f22bd7117951a/bin/plugin1d.ilk -------------------------------------------------------------------------------- /bin/plugin1d.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perandersson/plugin/1602fa6cd97fcacb62d72084c03f22bd7117951a/bin/plugin1d.lib -------------------------------------------------------------------------------- /demo/customcomponent1/CustomComponent1.cpp: -------------------------------------------------------------------------------- 1 | #include "CustomComponent1.h" 2 | #include 3 | 4 | CustomComponent1::CustomComponent1() : mRefCount(0) 5 | { 6 | total = 0; 7 | } 8 | 9 | CustomComponent1::~CustomComponent1() 10 | { 11 | 12 | } 13 | 14 | void CustomComponent1::Update(float dt) 15 | { 16 | //std::cout << "Updating CustomComponent1: " << dt << std::endl; 17 | total += dt; 18 | } 19 | 20 | PL_UINT64 CustomComponent1::AddRef() 21 | { 22 | mRefCount++; 23 | return mRefCount; 24 | } 25 | 26 | PL_UINT64 CustomComponent1::Release() 27 | { 28 | if (--mRefCount == 0) { 29 | delete this; 30 | return 0; 31 | } 32 | return mRefCount; 33 | } 34 | 35 | PL_RES CustomComponent1::ConvertToType(PL_TYPE type, void** _out_Ptr) 36 | { 37 | if (type == PL_TYPEOF(gameengine::IComponent)) { 38 | *_out_Ptr = static_cast(this); 39 | AddRef(); 40 | return PL_OK; 41 | } 42 | *_out_Ptr = nullptr; 43 | return PL_ERR; 44 | } 45 | -------------------------------------------------------------------------------- /demo/customcomponent1/CustomComponent1.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../gameengine.contract/contract.h" 3 | 4 | class CustomComponent1 : public gameengine::IComponent 5 | { 6 | public: 7 | CustomComponent1(); 8 | virtual ~CustomComponent1(); 9 | 10 | public: 11 | virtual void Update(float dt); 12 | virtual PL_UINT64 AddRef(); 13 | virtual PL_UINT64 Release(); 14 | virtual PL_RES ConvertToType(PL_TYPE type, void** _out_Ptr); 15 | 16 | private: 17 | float total; 18 | int mRefCount; 19 | }; 20 | -------------------------------------------------------------------------------- /demo/customcomponent1/CustomComponent1Activator.cpp: -------------------------------------------------------------------------------- 1 | #include "../gameengine.contract/contract.h" 2 | #include "CustomComponent1.h" 3 | #include 4 | 5 | #include 6 | 7 | PL_RES MyEntryPoint() { 8 | PL_RES res = Plugin_RegisterObject(PL_TYPEOF(gameengine::IComponent), new CustomComponent1()); 9 | return res; 10 | } 11 | 12 | DEFINE_ENTRYPOINT(MyEntryPoint); -------------------------------------------------------------------------------- /demo/customcomponent1/customcomponent1.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {C4E45C96-41C6-4B64-A5C1-B7EE3545FD02} 15 | Win32Proj 16 | customcomponent1 17 | 18 | 19 | 20 | DynamicLibrary 21 | true 22 | v120 23 | MultiByte 24 | 25 | 26 | DynamicLibrary 27 | false 28 | v120 29 | true 30 | Unicode 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | 45 | 46 | false 47 | 48 | 49 | 50 | 51 | 52 | Level3 53 | Disabled 54 | WIN32;_DEBUG;_WINDOWS;_USRDLL;PLUGIN_EXPORTS;%(PreprocessorDefinitions) 55 | ../../plugin 56 | 57 | 58 | Windows 59 | true 60 | ../../bin;%(AdditionalLibraryDirectories) 61 | plugin1d.lib;%(AdditionalDependencies) 62 | 63 | 64 | 65 | 66 | Level3 67 | 68 | 69 | MaxSpeed 70 | true 71 | true 72 | WIN32;NDEBUG;_WINDOWS;_USRDLL;PLUGIN_EXPORTS;%(PreprocessorDefinitions) 73 | ../../plugin 74 | 75 | 76 | Windows 77 | true 78 | true 79 | true 80 | ../../bin;%(AdditionalLibraryDirectories) 81 | plugin1.lib;%(AdditionalDependencies) 82 | 83 | 84 | 85 | 86 | {ac42a67a-cdf4-4870-b7a3-38e6d73365bf} 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /demo/customcomponent1/customcomponent1.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 10 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 11 | 12 | 13 | 14 | 15 | Source Files 16 | 17 | 18 | 19 | 20 | Source Files 21 | 22 | 23 | Source Files 24 | 25 | 26 | -------------------------------------------------------------------------------- /demo/demo.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Express 2013 for Windows Desktop 4 | VisualStudioVersion = 12.0.30110.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gameengine.contract", "gameengine.contract\gameengine.contract.vcxproj", "{AC42A67A-CDF4-4870-B7A3-38E6D73365BF}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gameengine", "gameengine\gameengine.vcxproj", "{64961D9D-79FC-4864-803F-582D621A500F}" 9 | ProjectSection(ProjectDependencies) = postProject 10 | {AC42A67A-CDF4-4870-B7A3-38E6D73365BF} = {AC42A67A-CDF4-4870-B7A3-38E6D73365BF} 11 | EndProjectSection 12 | EndProject 13 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "demo", "demo\demo.vcxproj", "{AB5027E7-846D-4C83-8216-ACD9A7A6649E}" 14 | EndProject 15 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "customcomponent1", "customcomponent1\customcomponent1.vcxproj", "{C4E45C96-41C6-4B64-A5C1-B7EE3545FD02}" 16 | EndProject 17 | Global 18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 19 | Debug|Win32 = Debug|Win32 20 | Release|Win32 = Release|Win32 21 | EndGlobalSection 22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 23 | {AC42A67A-CDF4-4870-B7A3-38E6D73365BF}.Debug|Win32.ActiveCfg = Debug|Win32 24 | {AC42A67A-CDF4-4870-B7A3-38E6D73365BF}.Debug|Win32.Build.0 = Debug|Win32 25 | {AC42A67A-CDF4-4870-B7A3-38E6D73365BF}.Release|Win32.ActiveCfg = Release|Win32 26 | {AC42A67A-CDF4-4870-B7A3-38E6D73365BF}.Release|Win32.Build.0 = Release|Win32 27 | {64961D9D-79FC-4864-803F-582D621A500F}.Debug|Win32.ActiveCfg = Debug|Win32 28 | {64961D9D-79FC-4864-803F-582D621A500F}.Debug|Win32.Build.0 = Debug|Win32 29 | {64961D9D-79FC-4864-803F-582D621A500F}.Release|Win32.ActiveCfg = Release|Win32 30 | {64961D9D-79FC-4864-803F-582D621A500F}.Release|Win32.Build.0 = Release|Win32 31 | {AB5027E7-846D-4C83-8216-ACD9A7A6649E}.Debug|Win32.ActiveCfg = Debug|Win32 32 | {AB5027E7-846D-4C83-8216-ACD9A7A6649E}.Debug|Win32.Build.0 = Debug|Win32 33 | {AB5027E7-846D-4C83-8216-ACD9A7A6649E}.Release|Win32.ActiveCfg = Release|Win32 34 | {AB5027E7-846D-4C83-8216-ACD9A7A6649E}.Release|Win32.Build.0 = Release|Win32 35 | {C4E45C96-41C6-4B64-A5C1-B7EE3545FD02}.Debug|Win32.ActiveCfg = Debug|Win32 36 | {C4E45C96-41C6-4B64-A5C1-B7EE3545FD02}.Debug|Win32.Build.0 = Debug|Win32 37 | {C4E45C96-41C6-4B64-A5C1-B7EE3545FD02}.Release|Win32.ActiveCfg = Release|Win32 38 | {C4E45C96-41C6-4B64-A5C1-B7EE3545FD02}.Release|Win32.Build.0 = Release|Win32 39 | EndGlobalSection 40 | GlobalSection(SolutionProperties) = preSolution 41 | HideSolutionNode = FALSE 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /demo/demo.v12.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perandersson/plugin/1602fa6cd97fcacb62d72084c03f22bd7117951a/demo/demo.v12.suo -------------------------------------------------------------------------------- /demo/demo/DemoActivator.cpp: -------------------------------------------------------------------------------- 1 | #include "../gameengine.contract/contract.h" 2 | #include "DemoGame.h" 3 | #include 4 | 5 | #include 6 | 7 | class InternalComponent : public gameengine::IComponent 8 | { 9 | public: 10 | InternalComponent() { counter = 0; } 11 | virtual ~InternalComponent() {} 12 | 13 | virtual void Update(float dt) { 14 | counter += dt; 15 | } 16 | 17 | float counter; 18 | }; 19 | 20 | DemoGame* gGame; 21 | 22 | PL_RES GetAllComponents(PL_TYPE type, PIPluginObject object) { 23 | gameengine::IComponent* component; 24 | if (object->ConvertToType(PL_TYPEOF(gameengine::IComponent), (void**)&component)) { 25 | gGame->AddComponent(component); 26 | } 27 | return PL_OK; 28 | } 29 | 30 | PL_RES MyEntryPoint() { 31 | gGame = new DemoGame(); 32 | Plugin_RegisterObject(PL_TYPEOF(gameengine::IGame), gGame); 33 | 34 | Plugin_GetObjects(PL_TYPEOF(gameengine::IComponent), GetAllComponents); 35 | 36 | IPluginObject* ptr; 37 | if (Plugin_GetObject(PL_TYPEOF(gameengine::IComponent), &ptr)) { 38 | gameengine::IComponent* component; 39 | if (ptr->ConvertToType(PL_TYPEOF(gameengine::IComponent), (void**)&component)) { 40 | gGame->AddComponent(component); 41 | } 42 | ptr->Release(); 43 | } 44 | 45 | return PL_OK; 46 | } 47 | 48 | DEFINE_ENTRYPOINT(MyEntryPoint); 49 | -------------------------------------------------------------------------------- /demo/demo/DemoGame.cpp: -------------------------------------------------------------------------------- 1 | #include "DemoGame.h" 2 | #include 3 | #include 4 | 5 | DemoGame::DemoGame() :mRefCount(0) 6 | { 7 | 8 | } 9 | 10 | DemoGame::~DemoGame() 11 | { 12 | std::list::iterator it = mComponents.begin(); 13 | std::list::iterator end = mComponents.end(); 14 | for (; it != end; ++it) { 15 | (*it)->Release(); 16 | } 17 | } 18 | 19 | void DemoGame::AddComponent(gameengine::IComponent* component) 20 | { 21 | mComponents.push_back(component); 22 | } 23 | 24 | void DemoGame::AddInternalComponent(gameengine::IComponent* component) 25 | { 26 | mInternalComponents.push_back(component); 27 | } 28 | 29 | void DemoGame::StartGame() 30 | { 31 | std::cout << "Starting demogame" << std::endl; 32 | DWORD systime = GetTickCount(); 33 | 34 | #ifdef _DEBUG 35 | for (int i = 0; i < 1000000; i++) { 36 | #else 37 | for (int i = 0; i < 100000000; i++) { 38 | #endif 39 | std::list::iterator it = mComponents.begin(); 40 | std::list::iterator end = mComponents.end(); 41 | for (; it != end; ++it) { 42 | (*it)->Update(0.1f); 43 | } 44 | } 45 | DWORD systime2 = GetTickCount(); 46 | 47 | DWORD systime3 = GetTickCount(); 48 | #ifdef _DEBUG 49 | for (int i = 0; i < 1000000; i++) { 50 | #else 51 | for (int i = 0; i < 100000000; i++) { 52 | #endif 53 | std::list::iterator it = mInternalComponents.begin(); 54 | std::list::iterator end = mInternalComponents.end(); 55 | for (; it != end; ++it) { 56 | (*it)->Update(0.1f); 57 | } 58 | } 59 | DWORD systime4 = GetTickCount(); 60 | 61 | std::cout << "External time: " << systime2 - systime << ", Internal time: " << systime4 - systime3 << std::endl; 62 | } 63 | 64 | 65 | PL_UINT64 DemoGame::AddRef() 66 | { 67 | mRefCount++; 68 | return mRefCount; 69 | } 70 | 71 | PL_UINT64 DemoGame::Release() 72 | { 73 | if (--mRefCount == 0) { 74 | delete this; 75 | return 0; 76 | } 77 | return mRefCount; 78 | } 79 | 80 | PL_RES DemoGame::ConvertToType(PL_TYPE type, void** _out_Ptr) 81 | { 82 | if (_out_Ptr == nullptr) 83 | return PL_ERR; 84 | 85 | if (type == PL_TYPEOF(gameengine::IGame)) { 86 | *_out_Ptr = static_cast(this); 87 | AddRef(); 88 | return PL_OK; 89 | } 90 | *_out_Ptr = nullptr; 91 | return PL_ERR; 92 | } 93 | -------------------------------------------------------------------------------- /demo/demo/DemoGame.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../gameengine.contract/contract.h" 3 | #include 4 | 5 | 6 | class DemoGame : public gameengine::IGame 7 | { 8 | public: 9 | DemoGame(); 10 | virtual ~DemoGame(); 11 | 12 | void AddInternalComponent(gameengine::IComponent* component); 13 | void AddComponent(gameengine::IComponent* component); 14 | 15 | 16 | public: 17 | virtual void StartGame(); 18 | 19 | virtual PL_UINT64 AddRef(); 20 | virtual PL_UINT64 Release(); 21 | virtual PL_RES ConvertToType(PL_TYPE type, void** _out_Ptr); 22 | 23 | private: 24 | std::list mComponents; 25 | std::list mInternalComponents; 26 | 27 | PL_UINT64 mRefCount; 28 | }; -------------------------------------------------------------------------------- /demo/demo/demo.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {AB5027E7-846D-4C83-8216-ACD9A7A6649E} 15 | Win32Proj 16 | demo 17 | 18 | 19 | 20 | DynamicLibrary 21 | true 22 | v120 23 | MultiByte 24 | 25 | 26 | DynamicLibrary 27 | false 28 | v120 29 | true 30 | Unicode 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | 45 | 46 | false 47 | 48 | 49 | 50 | 51 | 52 | Level3 53 | Disabled 54 | WIN32;_DEBUG;_WINDOWS;_USRDLL;PLUGIN_EXPORTS;%(PreprocessorDefinitions) 55 | ../../plugin 56 | 57 | 58 | Windows 59 | true 60 | ../../bin;%(AdditionalLibraryDirectories) 61 | plugin1d.lib;%(AdditionalDependencies) 62 | 63 | 64 | 65 | 66 | Level3 67 | 68 | 69 | MaxSpeed 70 | true 71 | true 72 | WIN32;NDEBUG;_WINDOWS;_USRDLL;PLUGIN_EXPORTS;%(PreprocessorDefinitions) 73 | ../../plugin 74 | 75 | 76 | Windows 77 | true 78 | true 79 | true 80 | plugin1.lib;%(AdditionalDependencies) 81 | ../../bin;%(AdditionalLibraryDirectories) 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | {ac42a67a-cdf4-4870-b7a3-38e6d73365bf} 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /demo/demo/demo.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | 10 | 11 | Source Files 12 | 13 | 14 | Source Files 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /demo/gameengine.contract/component.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace gameengine 5 | { 6 | // 7 | // The actual game instance 8 | DECLARE_INTERFACE(IComponent, 9343021366, IPluginObject) 9 | { 10 | virtual void Update(float dt) = 0; 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /demo/gameengine.contract/contract.cpp: -------------------------------------------------------------------------------- 1 | #include "contract.h" -------------------------------------------------------------------------------- /demo/gameengine.contract/contract.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "game.h" 4 | #include "component.h" -------------------------------------------------------------------------------- /demo/gameengine.contract/game.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace gameengine 5 | { 6 | // 7 | // The actual game instance 8 | DECLARE_INTERFACE(IGame, 800200966, IPluginObject) 9 | { 10 | virtual void StartGame() = 0; 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /demo/gameengine.contract/gameengine.contract.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {AC42A67A-CDF4-4870-B7A3-38E6D73365BF} 15 | Win32Proj 16 | gameenginecontract 17 | 18 | 19 | 20 | DynamicLibrary 21 | true 22 | v120 23 | MultiByte 24 | 25 | 26 | DynamicLibrary 27 | false 28 | v120 29 | true 30 | Unicode 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | 45 | 46 | false 47 | 48 | 49 | 50 | 51 | 52 | Level3 53 | Disabled 54 | WIN32;_DEBUG;_WINDOWS;_USRDLL;PLUGIN_EXPORTS;%(PreprocessorDefinitions) 55 | ../../plugin 56 | 57 | 58 | Windows 59 | true 60 | 61 | 62 | 63 | 64 | Level3 65 | 66 | 67 | MaxSpeed 68 | true 69 | true 70 | WIN32;NDEBUG;_WINDOWS;_USRDLL;PLUGIN_EXPORTS;%(PreprocessorDefinitions) 71 | ../../plugin 72 | 73 | 74 | Windows 75 | true 76 | true 77 | true 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /demo/gameengine.contract/gameengine.contract.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {e6b290d4-8b80-4bf3-92a8-24f5d4b298f4} 10 | 11 | 12 | 13 | 14 | Source Files 15 | 16 | 17 | Contract 18 | 19 | 20 | Contract 21 | 22 | 23 | 24 | 25 | Source Files 26 | 27 | 28 | -------------------------------------------------------------------------------- /demo/gameengine.contract/gameengine.contract.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /demo/gameengine/gameengine.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {64961D9D-79FC-4864-803F-582D621A500F} 15 | Win32Proj 16 | gameengine 17 | 18 | 19 | 20 | Application 21 | true 22 | v120 23 | MultiByte 24 | 25 | 26 | Application 27 | false 28 | v120 29 | true 30 | Unicode 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | 45 | 46 | false 47 | 48 | 49 | 50 | 51 | 52 | Level3 53 | Disabled 54 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 55 | ../../plugin;../gameengine.contract 56 | 57 | 58 | Console 59 | true 60 | plugin1d.lib;%(AdditionalDependencies) 61 | ../../bin;%(AdditionalLibraryDirectories) 62 | 63 | 64 | 65 | 66 | Level3 67 | 68 | 69 | MaxSpeed 70 | true 71 | true 72 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 73 | ../../plugin;../gameengine.contract 74 | 75 | 76 | Console 77 | true 78 | true 79 | true 80 | plugin1.lib;%(AdditionalDependencies) 81 | ../../bin;%(AdditionalLibraryDirectories) 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | {ac42a67a-cdf4-4870-b7a3-38e6d73365bf} 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /demo/gameengine/gameengine.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | 10 | 11 | Source Files 12 | 13 | 14 | -------------------------------------------------------------------------------- /demo/gameengine/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../gameengine.contract/contract.h" 3 | #include 4 | 5 | void StartGame() 6 | { 7 | PL_RES res = PL_OK; 8 | 9 | PIPluginObject object; 10 | res = Plugin_GetObject(PL_TYPEOF(gameengine::IGame), &object); assert(SUCCESS(res)); 11 | 12 | gameengine::IGame* game; 13 | res = object->ConvertToType(PL_TYPEOF(gameengine::IGame), (void**)&game); assert(SUCCESS(res)); 14 | 15 | game->StartGame(); 16 | 17 | SAFE_RELEASE(game); 18 | SAFE_RELEASE(object); 19 | } 20 | 21 | class HostAppService : public gameengine::IComponent 22 | { 23 | public: 24 | HostAppService() : mRefCount(1) { 25 | 26 | } 27 | 28 | virtual ~HostAppService() { 29 | 30 | } 31 | 32 | PL_UINT64 AddRef() { 33 | return mRefCount++; 34 | } 35 | 36 | PL_UINT64 Release() { 37 | if (--mRefCount == 0) { 38 | delete this; 39 | return 0; 40 | } 41 | return mRefCount; 42 | } 43 | 44 | PL_RES ConvertToType(PL_TYPE type, void** _out_Ptr) { 45 | if (type == PL_TYPEOF(gameengine::IComponent)) { 46 | *_out_Ptr = static_cast(this); 47 | AddRef(); 48 | return PL_OK; 49 | } 50 | *_out_Ptr = nullptr; 51 | return PL_ERR; 52 | } 53 | 54 | virtual void Update(float dt) { 55 | 56 | } 57 | 58 | private: 59 | PL_UINT64 mRefCount; 60 | }; 61 | 62 | int main() 63 | { 64 | PL_RES res = PL_OK; 65 | 66 | // Initialize the plugin framework 67 | res = Plugin_Init(); assert(SUCCESS(res)); 68 | 69 | // Register a service from host application (this program) and expose 70 | // it to the the loaded plugins 71 | res = Plugin_RegisterGlobalObject(PL_TYPEOF(gameengine::IComponent), new HostAppService()); assert(SUCCESS(res)); 72 | 73 | // Load our custom libraries 74 | PL_LIBID customcomponent1_dll = Plugin_LoadLibrary("customcomponent1.dll"); assert(customcomponent1_dll != PL_ERR); 75 | PL_LIBID demo_dll = Plugin_LoadLibrary("demo.dll"); assert(demo_dll != PL_ERR); 76 | 77 | // Start the game! 78 | StartGame(); 79 | 80 | // Unload libraries. This is done automatically by the Plugin_Release command. 81 | // You are only allowed to unload libraries that are not in use. 82 | res = Plugin_UnloadLibrary(demo_dll); assert(SUCCESS(res)); 83 | res = Plugin_UnloadLibrary(customcomponent1_dll); assert(SUCCESS(res)); 84 | 85 | // Release the plugin framework 86 | res = Plugin_Release(); assert(SUCCESS(res)); 87 | 88 | return 0; 89 | } 90 | -------------------------------------------------------------------------------- /plugin/plugin/contract.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef _PLUGIN_CONTRACT_H_ 3 | #define _PLUGIN_CONTRACT_H_ 4 | 5 | // 6 | // This is the version 1 of the plugin library 7 | // 8 | 9 | #include "pluginobject1.h" 10 | 11 | 12 | // 13 | // Typedefs for prettier interface 14 | // 15 | 16 | // Function signature for when retrieving a list of plugin objects. 17 | typedef PL_RES (*PIPluginObjectFunc)(PL_TYPE, PIPluginObject); 18 | 19 | extern "C" { 20 | 21 | // 22 | // Initializes the plugin framework 23 | // 24 | // @return PL_OK if successfull; PL_ERR otherwise; 25 | extern PLUGIN_CONTRACT_API PL_RES Plugin1_Init(); 26 | 27 | // 28 | // Releases the plugin frameworks internal resources 29 | // 30 | // @return PL_OK if successfull; PL_ERR otherwise; 31 | extern PLUGIN_CONTRACT_API PL_RES Plugin1_Release(); 32 | 33 | // 34 | // Retrieves the latest error code 35 | // 36 | // @return The last error code encountered by the plugin framework 37 | extern PLUGIN_CONTRACT_API PL_ERRCODE Plugin1_GetLastError(); 38 | 39 | // 40 | // Retrieves an object registered in the plugin framework. 41 | 42 | // This increases the reference counter of the object by invoking {@see IPluginObject1::AddRef}. If the 43 | // plugin framework returns a valid pointer then you are responsible for 44 | // invoking the {@see IPluginObject1::Release} method when you are done. 45 | // 46 | // @param type 47 | // The service type 48 | // @param _out_Ptr 49 | // The memory location where we want to put the object into 50 | // @return PL_OK if successfull; PL_ERR otherwise; 51 | extern PLUGIN_CONTRACT_API PL_RES Plugin1_GetObject(PL_TYPE type, PIPluginObject* _out_Ptr); 52 | 53 | // 54 | // Retrieves an object registered in the plugin framework from the specified library. 55 | 56 | // This increases the reference counter of the object by invoking {@see IPluginObject1::AddRef}. If the 57 | // plugin framework returns a valid pointer then you are responsible for 58 | // invoking the {@see IPluginObject1::Release} method when you are done. 59 | // 60 | // @param libraryID 61 | // The library ID returned by the Plugin1_LoadLibrary. 62 | // @param type 63 | // The service type 64 | // @param _out_Ptr 65 | // The memory location where we want to put the object into 66 | // @return PL_OK if successfull; PL_ERR otherwise; 67 | extern PLUGIN_CONTRACT_API PL_RES Plugin1_GetObjectFromLibrary(PL_LIBID libraryID, PL_TYPE type, PIPluginObject* _out_Ptr); 68 | 69 | // 70 | // Retrieves all objects registered in the plugin framework by the given type. An object is automatically 71 | // referenced- and deferenced when entering and exiting the supplied function pointer. Unless, of course, 72 | // you are planning on saving the pointer somewhere. Then you are required to invoke AddRef. 73 | // 74 | // All other access to the object follows the same pattern as Plugin1_GetObject. 75 | // 76 | // @param type 77 | // The service type 78 | // @param func 79 | // The function we want to invoke for each object found 80 | // @return PL_OK if successfull; PL_ERR otherwise; 81 | extern PLUGIN_CONTRACT_API PL_RES Plugin1_GetObjects(PL_TYPE type, PIPluginObjectFunc func); 82 | 83 | // 84 | // Register a new object into the plugin framework 85 | // 86 | // @param type 87 | // @param ptr 88 | // @return PL_OK if successfull; PL_ERR otherwise; 89 | extern PLUGIN_CONTRACT_API PL_RES Plugin1_RegisterObject(PL_TYPE type, PIPluginObject ptr); 90 | 91 | // 92 | // Register a new global object in the plugin framework. This is done by the host application. 93 | // 94 | // @param type 95 | // The type of the object 96 | // @param ptr 97 | // The pointer to the plugin object 98 | // @return PL_OK if successfull; PL_ERR otherwise 99 | extern PLUGIN_CONTRACT_API PL_RES Plugin1_RegisterGlobalObject(PL_TYPE type, PIPluginObject ptr); 100 | 101 | // 102 | // Load the supplied library 103 | // 104 | // @param filename 105 | // A null-terminated string containing the path to the plugin without the suffix 106 | // @return An non-zero identifier if successfull; PLRES_ERR otherwise; 107 | extern PLUGIN_CONTRACT_API PL_LIBID Plugin1_LoadLibrary(const char* filename); 108 | 109 | // 110 | // Unload the supplied library 111 | // 112 | // @param id 113 | // The library id. This value is returned by the Plugin1_LoadLibrary function. 114 | // @return PL_OK if successfull; PL_ERR otherwise; 115 | extern PLUGIN_CONTRACT_API PL_RES Plugin1_UnloadLibrary(PL_LIBID id); 116 | } 117 | 118 | // Function signature for the entry-point of the plugin 119 | typedef PL_RES(*Plugin1EntryPointFunc)(); 120 | 121 | #define Plugin_Init Plugin1_Init 122 | #define Plugin_Release Plugin1_Release 123 | #define Plugin_GetLastError Plugin1_GetLastError 124 | #define Plugin_GetObject Plugin1_GetObject 125 | #define Plugin_GetObjectFromLibrary Plugin1_GetObjectFromLibrary 126 | #define Plugin_GetObjects Plugin1_GetObjects 127 | #define Plugin_RegisterObject Plugin1_RegisterObject 128 | #define Plugin_RegisterGlobalObject Plugin1_RegisterGlobalObject 129 | #define Plugin_LoadLibrary Plugin1_LoadLibrary 130 | #define Plugin_UnloadLibrary Plugin1_UnloadLibrary 131 | 132 | #define PluginEntryPointFunc Plugin1EntryPointFunc 133 | 134 | // 135 | // Each plugin is required to supply an entry-point function for the plugin. 136 | // It is the entry-point that registers- the neccessary services used inside 137 | // the plugin framework 138 | #define DEFINE_ENTRYPOINT(Function) \ 139 | extern "C" { \ 140 | PLUGIN_API PL_RES __cdecl Plugin1_EntryPoint() { \ 141 | return Function##(); \ 142 | } \ 143 | } 144 | 145 | 146 | #endif 147 | -------------------------------------------------------------------------------- /plugin/plugin/core/moduleloader.cpp: -------------------------------------------------------------------------------- 1 | #include "moduleloader.h" 2 | #include 3 | 4 | #ifdef WIN32 5 | #define WIN32_LEAN_AND_MEAN 6 | #include 7 | 8 | LibraryHandle ModuleLoader::GetLibraryHandle(const char* fileName) 9 | { 10 | char tmp[1024] = { 0 }; 11 | sprintf(tmp, "%s.dll", fileName); 12 | 13 | auto library = LoadLibraryA(tmp); 14 | if (library == nullptr) 15 | return nullptr; 16 | 17 | assert(((PIMAGE_DOS_HEADER)library)->e_magic == IMAGE_DOS_SIGNATURE); 18 | 19 | return library; 20 | } 21 | 22 | void ModuleLoader::UnloadLibrary(LibraryHandle library) 23 | { 24 | FreeLibrary((HMODULE)library); 25 | } 26 | 27 | void* ModuleLoader::GetFunctionPtr(LibraryHandle library, const char* name) 28 | { 29 | FARPROC addr = GetProcAddress((HMODULE)library, name); 30 | return addr; 31 | } 32 | 33 | 34 | std::vector ModuleLoader::GetFunctionNames(LibraryHandle library) 35 | { 36 | std::vector functions; 37 | 38 | HMODULE lib = (HMODULE)library; 39 | PIMAGE_NT_HEADERS header = (PIMAGE_NT_HEADERS)((BYTE *)lib + ((PIMAGE_DOS_HEADER)lib)->e_lfanew); 40 | assert(header->Signature == IMAGE_NT_SIGNATURE); 41 | assert(header->OptionalHeader.NumberOfRvaAndSizes > 0); 42 | 43 | PIMAGE_EXPORT_DIRECTORY exports = (PIMAGE_EXPORT_DIRECTORY)((BYTE *)lib + header-> 44 | OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); 45 | PVOID names = (BYTE *)lib + exports->AddressOfNames; 46 | for (DWORD i = 0; i < exports->NumberOfNames; i++) { 47 | char* cname = (char *)lib + ((DWORD *)names)[i]; 48 | std::string name = std::string(cname); 49 | functions.push_back(name); 50 | } 51 | 52 | return functions; 53 | } 54 | 55 | #else 56 | 57 | #error Not implemented 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /plugin/plugin/core/moduleloader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | typedef void* LibraryHandle; 5 | 6 | class ModuleLoader 7 | { 8 | public: 9 | // 10 | // Load the supplied library and return a library handle for it 11 | // 12 | // @param fileName 13 | // The library filename 14 | // @return A library handle; NULL if no library could be loaded 15 | static LibraryHandle GetLibraryHandle(const char* fileName); 16 | 17 | // 18 | // Unload the supplied library 19 | // 20 | // @param library 21 | // The library 22 | static void UnloadLibrary(LibraryHandle library); 23 | 24 | // 25 | // Load a function from the supplied library and return a library handle for it 26 | // 27 | // @param library 28 | // The library 29 | // @param name 30 | // The function name 31 | // @return A function if found; NULL if no function was found 32 | template 33 | static T GetFunction(LibraryHandle library, const char* name) { 34 | void* ptr = GetFunctionPtr(library, name); 35 | if (ptr == nullptr) 36 | return nullptr; 37 | 38 | return reinterpret_cast(ptr); 39 | } 40 | 41 | // 42 | // Retrieves a list of all exported functions in a library 43 | // 44 | // @param library 45 | // The library 46 | // @return A list of all the functions exported into the supplied library. 47 | static std::vector GetFunctionNames(LibraryHandle library); 48 | 49 | private: 50 | static void* GetFunctionPtr(LibraryHandle library, const char* name); 51 | }; 52 | 53 | -------------------------------------------------------------------------------- /plugin/plugin/core/plugincontext.cpp: -------------------------------------------------------------------------------- 1 | #include "plugincontext.h" 2 | #include "moduleloader.h" 3 | #include 4 | #include 5 | #include 6 | 7 | class ObjectReference 8 | { 9 | public: 10 | ObjectReference(PL_TYPE type, PIPluginObject object) : mType(type), mObject(object) { 11 | object->AddRef(); 12 | } 13 | 14 | ObjectReference(const ObjectReference& lhs) : mType(lhs.mType), mObject(lhs.mObject) { 15 | mObject->AddRef(); 16 | } 17 | 18 | ~ObjectReference() { 19 | mObject->Release(); 20 | } 21 | 22 | PL_TYPE GetType() const { 23 | return mType; 24 | } 25 | 26 | PIPluginObject GetObject() const { 27 | return mObject; 28 | } 29 | 30 | private: 31 | PL_TYPE mType; 32 | PIPluginObject mObject; 33 | }; 34 | 35 | typedef std::vector> Objects; 36 | 37 | class PluginLibrary 38 | { 39 | public: 40 | PluginLibrary(LibraryHandle handle, PL_LIBID id) : mHandle(handle), mID(id) { 41 | 42 | } 43 | 44 | ~PluginLibrary() { 45 | mObjects.clear(); 46 | if (mHandle != nullptr) { 47 | ModuleLoader::UnloadLibrary(mHandle); 48 | mHandle = nullptr; 49 | } 50 | } 51 | 52 | LibraryHandle GetHandle() const{ 53 | return mHandle; 54 | } 55 | 56 | PL_LIBID GetID() const { 57 | return mID; 58 | } 59 | 60 | PIPluginObject GetObject(PL_TYPE type) { 61 | Objects::size_type size = mObjects.size(); 62 | for (Objects::size_type i = 0; i < size; ++i) { 63 | auto ref = mObjects[i]; 64 | if (ref->GetType() == type) { 65 | return ref->GetObject(); 66 | } 67 | } 68 | return nullptr; 69 | } 70 | 71 | PL_RES GetObjects(PL_TYPE type, PIPluginObjectFunc func) { 72 | Objects::size_type size = mObjects.size(); 73 | for (Objects::size_type i = 0; i < size; ++i) { 74 | auto ref = mObjects[i]; 75 | if (ref->GetType() == type) { 76 | auto object = ref->GetObject(); 77 | object->AddRef(); 78 | auto res = (*func)(type, object); 79 | object->Release(); 80 | if (res != PL_OK) 81 | return PL_ERR; 82 | } 83 | } 84 | return PL_OK; 85 | } 86 | 87 | void AddObject(PL_TYPE type, PIPluginObject object) { 88 | auto ref = std::shared_ptr(new ObjectReference(type, object)); 89 | mObjects.push_back(ref); 90 | } 91 | 92 | private: 93 | LibraryHandle mHandle; 94 | PL_LIBID mID; 95 | Objects mObjects; 96 | }; 97 | 98 | typedef std::vector> Libraries; 99 | 100 | class PluginContext 101 | { 102 | public: 103 | PluginContext() : mLastError(PL_ERRCODE_NOERROR), mNextID(1) { 104 | } 105 | 106 | PL_ERRCODE GetLastError() { 107 | return mLastError.load(); 108 | } 109 | 110 | void SetLastError(PL_ERRCODE errorCode) { 111 | mLastError.exchange(errorCode); 112 | } 113 | 114 | PL_RES GetObject(PL_TYPE type, PIPluginObject* _out_Ptr) { 115 | if (type == 0 || _out_Ptr == nullptr) { 116 | SetLastError(PL_ERRCODE_INVALIDARGUMENT); 117 | return PL_ERR; 118 | } 119 | 120 | auto globalObject = GetGlobalObject(type); 121 | if (globalObject != nullptr) { 122 | globalObject->AddRef(); 123 | *_out_Ptr = globalObject; 124 | return PL_OK; 125 | } 126 | 127 | // See if any libraries has exposed the supplied object 128 | Libraries::size_type size = mLibraries.size(); 129 | for (Libraries::size_type i = 0; i < size; ++i) { 130 | auto object = mLibraries[i]->GetObject(type); 131 | if (object != nullptr) { 132 | object->AddRef(); 133 | *_out_Ptr = object; 134 | return PL_OK; 135 | } 136 | } 137 | *_out_Ptr = nullptr; 138 | SetLastError(PL_ERRCODE_OBJECTNOTFOUND); 139 | return PL_ERR; 140 | } 141 | 142 | PL_RES GetObjectFromLibrary(PL_LIBID libraryID, PL_TYPE type, PIPluginObject* _out_Ptr) { 143 | if (libraryID == 0 || type == 0 || _out_Ptr == nullptr) { 144 | SetLastError(PL_ERRCODE_INVALIDARGUMENT); 145 | return PL_ERR; 146 | } 147 | 148 | 149 | Libraries::size_type size = mLibraries.size(); 150 | for (Libraries::size_type i = 0; i < size; ++i) { 151 | auto library = mLibraries[i]; 152 | if (library->GetID() == libraryID) { 153 | auto object = library->GetObject(type); 154 | if (object != nullptr) { 155 | object->AddRef(); 156 | *_out_Ptr = object; 157 | return PL_OK; 158 | } 159 | } 160 | } 161 | 162 | *_out_Ptr = nullptr; 163 | SetLastError(PL_ERRCODE_OBJECTNOTFOUND); 164 | return PL_ERR; 165 | } 166 | 167 | PL_RES GetObjects(PL_TYPE type, PIPluginObjectFunc func) { 168 | if (type == 0 || func == nullptr) { 169 | SetLastError(PL_ERRCODE_INVALIDARGUMENT); 170 | return PL_ERR; 171 | } 172 | 173 | auto res = GetGlobalObjects(type, func); 174 | if (res == PL_ERR) { 175 | SetLastError(PL_ERRCODE_GETOBJECTSFAILED); 176 | return PL_ERR; 177 | } 178 | 179 | // See if any libraries has exposed the supplied object 180 | Libraries::size_type size = mLibraries.size(); 181 | for (Libraries::size_type i = 0; i < size; ++i) { 182 | res = mLibraries[i]->GetObjects(type, func); 183 | if (res == PL_ERR) { 184 | SetLastError(PL_ERRCODE_GETOBJECTSFAILED); 185 | return PL_ERR; 186 | } 187 | } 188 | 189 | return PL_OK; 190 | } 191 | 192 | PIPluginObject GetGlobalObject(PL_TYPE type) { 193 | Objects::size_type size = mGlobalObjects.size(); 194 | for (Objects::size_type i = 0; i < size; ++i) { 195 | auto ref = mGlobalObjects[i]; 196 | if (ref->GetType() == type) { 197 | return ref->GetObject(); 198 | } 199 | } 200 | return nullptr; 201 | } 202 | 203 | PL_RES GetGlobalObjects(PL_TYPE type, PIPluginObjectFunc func) { 204 | Objects::size_type size = mGlobalObjects.size(); 205 | for (Objects::size_type i = 0; i < size; ++i) { 206 | auto ref = mGlobalObjects[i]; 207 | if (ref->GetType() == type) { 208 | auto object = ref->GetObject(); 209 | object->AddRef(); 210 | auto res = (*func)(type, object); 211 | object->Release(); 212 | if (res == PL_ERR) 213 | return PL_ERR; 214 | } 215 | } 216 | return PL_OK; 217 | } 218 | 219 | PL_RES RegisterObject(PL_TYPE type, PIPluginObject ptr) { 220 | if (type == 0 || ptr == nullptr) { 221 | SetLastError(PL_ERRCODE_INVALIDARGUMENT); 222 | return PL_ERR; 223 | } 224 | 225 | auto currentLibrary = mCurrentLibrary.lock(); 226 | if (currentLibrary.get() == nullptr) { 227 | SetLastError(PL_ERRCODE_NOACTIVEPLUGIN); 228 | return PL_ERR; 229 | } 230 | currentLibrary->AddObject(type, ptr); 231 | return PL_OK; 232 | } 233 | 234 | PL_RES RegisterGlobalObject(PL_TYPE type, PIPluginObject ptr) { 235 | if (type == 0 || ptr == nullptr) { 236 | SetLastError(PL_ERRCODE_INVALIDARGUMENT); 237 | return PL_ERR; 238 | } 239 | 240 | auto currentLibrary = mCurrentLibrary.lock(); 241 | if (currentLibrary.get() != nullptr) { 242 | SetLastError(PL_ERRCODE_NOTHOSTERROR); 243 | return PL_ERR; 244 | } 245 | 246 | auto ref = std::shared_ptr(new ObjectReference(type, ptr)); 247 | mGlobalObjects.push_back(ref); 248 | return PL_OK; 249 | } 250 | 251 | PL_LIBID LoadLibrary(const char* filename) { 252 | if (filename == nullptr) { 253 | SetLastError(PL_ERRCODE_INVALIDARGUMENT); 254 | return PL_ERR; 255 | } 256 | 257 | auto library = ModuleLoader::GetLibraryHandle(filename); 258 | if (library == nullptr) { 259 | SetLastError(PL_ERRCODE_LIBRARYNOTFOUND); 260 | return PL_ERR; 261 | } 262 | 263 | auto entryPoint = ModuleLoader::GetFunction(library, "Plugin1_EntryPoint"); 264 | if (entryPoint == nullptr) { 265 | ModuleLoader::UnloadLibrary(library); 266 | SetLastError(PL_ERRCODE_MISSINGENTRYPOINT); 267 | return PL_ERR; 268 | } 269 | 270 | PL_LIBID newID = mNextID++; 271 | auto ref = std::shared_ptr(new PluginLibrary(library, newID)); 272 | mCurrentLibrary = ref; 273 | PL_RES result = (*entryPoint)(); 274 | mCurrentLibrary.reset(); 275 | if (result == PL_ERR) { 276 | SetLastError(PL_ERRCODE_ENTRYPOINTFAILURE); 277 | return PL_ERR; 278 | } 279 | 280 | mLibraries.insert(mLibraries.begin(), ref); 281 | return newID; 282 | } 283 | 284 | PL_RES UnloadLibrary(PL_LIBID id) { 285 | if (id == 0) { 286 | SetLastError(PL_ERRCODE_INVALIDARGUMENT); 287 | return PL_ERR; 288 | } 289 | 290 | const Libraries::size_type size = mLibraries.size(); 291 | if (size == 0) { 292 | SetLastError(PL_ERRCODE_NONEXISTENTLIBID); 293 | return PL_ERR; 294 | } 295 | 296 | // You are only allowd to remove libraries in the reverse order of 297 | // when you added them. Remember that the items are always added at the top (push_front). 298 | for (Libraries::size_type i = 0; i < size; ++i) { 299 | auto library = mLibraries[i]; 300 | if (library->GetID() == id) { 301 | if (i != 0) { 302 | SetLastError(PL_ERRCODE_LIBRARYINUSE); 303 | return PL_ERR; 304 | } 305 | else { 306 | Libraries::iterator removeIt = mLibraries.begin() + i; 307 | mLibraries.erase(removeIt); 308 | return PL_OK; 309 | } 310 | } 311 | } 312 | 313 | SetLastError(PL_ERRCODE_NONEXISTENTLIBID); 314 | return PL_ERR; 315 | } 316 | 317 | private: 318 | std::atomic mLastError; 319 | std::atomic mNextID; 320 | Libraries mLibraries; 321 | std::weak_ptr mCurrentLibrary; 322 | Objects mGlobalObjects; 323 | }; 324 | 325 | PluginContext* gPluginContext = nullptr; 326 | 327 | PLUGIN_CONTRACT_API PL_RES Plugin_Init() 328 | { 329 | if (gPluginContext != nullptr) 330 | return PL_ERR; 331 | 332 | gPluginContext = new PluginContext(); 333 | return PL_OK; 334 | } 335 | 336 | PLUGIN_CONTRACT_API PL_RES Plugin_Release() 337 | { 338 | if (gPluginContext == nullptr) 339 | return PL_ERR; 340 | 341 | delete gPluginContext; 342 | return PL_OK; 343 | } 344 | 345 | PLUGIN_CONTRACT_API PL_ERRCODE Plugin_GetLastError() 346 | { 347 | if (gPluginContext == nullptr) 348 | return PL_ERRCODE_NOTINITIALIZED; 349 | 350 | return gPluginContext->GetLastError(); 351 | } 352 | 353 | PLUGIN_CONTRACT_API PL_RES Plugin_GetObject(PL_TYPE type, PIPluginObject* _out_Ptr) 354 | { 355 | if (gPluginContext == nullptr) 356 | return PL_ERR; 357 | 358 | return gPluginContext->GetObject(type, _out_Ptr); 359 | } 360 | 361 | PLUGIN_CONTRACT_API PL_RES Plugin_GetObjectFromLibrary(PL_LIBID libraryID, PL_TYPE type, PIPluginObject* _out_Ptr) 362 | { 363 | if (gPluginContext == nullptr) 364 | return PL_ERR; 365 | 366 | return gPluginContext->GetObjectFromLibrary(libraryID, type, _out_Ptr); 367 | } 368 | 369 | PLUGIN_CONTRACT_API PL_RES Plugin_GetObjects(PL_TYPE type, PIPluginObjectFunc func) 370 | { 371 | if (gPluginContext == nullptr) 372 | return PL_ERR; 373 | 374 | return gPluginContext->GetObjects(type, func); 375 | } 376 | 377 | PLUGIN_CONTRACT_API PL_RES Plugin_RegisterObject(PL_TYPE type, PIPluginObject ptr) 378 | { 379 | if (gPluginContext == nullptr) 380 | return PL_ERR; 381 | 382 | return gPluginContext->RegisterObject(type, ptr); 383 | } 384 | 385 | PLUGIN_CONTRACT_API PL_RES Plugin_RegisterGlobalObject(PL_TYPE type, PIPluginObject ptr) 386 | { 387 | if (gPluginContext == nullptr) 388 | return PL_ERR; 389 | 390 | return gPluginContext->RegisterGlobalObject(type, ptr); 391 | } 392 | 393 | PLUGIN_CONTRACT_API PL_LIBID Plugin_LoadLibrary(const char* filename) 394 | { 395 | if (gPluginContext == nullptr) 396 | return PL_ERR; 397 | 398 | return gPluginContext->LoadLibrary(filename); 399 | } 400 | 401 | PLUGIN_CONTRACT_API PL_RES Plugin_UnloadLibrary(PL_LIBID id) 402 | { 403 | if (gPluginContext == nullptr) 404 | return PL_ERR; 405 | 406 | return gPluginContext->UnloadLibrary(id); 407 | } 408 | -------------------------------------------------------------------------------- /plugin/plugin/core/plugincontext.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../contract.h" 3 | #include 4 | #include 5 | 6 | extern "C" { 7 | PLUGIN_CONTRACT_API PL_RES Plugin_Init(); 8 | PLUGIN_CONTRACT_API PL_RES Plugin_Release(); 9 | PLUGIN_CONTRACT_API PL_ERRCODE Plugin_GetLastError(); 10 | PLUGIN_CONTRACT_API PL_RES Plugin_GetObject(PL_TYPE type, PIPluginObject* _out_Ptr); 11 | PLUGIN_CONTRACT_API PL_RES Plugin_RegisterObject(PL_TYPE type, PIPluginObject ptr); 12 | PLUGIN_CONTRACT_API PL_RES Plugin_GetObjects(PL_TYPE type, PIPluginObjectFunc func); 13 | PLUGIN_CONTRACT_API PL_RES Plugin_RegisterGlobalObject(PL_TYPE type, PIPluginObject ptr); 14 | PLUGIN_CONTRACT_API PL_LIBID Plugin_LoadLibrary(const char* filename); 15 | PLUGIN_CONTRACT_API PL_RES Plugin_UnloadLibrary(PL_LIBID id); 16 | } -------------------------------------------------------------------------------- /plugin/plugin/defines.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef _PLUGIN_DEFINES_H_ 3 | #define _PLUGIN_DEFINES_H_ 4 | 5 | #ifdef PLUGIN_EXPORTS 6 | #ifndef PLUGIN_API 7 | #define PLUGIN_API __declspec(dllexport) 8 | #endif 9 | #else 10 | #ifndef PLUGIN_API 11 | #define PLUGIN_API __declspec(dllimport) 12 | #endif 13 | #endif 14 | 15 | #ifdef PLUGIN_CONTRACT_EXPORTS 16 | #ifndef PLUGIN_CONTRACT_API 17 | #define PLUGIN_CONTRACT_API __declspec(dllexport) 18 | #endif 19 | #else 20 | #ifndef PLUGIN_CONTRACT_API 21 | #define PLUGIN_CONTRACT_API __declspec(dllimport) 22 | #endif 23 | #endif 24 | 25 | // 26 | // Declare all the interfaces used by the plugin engine 27 | // 28 | 29 | struct PLUGIN_API IPluginObject1; 30 | 31 | typedef IPluginObject1 IPluginObject; 32 | typedef IPluginObject1* PIPluginObject; 33 | 34 | // A plugin object type 35 | typedef long long PL_TYPE; 36 | 37 | // A result returned by the plugin framework's interface. 38 | typedef int PL_RES; 39 | 40 | // A loaded plugin ID. Useful if we want to manually close any opened plugins 41 | typedef unsigned int PL_LIBID; 42 | 43 | // An error code delivered by the plugin framework 44 | typedef int PL_ERRCODE; 45 | 46 | // Symbolizes an unsigned long in the plugin framework 47 | typedef unsigned long PL_UINT64; 48 | 49 | #define PL_OK 1 50 | #define PL_ERR 0 51 | 52 | 53 | // 54 | // Define a plugin object type ID (ID for this specific interface). 55 | // 56 | // @param Type 57 | // The interface type 58 | // @param UID 59 | // A unique ID number. It's up to your project to select which ones you want. 60 | // Numbers below 10 are restricted. 61 | #define DEFINE_PLTYPE(Type, UID) static const PL_TYPE Type##_ID = UID##LL 62 | 63 | // 64 | // Retrieves a plugin object type ID unique to the supplied Type. You are also free to manually type in _ID if you want. 65 | // 66 | // @param Type 67 | // The type 68 | #define PL_TYPEOF(Type) Type##_ID 69 | 70 | // 71 | // Declare a new interface useful for the plugin framework. 72 | // 73 | // @param Name 74 | // The interface name 75 | // @param Inherits 76 | // The class that the new interface inherits from. If nothing then specify IPluginObject 77 | #define DECLARE_INTERFACE(Name, Inherits) struct PLUGIN_API Name : public Inherits 78 | 79 | #ifndef SAFE_RELEASE 80 | #define SAFE_RELEASE(Obj) if(Obj != nullptr) Obj->Release() 81 | #endif 82 | 83 | #ifndef FAILURE 84 | #define FAILURE(X) ((X) == PL_ERR) 85 | #endif 86 | 87 | #ifndef SUCCESS 88 | #define SUCCESS(X) ((X) == PL_OK) 89 | #endif 90 | 91 | // 92 | // Error codes 93 | // 94 | 95 | // No error has occured 96 | #define PL_ERRCODE_NOERROR 0 97 | 98 | // The library was not found 99 | #define PL_ERRCODE_LIBRARYNOTFOUND 1 100 | 101 | // The entry point is missing inside the plugin 102 | #define PL_ERRCODE_MISSINGENTRYPOINT 2 103 | 104 | // Entry point returned failure 105 | #define PL_ERRCODE_ENTRYPOINTFAILURE 3 106 | 107 | // The object you are looking for is not found 108 | #define PL_ERRCODE_OBJECTNOTFOUND 4 109 | 110 | // The supplied PL_LIBID doesn't exist 111 | #define PL_ERRCODE_NONEXISTENTLIBID 5 112 | 113 | // You are trying to perform an action without an active plugin available 114 | #define PL_ERRCODE_NOACTIVEPLUGIN 6 115 | 116 | // You are trying to register a non-global object as a plugin, which is not allowed. 117 | #define PL_ERRCODE_NOTHOSTERROR 7 118 | 119 | // The plugin framework is not initialized 120 | #define PL_ERRCODE_NOTINITIALIZED 8 121 | 122 | // This error code happens if the host application tries to unload 123 | // a library that's currently in use (has object's with reference counter > 0). 124 | #define PL_ERRCODE_LIBRARYINUSE 9 125 | 126 | // Error code occures if retrieval of get objects fails by some reason 127 | #define PL_ERRCODE_GETOBJECTSFAILED 10 128 | 129 | // A supplied argument is invalid 130 | #define PL_ERRCODE_INVALIDARGUMENT 11 131 | 132 | #endif 133 | -------------------------------------------------------------------------------- /plugin/plugin/pluginobject1.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "defines.h" 3 | 4 | // 5 | // Base class for everything exposed using the plugin framework 6 | struct PLUGIN_API IPluginObject1 7 | { 8 | public: 9 | virtual ~IPluginObject1() {} 10 | 11 | // 12 | // Increments the internal reference counter for this object. 13 | // 14 | // @return The new reference count. 15 | virtual PL_UINT64 AddRef() = 0; 16 | 17 | // 18 | // Decrements the internal reference counter for this object. The owner plugin is 19 | // free to release this objects internal memory whenever it reaches 0 - if it want's to. 20 | // 21 | // @reutrn The new reference count 22 | virtual PL_UINT64 Release() = 0; 23 | 24 | // 25 | // Convert this type into a new type - if possible. This is up the the one exposing 26 | // the original pointer to begin with 27 | // 28 | // @param type 29 | // The new type 30 | // @param _out_Ptr 31 | // A memory location where we put the new pointer 32 | // @return PL_OK if successfull; PL_ERR otherwise; 33 | virtual PL_RES ToInterface(PL_TYPE type, void** _out_Ptr) = 0; 34 | }; 35 | 36 | DEFINE_PLTYPE(IPluginObject1, 1); 37 | DEFINE_PLTYPE(IPluginObject, 1); 38 | -------------------------------------------------------------------------------- /projects/vs2013/plugin.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Express 2013 for Windows Desktop 4 | VisualStudioVersion = 12.0.30110.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "plugin", "plugin.vcxproj", "{6A708F37-BD90-482C-92CD-0CCCA385112A}" 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 | {6A708F37-BD90-482C-92CD-0CCCA385112A}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {6A708F37-BD90-482C-92CD-0CCCA385112A}.Debug|Win32.Build.0 = Debug|Win32 16 | {6A708F37-BD90-482C-92CD-0CCCA385112A}.Release|Win32.ActiveCfg = Release|Win32 17 | {6A708F37-BD90-482C-92CD-0CCCA385112A}.Release|Win32.Build.0 = Release|Win32 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /projects/vs2013/plugin.v12.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/perandersson/plugin/1602fa6cd97fcacb62d72084c03f22bd7117951a/projects/vs2013/plugin.v12.suo -------------------------------------------------------------------------------- /projects/vs2013/plugin.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | {6A708F37-BD90-482C-92CD-0CCCA385112A} 26 | Win32Proj 27 | plugincore 28 | plugin 29 | 30 | 31 | 32 | DynamicLibrary 33 | true 34 | v120 35 | MultiByte 36 | 37 | 38 | DynamicLibrary 39 | false 40 | v120 41 | true 42 | MultiByte 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | $(SolutionDir)../../bin/ 56 | $(SolutionDir)../../bin/$(Configuration)/$(ProjectName)/ 57 | $(ProjectName)1d 58 | 59 | 60 | $(SolutionDir)../../bin/ 61 | $(SolutionDir)../../bin/$(Configuration)/$(ProjectName)/ 62 | $(ProjectName)1 63 | 64 | 65 | 66 | 67 | 68 | Level3 69 | Disabled 70 | WIN32;_DEBUG;_LIB;PLUGIN_CONTRACT_EXPORTS;%(PreprocessorDefinitions) 71 | 72 | 73 | Windows 74 | true 75 | 76 | 77 | 78 | 79 | Level3 80 | 81 | 82 | MaxSpeed 83 | true 84 | true 85 | WIN32;NDEBUG;_LIB;PLUGIN_CONTRACT_EXPORTS;%(PreprocessorDefinitions) 86 | 87 | 88 | Windows 89 | true 90 | true 91 | true 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /projects/vs2013/plugin.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 10 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 11 | 12 | 13 | {e4fcfd7b-f3c0-45b1-9d21-337df1c7f2e8} 14 | 15 | 16 | 17 | 18 | Source Files 19 | 20 | 21 | Source Files 22 | 23 | 24 | Source Files 25 | 26 | 27 | Source Files\core 28 | 29 | 30 | Source Files\core 31 | 32 | 33 | 34 | 35 | Source Files\core 36 | 37 | 38 | Source Files\core 39 | 40 | 41 | -------------------------------------------------------------------------------- /projects/vs2013/plugin.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | --------------------------------------------------------------------------------