diff --git a/.gitignore b/.gitignore
index b8373ae1b..2e7fd5e8e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,3 +11,99 @@ Thumbs.db
/src/plugins/automation/generated/salamander_h.h
/src/plugins/automation/generated/salamander_i.c
/src/plugins/automation/generated/salamander_p.c
+/src/plugins/7zip/vcxproj/7ZA/salamander/Debug_x64/plugins/7zip
+/src/plugins/7zip/vcxproj/7ZA/salamander/Release_x64/plugins/7zip
+/src/plugins/7zip/vcxproj/7zwrapper/salamander/Debug_x64/plugins/7zip
+/src/plugins/7zip/vcxproj/7zwrapper/salamander/Release_x64/plugins/7zip
+/src/plugins/7zip/vcxproj/salamander/Debug_x64/plugins/7zip
+/src/plugins/7zip/vcxproj/salamander/Release_x64/plugins/7zip
+/src/plugins/automation/vcxproj/salamander/Debug_x64/plugins/automation
+/src/plugins/automation/vcxproj/salamander/Release_x64/plugins/automation
+/src/plugins/checksum/vcxproj/salamander/Debug_x64/plugins/checksum
+/src/plugins/checksum/vcxproj/salamander/Release_x64/plugins/checksum
+/src/plugins/checkver/vcxproj/salamander/Debug_x64/plugins/checkver
+/src/plugins/checkver/vcxproj/salamander/Release_x64/plugins/checkver
+/src/plugins/dbviewer/vcxproj/salamander/Debug_x64/plugins/dbviewer
+/src/plugins/dbviewer/vcxproj/salamander/Release_x64/plugins/dbviewer
+/src/plugins/demomenu/vcxproj/salamander/Debug_x64/plugins/demomenu
+/src/plugins/demomenu/vcxproj/salamander/Release_x64/plugins/demomenu
+/src/plugins/demoplug/vcxproj/salamander/Debug_x64/plugins/demoplug
+/src/plugins/demoplug/vcxproj/salamander/Release_x64/plugins/demoplug
+/src/plugins/demoview/vcxproj/salamander/Debug_x64/plugins/demoview
+/src/plugins/demoview/vcxproj/salamander/Release_x64/plugins/demoview
+/src/plugins/diskmap/vcxproj/salamander/Debug_x64/plugins/diskmap
+/src/plugins/diskmap/vcxproj/salamander/Release_x64/plugins/diskmap
+/src/plugins/filecomp/vcxproj/fcremote/salamander/Debug_x64/plugins/filecomp
+/src/plugins/filecomp/vcxproj/fcremote/salamander/Release_x64/plugins/filecomp
+/src/plugins/filecomp/vcxproj/salamander/Debug_x64/plugins/filecomp
+/src/plugins/filecomp/vcxproj/salamander/Release_x64/plugins/filecomp
+/src/plugins/folders/vcxproj/salamander/Debug_x64/plugins/folders
+/src/plugins/folders/vcxproj/salamander/Release_x64/plugins/folders
+/src/plugins/ftp/vcxproj/salamander/Debug_x64/plugins/ftp
+/src/plugins/ftp/vcxproj/salamander/Release_x64/plugins/ftp
+/src/plugins/ieviewer/vcxproj/salamander/Debug_x64/plugins/ieviewer
+/src/plugins/ieviewer/vcxproj/salamander/Release_x64/plugins/ieviewer
+/src/plugins/mmviewer/vcxproj/salamander/Debug_x64/plugins/mmviewer
+/src/plugins/mmviewer/vcxproj/salamander/Release_x64/plugins/mmviewer
+/src/plugins/nethood/vcxproj/salamander/Debug_x64/plugins/nethood
+/src/plugins/nethood/vcxproj/salamander/Release_x64/plugins/nethood
+/src/plugins/pak/vcxproj/salamander/Debug_x64/plugins/pak
+/src/plugins/pak/vcxproj/salamander/Release_x64/plugins/pak
+/src/plugins/peviewer/vcxproj/salamander/Debug_x64/plugins/peviewer
+/src/plugins/peviewer/vcxproj/salamander/Release_x64/plugins/peviewer
+/src/plugins/pictview/vcxproj/exif/salamander/Debug_x64/plugins/pictview
+/src/plugins/pictview/vcxproj/exif/salamander/Release_x64/plugins/pictview
+/src/plugins/pictview/vcxproj/salamander/Debug_x64/plugins/pictview
+/src/plugins/pictview/vcxproj/salamander/Release_x64/plugins/pictview
+/src/plugins/portables/vcxproj/salamander/Debug_x64/plugins/portables
+/src/plugins/portables/vcxproj/salamander/Release_x64/plugins/portables
+/src/plugins/regedt/vcxproj/salamander/Debug_x64/plugins/regedt
+/src/plugins/regedt/vcxproj/salamander/Release_x64/plugins/regedt
+/src/plugins/renamer/vcxproj/salamander/Debug_x64/plugins/renamer
+/src/plugins/renamer/vcxproj/salamander/Release_x64/plugins/renamer
+/src/plugins/splitcbn/vcxproj/salamander/Debug_x64/plugins/splitcbn
+/src/plugins/splitcbn/vcxproj/salamander/Release_x64/plugins/splitcbn
+/src/plugins/tar/vcxproj/salamander/Debug_x64/plugins/tar
+/src/plugins/tar/vcxproj/salamander/Release_x64/plugins/tar
+/src/plugins/unarj/vcxproj/salamander/Debug_x64/plugins/unarj
+/src/plugins/unarj/vcxproj/salamander/Release_x64/plugins/unarj
+/src/plugins/uncab/vcxproj/salamander/Debug_x64/plugins/uncab
+/src/plugins/uncab/vcxproj/salamander/Release_x64/plugins/uncab
+/src/plugins/unchm/vcxproj/chmlib/salamander/Debug_x64/plugins/unchm
+/src/plugins/unchm/vcxproj/chmlib/salamander/Release_x64/plugins/unchm
+/src/plugins/unchm/vcxproj/salamander/Debug_x64/plugins/unchm
+/src/plugins/unchm/vcxproj/salamander/Release_x64/plugins/unchm
+/src/plugins/undelete/vcxproj/salamander/Debug_x64/plugins/undelete
+/src/plugins/undelete/vcxproj/salamander/Release_x64/plugins/undelete
+/src/plugins/unfat/vcxproj/salamander/Debug_x64/plugins/unfat
+/src/plugins/unfat/vcxproj/salamander/Release_x64/plugins/unfat
+/src/plugins/uniso/vcxproj/salamander/Debug_x64/plugins/uniso
+/src/plugins/uniso/vcxproj/salamander/Release_x64/plugins/uniso
+/src/plugins/unlha/vcxproj/salamander/Debug_x64/plugins/unlha
+/src/plugins/unlha/vcxproj/salamander/Release_x64/plugins/unlha
+/src/plugins/unmime/vcxproj/salamander/Debug_x64/plugins/unmime
+/src/plugins/unmime/vcxproj/salamander/Release_x64/plugins/unmime
+/src/plugins/unole/vcxproj/salamander/Debug_x64/plugins/unole
+/src/plugins/unole/vcxproj/salamander/Release_x64/plugins/unole
+/src/plugins/unrar/vcxproj/salamander/Debug_x64/plugins/unrar
+/src/plugins/unrar/vcxproj/salamander/Release_x64/plugins/unrar
+/src/plugins/wmobile/vcxproj/salamander/Debug_x64/plugins/wmobile
+/src/plugins/wmobile/vcxproj/salamander/Release_x64/plugins/wmobile
+/src/plugins/zip/vcxproj/salamander/Debug_x64/plugins/zip
+/src/plugins/zip/vcxproj/salamander/Release_x64/plugins/zip
+/src/plugins/zip/vcxproj/zip2sfx/salamander/Debug_x86/plugins/zip/zip2sfx/Intermediate/microsoft/STL
+/src/plugins/zip/vcxproj/zip2sfx/salamander/Release_x86/plugins/zip/zip2sfx/Intermediate/microsoft/STL
+/src/vcxproj/salamander/Debug_x64
+/src/vcxproj/salamander/Release_x64
+/src/vcxproj/salmon/salamander/Debug_x64
+/src/vcxproj/salmon/salamander/Release_x64
+/src/vcxproj/salopen/salamander/Debug_x64/plugins/Intermediate/salopen/Intermediate/microsoft/STL
+/src/vcxproj/salopen/salamander/Release_x64/plugins/Intermediate/salopen/Intermediate/microsoft/STL
+/src/vcxproj/salspawn/salamander/Debug_x64/plugins/Intermediate/salspawn/Intermediate/microsoft/STL
+/src/vcxproj/salspawn/salamander/Release_x64/plugins/Intermediate/salspawn/Intermediate/microsoft/STL
+/src/vcxproj/shellext/salamander/Debug_x64/plugins/Intermediate/salextx64/Intermediate/microsoft/STL
+/src/vcxproj/shellext/salamander/Debug_x86/plugins/Intermediate/salextx86/Intermediate/microsoft/STL
+/src/vcxproj/shellext/salamander/Release_x64/plugins/Intermediate/salextx64/Intermediate/microsoft/STL
+/src/vcxproj/shellext/salamander/Release_x86/plugins/Intermediate/salextx86/Intermediate/microsoft/STL
+/src/vcxproj/sqlite/salamander/Debug_x64
+/src/vcxproj/sqlite/salamander/Release_x64
diff --git a/src/plugins/csdemo/csdemo.cpp b/src/plugins/csdemo/csdemo.cpp
new file mode 100644
index 000000000..fd3f8faa3
--- /dev/null
+++ b/src/plugins/csdemo/csdemo.cpp
@@ -0,0 +1,198 @@
+// SPDX-FileCopyrightText: 2023 Open Salamander Authors
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+//****************************************************************************
+//
+// Copyright (c) 2023 Open Salamander Authors
+//
+// This is a part of the Open Salamander SDK library.
+//
+//****************************************************************************
+
+#include "precomp.h"
+
+// plugin interface object; Salamander calls its methods
+CPluginInterface PluginInterface;
+// additional parts of the CPluginInterface interface
+CPluginInterfaceForMenuExt InterfaceForMenuExt;
+
+// global data
+const char* PluginNameEN = "C# Demo"; // untranslated plugin name, used before the language module loads and for debugging
+const char* PluginNameShort = "CSDEMO"; // plugin name (short, without spaces)
+
+HINSTANCE DLLInstance = NULL; // handle of the SPL - language-neutral resources
+HINSTANCE HLanguage = NULL; // handle of the SLG - language-specific resources
+
+// generic Salamander interface - valid from startup until the plugin shuts down
+CSalamanderGeneralAbstract* SalamanderGeneral = NULL;
+
+// variable definition for "dbg.h"
+CSalamanderDebugAbstract* SalamanderDebug = NULL;
+
+// variable definition for "spl_com.h"
+int SalamanderVersion = 0;
+
+// interface providing custom Windows controls used in Salamander
+//CSalamanderGUIAbstract *SalamanderGUI = NULL;
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ if (fdwReason == DLL_PROCESS_ATTACH)
+ {
+ DLLInstance = hinstDLL;
+
+ INITCOMMONCONTROLSEX initCtrls;
+ initCtrls.dwSize = sizeof(INITCOMMONCONTROLSEX);
+ initCtrls.dwICC = ICC_BAR_CLASSES;
+ if (!InitCommonControlsEx(&initCtrls))
+ {
+ MessageBox(NULL, "InitCommonControlsEx failed!", "Error", MB_OK | MB_ICONERROR);
+ return FALSE; // DLL won't start
+ }
+ }
+
+ return TRUE; // DLL can be loaded
+}
+
+// ****************************************************************************
+
+char* LoadStr(int resID)
+{
+ return SalamanderGeneral->LoadStr(HLanguage, resID);
+}
+
+void OnAbout(HWND hParent)
+{
+ if (!ManagedBridge_ShowAbout(hParent))
+ {
+ SalamanderGeneral->SalMessageBox(hParent,
+ "Unable to open the managed About dialog.\n"
+ "Verify that CSDemo.Managed.dll is located next to the plugin.",
+ LoadStr(IDS_PLUGINNAME), MB_OK | MB_ICONERROR);
+ }
+}
+
+//
+// ****************************************************************************
+// SalamanderPluginGetReqVer
+//
+
+#ifdef __BORLANDC__
+extern "C"
+{
+ int WINAPI SalamanderPluginGetReqVer();
+ CPluginInterfaceAbstract* WINAPI SalamanderPluginEntry(CSalamanderPluginEntryAbstract* salamander);
+};
+#endif // __BORLANDC__
+
+int WINAPI SalamanderPluginGetReqVer()
+{
+ return LAST_VERSION_OF_SALAMANDER;
+}
+
+//
+// ****************************************************************************
+// SalamanderPluginEntry
+//
+
+CPluginInterfaceAbstract* WINAPI SalamanderPluginEntry(CSalamanderPluginEntryAbstract* salamander)
+{
+ // configure SalamanderDebug for "dbg.h"
+ SalamanderDebug = salamander->GetSalamanderDebug();
+ // configure SalamanderVersion for "spl_com.h"
+ SalamanderVersion = salamander->GetVersion();
+ HANDLES_CAN_USE_TRACE();
+ CALL_STACK_MESSAGE1("SalamanderPluginEntry()");
+
+ // the plugin targets the current version of Salamander and newer - verify the requirement
+ if (SalamanderVersion < LAST_VERSION_OF_SALAMANDER)
+ { // reject older versions
+ MessageBox(salamander->GetParentWindow(),
+ REQUIRE_LAST_VERSION_OF_SALAMANDER,
+ PluginNameEN, MB_OK | MB_ICONERROR);
+ return NULL;
+ }
+
+ // load the language module (.slg)
+ HLanguage = salamander->LoadLanguageModule(salamander->GetParentWindow(), PluginNameEN);
+ if (HLanguage == NULL)
+ return NULL;
+
+ // obtain the general Salamander interface
+ SalamanderGeneral = salamander->GetSalamanderGeneral();
+ // obtain the interface providing custom Windows controls used in Salamander
+ // SalamanderGUI = salamander->GetSalamanderGUI();
+
+ // set the help file name
+ SalamanderGeneral->SetHelpFileName("csdemo.chm");
+
+ // set the basic plugin metadata
+ salamander->SetBasicPluginData(LoadStr(IDS_PLUGINNAME), FUNCTION_DYNAMICMENUEXT | FUNCTION_CONFIGURATION,
+ VERSINFO_VERSION_NO_PLATFORM, VERSINFO_COPYRIGHT,
+ LoadStr(IDS_PLUGIN_DESCRIPTION), PluginNameShort,
+ NULL, NULL);
+
+ // set the plugin home page URL
+ salamander->SetPluginHomePageURL(LoadStr(IDS_PLUGIN_HOME));
+
+ return &PluginInterface;
+}
+
+//
+// ****************************************************************************
+// CPluginInterface
+//
+
+void WINAPI
+CPluginInterface::About(HWND parent)
+{
+ OnAbout(parent);
+}
+
+BOOL WINAPI
+CPluginInterface::Release(HWND parent, BOOL force)
+{
+ ManagedBridge_Shutdown();
+ return TRUE;
+}
+
+void WINAPI
+CPluginInterface::Configuration(HWND parent)
+{
+ if (!ManagedBridge_ShowConfiguration(parent))
+ {
+ SalamanderGeneral->SalMessageBox(parent,
+ "Unable to open the managed configuration window.",
+ LoadStr(IDS_PLUGINNAME), MB_OK | MB_ICONERROR);
+ }
+}
+
+void WINAPI
+CPluginInterface::Connect(HWND parent, CSalamanderConnectAbstract* salamander)
+{
+ CALL_STACK_MESSAGE1("CPluginInterface::Connect(,)");
+
+ // basic part:
+ salamander->AddMenuItem(-1, LoadStr(IDS_MENU_HELLO), SALHOTKEY('M', HOTKEYF_CONTROL | HOTKEYF_SHIFT),
+ MENUCMD_SHOWHELLO, FALSE, MENU_EVENT_TRUE, MENU_EVENT_TRUE, MENU_SKILLLEVEL_ALL);
+
+ ManagedBridge_EnsureInitialized(parent);
+
+ /*
+ CGUIIconListAbstract *iconList = SalamanderGUI->CreateIconList();
+ iconList->Create(16, 16, 1);
+ HICON hIcon = (HICON)LoadImage(DLLInstance, MAKEINTRESOURCE(IDI_PLUGINICON), IMAGE_ICON, 16, 16, SalamanderGeneral->GetIconLRFlags());
+ iconList->ReplaceIcon(0, hIcon);
+ DestroyIcon(hIcon);
+ salamander->SetIconListForGUI(iconList); // Salamander takes care of destroying the icon list
+
+ salamander->SetPluginIcon(0);
+ salamander->SetPluginMenuAndToolbarIcon(0);
+*/
+}
+
+CPluginInterfaceForMenuExtAbstract* WINAPI
+CPluginInterface::GetInterfaceForMenuExt()
+{
+ return &InterfaceForMenuExt;
+}
diff --git a/src/plugins/csdemo/csdemo.def b/src/plugins/csdemo/csdemo.def
new file mode 100644
index 000000000..ba26d3ac9
--- /dev/null
+++ b/src/plugins/csdemo/csdemo.def
@@ -0,0 +1,4 @@
+LIBRARY CSDEMO.SPL
+
+EXPORTS SalamanderPluginEntry
+EXPORTS SalamanderPluginGetReqVer
diff --git a/src/plugins/csdemo/csdemo.h b/src/plugins/csdemo/csdemo.h
new file mode 100644
index 000000000..5a3da48ca
--- /dev/null
+++ b/src/plugins/csdemo/csdemo.h
@@ -0,0 +1,73 @@
+// SPDX-FileCopyrightText: 2023 Open Salamander Authors
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+//****************************************************************************
+//
+// Copyright (c) 2023 Open Salamander Authors
+//
+// This is a part of the Open Salamander SDK library.
+//
+//****************************************************************************
+
+#pragma once
+
+// global data
+extern HINSTANCE DLLInstance; // handle of the SPL - language-neutral resources
+extern HINSTANCE HLanguage; // handle of the SLG - language-specific resources
+
+// generic Salamander interface - valid from startup until the plugin shuts down
+extern CSalamanderGeneralAbstract* SalamanderGeneral;
+
+char* LoadStr(int resID);
+
+// plugin menu commands
+#define MENUCMD_SHOWHELLO 1
+
+//
+// ****************************************************************************
+// CPluginInterface
+//
+
+class CPluginInterfaceForMenuExt : public CPluginInterfaceForMenuExtAbstract
+{
+public:
+ virtual DWORD WINAPI GetMenuItemState(int id, DWORD eventMask) { return 0; }
+ virtual BOOL WINAPI ExecuteMenuItem(CSalamanderForOperationsAbstract* salamander, HWND parent,
+ int id, DWORD eventMask);
+ virtual BOOL WINAPI HelpForMenuItem(HWND parent, int id);
+ virtual void WINAPI BuildMenu(HWND parent, CSalamanderBuildMenuAbstract* salamander) {}
+};
+
+class CPluginInterface : public CPluginInterfaceAbstract
+{
+public:
+ virtual void WINAPI About(HWND parent);
+
+ virtual BOOL WINAPI Release(HWND parent, BOOL force);
+
+ virtual void WINAPI LoadConfiguration(HWND parent, HKEY regKey, CSalamanderRegistryAbstract* registry) {}
+ virtual void WINAPI SaveConfiguration(HWND parent, HKEY regKey, CSalamanderRegistryAbstract* registry) {}
+ virtual void WINAPI Configuration(HWND parent);
+
+ virtual void WINAPI Connect(HWND parent, CSalamanderConnectAbstract* salamander);
+
+ virtual void WINAPI ReleasePluginDataInterface(CPluginDataInterfaceAbstract* pluginData) {}
+
+ virtual CPluginInterfaceForArchiverAbstract* WINAPI GetInterfaceForArchiver() { return NULL; }
+ virtual CPluginInterfaceForViewerAbstract* WINAPI GetInterfaceForViewer() { return NULL; }
+ virtual CPluginInterfaceForMenuExtAbstract* WINAPI GetInterfaceForMenuExt();
+ virtual CPluginInterfaceForFSAbstract* WINAPI GetInterfaceForFS() { return NULL; }
+ virtual CPluginInterfaceForThumbLoaderAbstract* WINAPI GetInterfaceForThumbLoader() { return NULL; }
+
+ virtual void WINAPI Event(int event, DWORD param) {}
+ virtual void WINAPI ClearHistory(HWND parent) {}
+ virtual void WINAPI AcceptChangeOnPathNotification(const char* path, BOOL includingSubdirs) {}
+
+ virtual void WINAPI PasswordManagerEvent(HWND parent, int event) {}
+};
+
+// plugin interface provided to Salamander
+extern CPluginInterface PluginInterface;
+
+// open the About dialog
+void OnAbout(HWND hParent);
diff --git a/src/plugins/csdemo/csdemo.rc b/src/plugins/csdemo/csdemo.rc
new file mode 100644
index 000000000..d590aa35e
--- /dev/null
+++ b/src/plugins/csdemo/csdemo.rc
@@ -0,0 +1,71 @@
+// Microsoft Visual C++ generated resource script.
+//
+#pragma code_page(65001)
+
+#include "csdemo.rh"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winresrc.h"
+
+#include "csdemo.rh2"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Neutral resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)
+LANGUAGE LANG_NEUTRAL,SUBLANG_NEUTRAL
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "csdemo.rh\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""winresrc.h""\r\n"
+ "\r\n"
+ "#include ""csdemo.rh2""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)\r\n"
+ "LANGUAGE LANG_NEUTRAL,SUBLANG_NEUTRAL\r\n"
+ "#include ""csdemo.rc2"" // non-Microsoft Visual C++ edited resources\r\n"
+ "#endif\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // Neutral resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)
+LANGUAGE LANG_NEUTRAL,SUBLANG_NEUTRAL
+#include "csdemo.rc2" // non-Microsoft Visual C++ edited resources
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
diff --git a/src/plugins/csdemo/csdemo.rc2 b/src/plugins/csdemo/csdemo.rc2
new file mode 100644
index 000000000..fc28bb78b
--- /dev/null
+++ b/src/plugins/csdemo/csdemo.rc2
@@ -0,0 +1,21 @@
+//****************************************************************************
+//
+// Copyright (c) 2023 Open Salamander Authors
+//
+// This is a part of the Open Salamander SDK library.
+//
+//****************************************************************************
+
+//
+// csdemo.rc2 - resources Microsoft Visual C++ does not edit directly
+//
+
+#ifdef APSTUDIO_INVOKED
+#error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+/////////////////////////////////////////////////////////////////////////////
+// Add manually edited resources here...
+
+#include "versinfo.rh2"
+#include "versinfo.rc2"
diff --git a/src/plugins/csdemo/csdemo.rh b/src/plugins/csdemo/csdemo.rh
new file mode 100644
index 000000000..d284dbc4b
--- /dev/null
+++ b/src/plugins/csdemo/csdemo.rh
@@ -0,0 +1,15 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by csdemo.rc
+//
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 8000
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 8200
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/src/plugins/csdemo/csdemo.rh2 b/src/plugins/csdemo/csdemo.rh2
new file mode 100644
index 000000000..b64ec7c92
--- /dev/null
+++ b/src/plugins/csdemo/csdemo.rh2
@@ -0,0 +1,25 @@
+//****************************************************************************
+//
+// Copyright (c) 2023 Open Salamander Authors
+//
+// This is a part of the Open Salamander SDK library.
+//
+//****************************************************************************
+
+// WARNING: cannot be replaced by "#pragma once" because it is included from .rc file and it seems resource compiler does not support "#pragma once"
+#ifndef __CSDEMO_RH2
+#define __CSDEMO_RH2
+
+#if defined(APSTUDIO_INVOKED) && !defined(APSTUDIO_READONLY_SYMBOLS)
+#error this file is not editable by Microsoft Visual C++
+#endif //defined(APSTUDIO_INVOKED) && !defined(APSTUDIO_READONLY_SYMBOLS)
+
+#define IDS_PLUGINNAME 46
+#define IDS_ABOUT 47
+#define IDS_PLUGIN_DESCRIPTION 48
+#define IDS_PLUGIN_HOME 49
+#define IDS_MENU_HELLO 50
+
+#define IDH_MENU_HELLO 900
+
+#endif // __CSDEMO_RH2
diff --git a/src/plugins/csdemo/help/compile.bat b/src/plugins/csdemo/help/compile.bat
new file mode 100644
index 000000000..fac30d4f9
--- /dev/null
+++ b/src/plugins/csdemo/help/compile.bat
@@ -0,0 +1,19 @@
+@echo off
+
+setlocal
+
+set HHCEXE=C:\Program Files (x86)\HTML Help Workshop\hhc.exe
+
+if not exist "%HHCEXE%" (
+ echo Unable to find HTML Help Workshop.
+ echo.
+ pause
+ endlocal
+ exit /b
+)
+
+call "%HHCEXE%" csdemo.hhp
+
+if not "%1"=="" (call "%1" csdemo.chm) else pause
+endlocal
+exit /b
diff --git a/src/plugins/csdemo/help/csdemo.hhc b/src/plugins/csdemo/help/csdemo.hhc
new file mode 100644
index 000000000..1b1d754d5
--- /dev/null
+++ b/src/plugins/csdemo/help/csdemo.hhc
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/plugins/csdemo/help/csdemo.hhk b/src/plugins/csdemo/help/csdemo.hhk
new file mode 100644
index 000000000..bba031d40
--- /dev/null
+++ b/src/plugins/csdemo/help/csdemo.hhk
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/plugins/csdemo/help/csdemo.hhp b/src/plugins/csdemo/help/csdemo.hhp
new file mode 100644
index 000000000..ec3094830
--- /dev/null
+++ b/src/plugins/csdemo/help/csdemo.hhp
@@ -0,0 +1,66 @@
+[OPTIONS]
+Auto Index=Yes
+Compatibility=1.1 or later
+Compiled file=csdemo.chm
+Contents file=csdemo.hhc
+Default Window=$global_ssdefault
+Default topic=hh\csdemo\introduction_intro.htm
+Display compile progress=No
+Full text search stop list file=..\..\shared\help\en\stop.stp
+Full-text search=Yes
+Index file=csdemo.hhk
+Language=0x409 English (United States)
+Title=C# Demo Plugin Help
+
+[WINDOWS]
+$global_ssdefault=,"salamand.chm::\salamand.hhc","csdemo.hhk","hh\csdemo\introduction_intro.htm","hh\csdemo\introduction_intro.htm",,,,"Web Help",0x3520,,0x180e,,,,,,,,0
+
+[FILES]
+hh\salamander_help.css
+hh\salamander_help_shared.css
+
+[ALIAS]
+IDH_MENU_HELLO=hh\csdemo\basic_hello.htm
+
+[MAP]
+#include "..\csdemo.rh"
+#include "..\csdemo.rh2"
+#include "..\lang\lang.rh"
+
+[MERGE FILES]
+salamand.chm
+zip.chm
+filecomp.chm
+7zip.chm
+dbviewer.chm
+demoplug.chm
+ftp.chm
+checksum.chm
+checkver.chm
+ieviewer.chm
+mmviewer.chm
+pak.chm
+peviewer.chm
+pictview.chm
+regedt.chm
+renamer.chm
+splitcbn.chm
+tar.chm
+unarj.chm
+uncab.chm
+undelete.chm
+unfat.chm
+uniso.chm
+unlha.chm
+unmime.chm
+unrar.chm
+wmobile.chm
+winscp.chm
+nethood.chm
+unchm.chm
+automation.chm
+diskmap.chm
+demoview.chm
+
+[INFOTYPES]
+
diff --git a/src/plugins/csdemo/help/hh/csdemo/basic_hello.htm b/src/plugins/csdemo/help/hh/csdemo/basic_hello.htm
new file mode 100644
index 000000000..71e3a0a2f
--- /dev/null
+++ b/src/plugins/csdemo/help/hh/csdemo/basic_hello.htm
@@ -0,0 +1,35 @@
+
+
+
+Managed Hello Command
+
+
+
+
+
+
+
+
+
+
+
Managed Hello Command
+
+
The Show C# Demo Window command demonstrates how a managed WinForms window
+can be opened from a native plugin. The dialog is implemented in the
+CSDemo.Managed.dll assembly and is hosted by the C++ bridge.
+
+
To open the managed window:
+
+
+ Menu: Plugins/C# Demo/Show C# Demo Window
+ Shortcut key: Ctrl+Shift+M
+
+
+
If the window fails to appear, verify that the managed assembly is next to
+csdemo.spl and that the .NET Framework 4.x runtime is available.
+
+
+
+
+
+
diff --git a/src/plugins/csdemo/help/hh/csdemo/introduction_intro.htm b/src/plugins/csdemo/help/hh/csdemo/introduction_intro.htm
new file mode 100644
index 000000000..24732a4c2
--- /dev/null
+++ b/src/plugins/csdemo/help/hh/csdemo/introduction_intro.htm
@@ -0,0 +1,31 @@
+
+
+
+Introduction
+
+
+
+
+
+
+
+
+
+
Getting Started with the C# Demo Plugin
+
+
The C# Demo plugin shows how native Open Salamander extensions can host managed code.
+It loads a .NET WinForms assembly that provides the About dialog,
+configuration window, and menu command logic.
+
+
The sample is intentionally simple – the native C++ layer is just a small bridge
+that starts the Common Language Runtime (CLR) and forwards commands to the managed
+assembly. You can use it as a template when creating your own plugins in C#.
+
+
See Using Plugins
+for a description of basic work with plugins.
+
+
+
+
+
+
diff --git a/src/plugins/csdemo/help/hh/salamander_help.css b/src/plugins/csdemo/help/hh/salamander_help.css
new file mode 100644
index 000000000..828c7b15d
--- /dev/null
+++ b/src/plugins/csdemo/help/hh/salamander_help.css
@@ -0,0 +1,14 @@
+/* Cascading Style Sheet for Open Salamander Help */
+/* Basic part used for CHM only, not for WEB */
+
+body
+{
+ margin: 0px;
+ padding: 0px;
+ background: #ffffff;
+ color: #000000;
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ font-size: 70%;
+ width: 100%;
+}
+
diff --git a/src/plugins/csdemo/help/hh/salamander_help_shared.css b/src/plugins/csdemo/help/hh/salamander_help_shared.css
new file mode 100644
index 000000000..e65570012
--- /dev/null
+++ b/src/plugins/csdemo/help/hh/salamander_help_shared.css
@@ -0,0 +1,325 @@
+/* Cascading Style Sheet for Open Salamander Help */
+/* Shared part used for both CHM and WEB */
+
+#help_page
+{
+ margin: 2px;
+ padding: 0px;
+ background: #fff;
+}
+
+#help_page .header
+{
+ margin-left: 0px;
+ padding: 0.3em 1.5em 0.3em 1em;
+ background: #99ccff;
+ border: 0px;
+
+ font-family: Verdana, sans-serif;
+ font-size: 110%;
+}
+
+#help_page .page
+{
+ padding: 0px 0.7em 0px 0.7em;
+ border: 0px;
+ background: #fff;
+}
+
+#help_page .footer
+{
+ margin: 0px;
+ padding: 0px;
+ margin-top: 3em;
+ background: #fff;
+ border: 0px;
+ width: 100%;
+ font-size: 90%;
+ text-align:center;
+ color: #228B22;
+}
+
+#help_page h1, h2, h3, h4
+{
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ margin: 0px;
+}
+
+#help_page h1
+{
+ font-size: 140%;
+ margin-top: 1em;
+ margin-bottom: .6em;
+}
+
+#help_page h2
+{
+ font-size: 115%;
+ margin-top: 1em;
+ margin-bottom: .6em;
+}
+
+#help_page h3
+{
+ font-size: 100%;
+ margin-left: 2.5em;
+ margin-bottom: 0.2em;
+ margin-top: 1.5em;
+}
+
+#help_page h4
+{
+ font-size: 100%;
+ margin-top: 1em;
+ margin-bottom: .6em;
+}
+
+#help_page h4.glossary
+{
+ margin-left: 1.2em;
+ margin-top: 1em;
+ margin-bottom: -0.5em;
+}
+
+#help_page h5
+{
+ font-size: 100%;
+ margin-left: 2.5em;
+ margin-bottom: 1em;
+ margin-top: 1.5em;
+}
+
+#help_page p
+{
+ margin-left: 2.5em;
+ margin-top: .6em;
+ margin-bottom: .6em;
+}
+
+#help_page p.indent
+{
+ margin-left: 3.8em;
+}
+
+#help_page ul, ol
+{
+ margin: 0px;
+ padding: 0px;
+ margin-top: .6em;
+ margin-bottom: 0em;
+}
+
+#help_page ul
+{
+ padding-left: 4.5em;
+ list-style-type: disc;
+}
+
+#help_page ul ul
+{
+ padding-left: 2em;
+}
+
+#help_page ol ol
+{
+ padding-left: 4em;
+}
+
+#help_page ul ol,
+#help_page ol ol
+{
+ list-style-type: lower-alpha;
+}
+
+#help_page ol
+{
+ padding-left: 6em;
+}
+
+#help_page li
+{
+ margin-bottom: .6em;
+}
+
+#help_page dl
+{
+ margin-top: 0em;
+ padding-left: 2.5em;
+}
+
+#help_page dd
+{
+ margin-left: 1.5em;
+}
+
+#help_page dt
+{
+ margin-top: .6em;
+}
+
+#help_page dl ul
+{
+ padding-left: 1.5em;
+}
+
+#help_page ul dl
+{
+ padding-left: 0em;
+}
+
+#help_page table
+{
+ width: 95%;
+ background: #999999;
+ margin-top: 0em;
+ margin-bottom: 0.5em;
+ margin-left: 2.5em;
+ background: #ffffff;
+}
+
+#help_page ol li table
+{
+ margin-top: 0.5em;
+}
+
+#help_page th
+{
+ padding: 2px 4px;
+ background: #dddddd;
+ text-align: left;
+ vertical-align: top;
+ margin: .25em;
+}
+
+#help_page td
+{
+ margin: .25em;
+ padding: 2px 4px;
+ background: #eeeeee;
+ vertical-align: top;
+}
+
+#help_page td.nowrap
+{
+ white-space: nowrap;
+}
+
+#help_page td.hdr
+{
+ /* darker gray on the left side */
+ margin: .25em;
+ background: #dddddd;
+ vertical-align: top;
+ padding: 2px 4px;
+ font-weight: bold;
+ width: 10%; /* reduce the left side of the table to a minimum */
+ padding-right: 10px; /* to make it look good, let's leave at least 10 pixels there */
+ white-space: nowrap;
+}
+
+#help_page tr
+{
+ margin: .25em;
+ vertical-align: top;
+}
+
+
+#help_page ul p,
+#help_page ol p,
+#help_page dl p
+{
+ margin-left: 0em;
+}
+
+#help_page ul table,
+#help_page ol table,
+#help_page dl table
+{
+ margin-left: 0em;
+}
+
+#help_page .nobr
+{
+ white-space: nowrap;
+}
+
+#help_page pre
+{
+ margin-top: .6em;
+ margin-bottom: .6em;
+ margin-left: 2.5em;
+}
+
+#help_page pre,
+#help_page code
+{
+ font: 100% Courier New, Courier, mono;
+ color: #660000;
+}
+
+#help_page .quote
+{
+ border: 1px solid #999999;
+ background: #eeeeee;
+ padding: 1em;
+ margin-left: 2.5em;
+}
+#help_page .quote p
+{
+ margin: 0em;
+}
+
+#help_page a:link
+{
+ color: #0066ff;
+}
+
+#help_page a:visited
+{
+ color: #996600;
+}
+
+#help_page a:hover
+{
+ color: #cc9900;
+}
+
+
+/* -------------- tables -------------- */
+
+#help_page .headerbarshade
+{
+ position: relative;
+ margin: 0;
+ left: 10px;
+ top: 2;
+ width: 100%;
+ height: 21px;
+}
+
+#help_page .headerbartable
+{
+ position: absolute;
+ margin: 0;
+ left: 0;
+ top: 2;
+ width: 100%;
+ height: 21px;
+}
+
+#help_page table.headerbartable td, table.headerbarshade td
+{
+ background: #99ccff;
+ border-left: 2px solid #ffffff;
+ margin: 0;
+ padding: 3px 0px 4px 0px;
+ font-family: Verdana, sans-serif;
+ font-size: 9pt;
+}
+
+#help_page table.headerbartable td.header
+{
+ padding-left: 4px;
+ text-align: left;
+}
+
diff --git a/src/plugins/csdemo/lang/lang.rc b/src/plugins/csdemo/lang/lang.rc
new file mode 100644
index 000000000..642eb2fe7
--- /dev/null
+++ b/src/plugins/csdemo/lang/lang.rc
@@ -0,0 +1,71 @@
+// Microsoft Visual C++ generated resource script.
+//
+#pragma code_page(65001)
+
+#include "lang.rh"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winresrc.h"
+
+#include "..\csdemo.rh2"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Neutral resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)
+LANGUAGE LANG_NEUTRAL,SUBLANG_NEUTRAL
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "lang.rh\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""winresrc.h""\r\n"
+ "\r\n"
+ "#include ""..\\csdemo.rh2""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)\r\n"
+ "LANGUAGE LANG_NEUTRAL,SUBLANG_NEUTRAL\r\n"
+ "#include ""lang.rc2"" // non-Microsoft Visual C++ edited resources\r\n"
+ "#endif\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // Neutral resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)
+LANGUAGE LANG_NEUTRAL,SUBLANG_NEUTRAL
+#include "lang.rc2" // non-Microsoft Visual C++ edited resources
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
diff --git a/src/plugins/csdemo/lang/lang.rc2 b/src/plugins/csdemo/lang/lang.rc2
new file mode 100644
index 000000000..f1d1aa887
--- /dev/null
+++ b/src/plugins/csdemo/lang/lang.rc2
@@ -0,0 +1,30 @@
+//****************************************************************************
+//
+// Copyright (c) 2023 Open Salamander Authors
+//
+// This is a part of the Open Salamander SDK library.
+//
+//****************************************************************************
+
+//
+// lang.rc2 - resources Microsoft Visual C++ does not edit directly
+//
+
+#ifdef APSTUDIO_INVOKED
+#error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+/////////////////////////////////////////////////////////////////////////////
+// Add manually edited resources here...
+
+#include "..\versinfo.rh2"
+#include "versinfo.rc2"
+
+STRINGTABLE
+{
+ IDS_PLUGINNAME, "C# Demo"
+ IDS_ABOUT, "About Plugin"
+ IDS_PLUGIN_DESCRIPTION, "Example plugin that hosts managed WinForms UI through the CLR."
+ IDS_PLUGIN_HOME, "https://github.com/open-salamander"
+ IDS_MENU_HELLO, "Show &C# Demo Window"
+}
diff --git a/src/plugins/csdemo/lang/lang.rh b/src/plugins/csdemo/lang/lang.rh
new file mode 100644
index 000000000..c74deabe9
--- /dev/null
+++ b/src/plugins/csdemo/lang/lang.rh
@@ -0,0 +1,15 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by lang.rc
+//
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 8500
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 8700
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/src/plugins/csdemo/managed/CSDemo.Managed.csproj b/src/plugins/csdemo/managed/CSDemo.Managed.csproj
new file mode 100644
index 000000000..d7d2b1933
--- /dev/null
+++ b/src/plugins/csdemo/managed/CSDemo.Managed.csproj
@@ -0,0 +1,22 @@
+
+
+ net48
+ true
+ CSDemo.Managed
+ OpenSalamander.CSDemo
+ enable
+ 10.0
+ false
+ false
+
+
+
+
+
+
+
diff --git a/src/plugins/csdemo/managed/EntryPoint.cs b/src/plugins/csdemo/managed/EntryPoint.cs
new file mode 100644
index 000000000..023db3172
--- /dev/null
+++ b/src/plugins/csdemo/managed/EntryPoint.cs
@@ -0,0 +1,247 @@
+// SPDX-FileCopyrightText: 2024 Open Salamander Authors
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+using System;
+using System.Globalization;
+using System.Windows.Forms;
+
+namespace OpenSalamander.CSDemo;
+
+public static class EntryPoint
+{
+ private static bool _visualsEnabled;
+
+ [STAThread]
+ public static int Dispatch(string? argument)
+ {
+ try
+ {
+ EnsureApplicationInitialized();
+
+ var parts = (argument ?? string.Empty).Split(new[] { ';' }, 3);
+ var command = parts.Length > 0 ? parts[0] : string.Empty;
+ var parentHandle = ParseHandle(parts.Length > 1 ? parts[1] : string.Empty);
+ var payload = parts.Length > 2 ? parts[2] : string.Empty;
+
+ return command switch
+ {
+ "About" => ShowAbout(parentHandle),
+ "Configure" => ShowConfiguration(parentHandle),
+ "Menu" => ShowHello(parentHandle, payload),
+ _ => 1,
+ };
+ }
+ catch (Exception ex)
+ {
+ ShowError("Unexpected managed exception:", ex);
+ return -1;
+ }
+ }
+
+ private static void EnsureApplicationInitialized()
+ {
+ if (_visualsEnabled)
+ {
+ return;
+ }
+
+ Application.EnableVisualStyles();
+ Application.SetCompatibleTextRenderingDefault(false);
+ _visualsEnabled = true;
+ }
+
+ private static int ShowAbout(IntPtr parent)
+ {
+ using var dialog = new Form
+ {
+ Text = "C# Demo Plugin",
+ StartPosition = FormStartPosition.CenterParent,
+ FormBorderStyle = FormBorderStyle.FixedDialog,
+ MaximizeBox = false,
+ MinimizeBox = false,
+ ClientSize = new System.Drawing.Size(380, 160),
+ };
+
+ var description = new Label
+ {
+ Text = "This dialog is implemented in managed C# code.\n\n" +
+ "It demonstrates how a WinForms UI can be displayed from a native " +
+ "Open Salamander plugin.",
+ Dock = DockStyle.Fill,
+ AutoSize = false,
+ Padding = new Padding(12),
+ };
+
+ var okButton = new Button
+ {
+ Text = "Close",
+ DialogResult = DialogResult.OK,
+ Anchor = AnchorStyles.Bottom | AnchorStyles.Right,
+ Size = new System.Drawing.Size(85, 26),
+ Location = new System.Drawing.Point(dialog.ClientSize.Width - 97, dialog.ClientSize.Height - 38),
+ };
+
+ dialog.Controls.Add(description);
+ dialog.Controls.Add(okButton);
+ dialog.AcceptButton = okButton;
+
+ ShowDialog(dialog, parent);
+ return 0;
+ }
+
+ private static int ShowConfiguration(IntPtr parent)
+ {
+ using var dialog = new Form
+ {
+ Text = "C# Demo Configuration",
+ StartPosition = FormStartPosition.CenterParent,
+ FormBorderStyle = FormBorderStyle.FixedDialog,
+ MaximizeBox = false,
+ MinimizeBox = false,
+ ClientSize = new System.Drawing.Size(420, 210),
+ };
+
+ var info = new Label
+ {
+ Text = "Managed configuration window.\n" +
+ "In a real plugin you could load and save settings " +
+ "through Salamander's registry APIs.",
+ AutoSize = false,
+ Dock = DockStyle.Top,
+ Padding = new Padding(12),
+ Height = 80,
+ };
+
+ var textLabel = new Label
+ {
+ Text = "Sample option:",
+ Location = new System.Drawing.Point(16, 96),
+ AutoSize = true,
+ };
+
+ var textBox = new TextBox
+ {
+ Location = new System.Drawing.Point(16, 118),
+ Width = 270,
+ Text = "Hello from managed code!",
+ };
+
+ var saveButton = new Button
+ {
+ Text = "OK",
+ DialogResult = DialogResult.OK,
+ Anchor = AnchorStyles.Bottom | AnchorStyles.Right,
+ Size = new System.Drawing.Size(85, 26),
+ Location = new System.Drawing.Point(dialog.ClientSize.Width - 185, dialog.ClientSize.Height - 42),
+ };
+
+ var cancelButton = new Button
+ {
+ Text = "Cancel",
+ DialogResult = DialogResult.Cancel,
+ Anchor = AnchorStyles.Bottom | AnchorStyles.Right,
+ Size = new System.Drawing.Size(85, 26),
+ Location = new System.Drawing.Point(dialog.ClientSize.Width - 94, dialog.ClientSize.Height - 42),
+ };
+
+ dialog.Controls.Add(info);
+ dialog.Controls.Add(textLabel);
+ dialog.Controls.Add(textBox);
+ dialog.Controls.Add(saveButton);
+ dialog.Controls.Add(cancelButton);
+
+ dialog.AcceptButton = saveButton;
+ dialog.CancelButton = cancelButton;
+
+ var result = ShowDialog(dialog, parent);
+ if (result == DialogResult.OK)
+ {
+ // In a real plugin the value would be forwarded to the native layer
+ // or persisted via Salamander's registry helpers.
+ MessageBox.Show(new WindowHandleWrapper(parent),
+ $"Managed sample saved:\n{textBox.Text}",
+ "C# Demo Plugin",
+ MessageBoxButtons.OK,
+ MessageBoxIcon.Information);
+ }
+
+ return 0;
+ }
+
+ private static int ShowHello(IntPtr parent, string payload)
+ {
+ using var dialog = new Form
+ {
+ Text = "Managed Window",
+ StartPosition = FormStartPosition.CenterParent,
+ ClientSize = new System.Drawing.Size(360, 180),
+ FormBorderStyle = FormBorderStyle.FixedDialog,
+ MaximizeBox = false,
+ MinimizeBox = false,
+ };
+
+ var label = new Label
+ {
+ Dock = DockStyle.Fill,
+ Padding = new Padding(16),
+ AutoSize = false,
+ TextAlign = System.Drawing.ContentAlignment.MiddleCenter,
+ Text = string.IsNullOrEmpty(payload)
+ ? "Hello from the managed world!"
+ : string.Format(CultureInfo.CurrentCulture, "Managed payload: {0}", payload),
+ };
+
+ dialog.Controls.Add(label);
+
+ var okButton = new Button
+ {
+ Text = "Close",
+ DialogResult = DialogResult.OK,
+ Anchor = AnchorStyles.Bottom | AnchorStyles.Right,
+ Size = new System.Drawing.Size(85, 26),
+ Location = new System.Drawing.Point(dialog.ClientSize.Width - 97, dialog.ClientSize.Height - 38),
+ };
+
+ dialog.Controls.Add(okButton);
+ dialog.AcceptButton = okButton;
+
+ ShowDialog(dialog, parent);
+ return 0;
+ }
+
+ private static DialogResult ShowDialog(Form dialog, IntPtr parent)
+ {
+ IWin32Window? owner = parent != IntPtr.Zero ? new WindowHandleWrapper(parent) : null;
+ return owner is null ? dialog.ShowDialog() : dialog.ShowDialog(owner);
+ }
+
+ private static IntPtr ParseHandle(string text)
+ {
+ if (ulong.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value))
+ {
+ return new IntPtr(unchecked((long)value));
+ }
+
+ return IntPtr.Zero;
+ }
+
+ private static void ShowError(string caption, Exception ex)
+ {
+ MessageBox.Show(
+ null,
+ $"{caption}\n{ex.Message}",
+ "C# Demo Plugin",
+ MessageBoxButtons.OK,
+ MessageBoxIcon.Error);
+ }
+
+ private sealed class WindowHandleWrapper : IWin32Window
+ {
+ public WindowHandleWrapper(IntPtr handle)
+ {
+ Handle = handle;
+ }
+
+ public IntPtr Handle { get; }
+ }
+}
diff --git a/src/plugins/csdemo/managed_bridge.cpp b/src/plugins/csdemo/managed_bridge.cpp
new file mode 100644
index 000000000..a254246b3
--- /dev/null
+++ b/src/plugins/csdemo/managed_bridge.cpp
@@ -0,0 +1,192 @@
+// SPDX-FileCopyrightText: 2024 Open Salamander Authors
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "precomp.h"
+#include "managed_bridge.h"
+
+#include
+#include
+#include
+
+#pragma comment(lib, "mscoree.lib")
+
+namespace
+{
+ICLRRuntimeHost* gRuntimeHost = nullptr;
+std::wstring gAssemblyPath;
+const wchar_t* const kManagedType = L"OpenSalamander.CSDemo.EntryPoint";
+const wchar_t* const kManagedMethod = L"Dispatch";
+
+std::wstring BuildArgument(const wchar_t* command, HWND parent, const wchar_t* payload)
+{
+ std::wstring argument = command;
+ argument.push_back(L';');
+
+ wchar_t buffer[32];
+ ULONGLONG handleValue = reinterpret_cast(parent);
+ StringCchPrintfW(buffer, _countof(buffer), L"%llu", handleValue);
+ argument.append(buffer);
+
+ argument.push_back(L';');
+ if (payload != nullptr)
+ {
+ argument.append(payload);
+ }
+
+ return argument;
+}
+
+std::wstring ToWide(const char* text)
+{
+ if (text == nullptr)
+ {
+ return std::wstring();
+ }
+
+ int required = MultiByteToWideChar(CP_UTF8, 0, text, -1, nullptr, 0);
+ if (required <= 0)
+ {
+ return std::wstring();
+ }
+
+ std::wstring result;
+ result.resize(required);
+ int converted = MultiByteToWideChar(CP_UTF8, 0, text, -1, result.data(), required);
+ if (converted <= 0)
+ {
+ return std::wstring();
+ }
+
+ result.resize(converted - 1);
+ return result;
+}
+
+bool ExecuteCommand(const wchar_t* command, HWND parent, const wchar_t* payload)
+{
+ if (gRuntimeHost == nullptr)
+ {
+ return false;
+ }
+
+ DWORD returnValue = 0;
+ std::wstring argument = BuildArgument(command, parent, payload);
+ HRESULT hr = gRuntimeHost->ExecuteInDefaultAppDomain(gAssemblyPath.c_str(), kManagedType, kManagedMethod,
+ argument.c_str(), &returnValue);
+ if (FAILED(hr))
+ {
+ wchar_t message[256];
+ StringCchPrintfW(message, _countof(message), L"Failed to execute managed command '%s' (0x%08X).", command, hr);
+ MessageBoxW(parent, message, L"C# Demo Plugin", MB_ICONERROR | MB_OK);
+ return false;
+ }
+
+ return returnValue == 0;
+}
+
+void ShowLoadError(HWND parent, const wchar_t* text)
+{
+ MessageBoxW(parent, text, L"C# Demo Plugin", MB_ICONERROR | MB_OK);
+}
+
+} // namespace
+
+bool ManagedBridge_EnsureInitialized(HWND parent)
+{
+ if (gRuntimeHost != nullptr)
+ {
+ return true;
+ }
+
+ ICLRMetaHost* metaHost = nullptr;
+ HRESULT hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&metaHost));
+ if (FAILED(hr))
+ {
+ ShowLoadError(parent, L"Failed to load CLR meta host.");
+ return false;
+ }
+
+ ICLRRuntimeInfo* runtimeInfo = nullptr;
+ hr = metaHost->GetRuntime(L"v4.0.30319", IID_PPV_ARGS(&runtimeInfo));
+ metaHost->Release();
+ if (FAILED(hr))
+ {
+ ShowLoadError(parent, L"Failed to locate CLR v4 runtime.");
+ return false;
+ }
+
+ hr = runtimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_PPV_ARGS(&gRuntimeHost));
+ runtimeInfo->Release();
+ if (FAILED(hr))
+ {
+ ShowLoadError(parent, L"Failed to create CLR runtime host.");
+ return false;
+ }
+
+ hr = gRuntimeHost->Start();
+ if (FAILED(hr))
+ {
+ ShowLoadError(parent, L"Failed to start CLR runtime.");
+ gRuntimeHost->Release();
+ gRuntimeHost = nullptr;
+ return false;
+ }
+
+ wchar_t modulePath[MAX_PATH] = {0};
+ if (GetModuleFileNameW(DLLInstance, modulePath, _countof(modulePath)) == 0)
+ {
+ ShowLoadError(parent, L"Failed to determine plugin path.");
+ ManagedBridge_Shutdown();
+ return false;
+ }
+
+ wchar_t* lastSlash = wcsrchr(modulePath, L'\\');
+ if (lastSlash != nullptr)
+ {
+ *(lastSlash + 1) = L'\0';
+ }
+
+ gAssemblyPath.assign(modulePath);
+ gAssemblyPath.append(L"CSDemo.Managed.dll");
+
+ return true;
+}
+
+void ManagedBridge_Shutdown()
+{
+ if (gRuntimeHost != nullptr)
+ {
+ gRuntimeHost->Stop();
+ gRuntimeHost->Release();
+ gRuntimeHost = nullptr;
+ gAssemblyPath.clear();
+ }
+}
+
+bool ManagedBridge_ShowAbout(HWND parent)
+{
+ if (!ManagedBridge_EnsureInitialized(parent))
+ {
+ return false;
+ }
+ return ExecuteCommand(L"About", parent, nullptr);
+}
+
+bool ManagedBridge_ShowConfiguration(HWND parent)
+{
+ if (!ManagedBridge_EnsureInitialized(parent))
+ {
+ return false;
+ }
+ return ExecuteCommand(L"Configure", parent, nullptr);
+}
+
+bool ManagedBridge_RunMenuCommand(HWND parent, const char* command)
+{
+ if (!ManagedBridge_EnsureInitialized(parent))
+ {
+ return false;
+ }
+
+ std::wstring payload = ToWide(command);
+ return ExecuteCommand(L"Menu", parent, payload.c_str());
+}
diff --git a/src/plugins/csdemo/managed_bridge.h b/src/plugins/csdemo/managed_bridge.h
new file mode 100644
index 000000000..b3294e58d
--- /dev/null
+++ b/src/plugins/csdemo/managed_bridge.h
@@ -0,0 +1,13 @@
+// SPDX-FileCopyrightText: 2024 Open Salamander Authors
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include
+
+bool ManagedBridge_EnsureInitialized(HWND parent);
+void ManagedBridge_Shutdown();
+bool ManagedBridge_ShowAbout(HWND parent);
+bool ManagedBridge_ShowConfiguration(HWND parent);
+bool ManagedBridge_RunMenuCommand(HWND parent, const char* command);
+
diff --git a/src/plugins/csdemo/menu.cpp b/src/plugins/csdemo/menu.cpp
new file mode 100644
index 000000000..c9a95825b
--- /dev/null
+++ b/src/plugins/csdemo/menu.cpp
@@ -0,0 +1,53 @@
+// SPDX-FileCopyrightText: 2023 Open Salamander Authors
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+//****************************************************************************
+//
+// Copyright (c) 2023 Open Salamander Authors
+//
+// This is a part of the Open Salamander SDK library.
+//
+//****************************************************************************
+
+#include "precomp.h"
+
+// ****************************************************************************
+// MENU SECTION
+// ****************************************************************************
+
+BOOL WINAPI
+CPluginInterfaceForMenuExt::ExecuteMenuItem(CSalamanderForOperationsAbstract* salamander,
+ HWND parent, int id, DWORD eventMask)
+{
+ switch (id)
+ {
+ case MENUCMD_SHOWHELLO:
+ {
+ if (!ManagedBridge_RunMenuCommand(parent, "Hello"))
+ {
+ SalamanderGeneral->ShowMessageBox("Unable to execute the managed command.", LoadStr(IDS_PLUGINNAME), MSGBOX_ERROR);
+ }
+ break;
+ }
+
+ default:
+ SalamanderGeneral->ShowMessageBox("Unknown command.", LoadStr(IDS_PLUGINNAME), MSGBOX_ERROR);
+ break;
+ }
+ return FALSE; // keep panel items selected
+}
+
+BOOL WINAPI
+CPluginInterfaceForMenuExt::HelpForMenuItem(HWND parent, int id)
+{
+ int helpID = 0;
+ switch (id)
+ {
+ case MENUCMD_SHOWHELLO:
+ helpID = IDH_MENU_HELLO;
+ break;
+ }
+ if (helpID != 0)
+ SalamanderGeneral->OpenHtmlHelp(parent, HHCDisplayContext, helpID, FALSE);
+ return helpID != 0;
+}
diff --git a/src/plugins/csdemo/precomp.cpp b/src/plugins/csdemo/precomp.cpp
new file mode 100644
index 000000000..5b3b36d58
--- /dev/null
+++ b/src/plugins/csdemo/precomp.cpp
@@ -0,0 +1,19 @@
+// SPDX-FileCopyrightText: 2023 Open Salamander Authors
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+//****************************************************************************
+//
+// Copyright (c) 2023 Open Salamander Authors
+//
+// This is a part of the Open Salamander SDK library.
+//
+//****************************************************************************
+
+#include "precomp.h"
+
+// the CSDemo project contains three groups of modules
+//
+// 1) the precomp.cpp module, which builds csdemo.pch (/Yc"precomp.h")
+// 2) modules that use csdemo.pch (/Yu"precomp.h")
+// 3) common files have their own automatically generated WINDOWS.PCH
+// (/YX"windows.h" /Fp"$(OutDir)\WINDOWS.PCH")
diff --git a/src/plugins/csdemo/precomp.h b/src/plugins/csdemo/precomp.h
new file mode 100644
index 000000000..64f01ef04
--- /dev/null
+++ b/src/plugins/csdemo/precomp.h
@@ -0,0 +1,58 @@
+// SPDX-FileCopyrightText: 2023 Open Salamander Authors
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+//****************************************************************************
+//
+// Copyright (c) 2023 Open Salamander Authors
+//
+// This is a part of the Open Salamander SDK library.
+//
+//****************************************************************************
+
+#pragma once
+
+#define WIN32_LEAN_AND_MEAN // exclude rarely-used stuff from Windows headers
+
+#include
+#include
+#include
+#ifdef _MSC_VER
+#include
+#endif // _MSC_VER
+#include
+#include
+#include
+#include
+#include
+#include
+
+#if defined(_DEBUG) && defined(_MSC_VER) // without passing file+line to 'new' operator, list of memory leaks shows only 'crtdbg.h(552)'
+#define new new (_NORMAL_BLOCK, __FILE__, __LINE__)
+#endif
+
+#include "versinfo.rh2"
+
+#include "spl_com.h"
+#include "spl_base.h"
+#include "spl_gen.h"
+#include "spl_menu.h"
+#include "spl_thum.h"
+#include "spl_view.h"
+#include "spl_vers.h"
+#include "spl_gui.h"
+
+#include "dbg.h"
+#include "mhandles.h"
+#include "arraylt.h"
+#include "winliblt.h"
+#include "auxtools.h"
+#include "csdemo.h"
+#include "managed_bridge.h"
+#include "csdemo.rh"
+#include "csdemo.rh2"
+#include "lang\lang.rh"
+
+#ifdef __BORLANDC__
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+#define max(a, b) (((a) > (b)) ? (a) : (b))
+#endif // __BORLANDC__
diff --git a/src/plugins/csdemo/vcxproj/csdemo.props b/src/plugins/csdemo/vcxproj/csdemo.props
new file mode 100644
index 000000000..f9e9b29ef
--- /dev/null
+++ b/src/plugins/csdemo/vcxproj/csdemo.props
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ WINVER=0x0601;_WIN32_WINNT=0x0601;_WIN32_IE=0x0800;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT;%(PreprocessorDefinitions)
+
+
+ WINVER=0x0601;%(PreprocessorDefinitions)
+
+
+
diff --git a/src/plugins/csdemo/vcxproj/csdemo.sln b/src/plugins/csdemo/vcxproj/csdemo.sln
new file mode 100644
index 000000000..082a9554e
--- /dev/null
+++ b/src/plugins/csdemo/vcxproj/csdemo.sln
@@ -0,0 +1,70 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29020.237
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "csdemo", "csdemo.vcxproj", "{8C89C5D0-4D7C-4A6D-8BFB-57C9B0E1682C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lang_csdemo", "lang_csdemo.vcxproj", "{3CB8B01D-BCB3-4F4E-B60A-9B46D2AF2F69}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSDemo.Managed", "..\managed\CSDemo.Managed.csproj", "{E9F70914-3011-4D4F-9E79-3A9540A5E0F3}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1BDAFFE2-B264-44E9-A670-B7EC029A726F}"
+ ProjectSection(SolutionItems) = preProject
+ ..\..\..\.editorconfig = ..\..\..\.editorconfig
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ SDK|x64 = SDK|x64
+ SDK|x86 = SDK|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {8C89C5D0-4D7C-4A6D-8BFB-57C9B0E1682C}.Debug|x64.ActiveCfg = Debug|x64
+ {8C89C5D0-4D7C-4A6D-8BFB-57C9B0E1682C}.Debug|x64.Build.0 = Debug|x64
+ {8C89C5D0-4D7C-4A6D-8BFB-57C9B0E1682C}.Debug|x86.ActiveCfg = Debug|Win32
+ {8C89C5D0-4D7C-4A6D-8BFB-57C9B0E1682C}.Debug|x86.Build.0 = Debug|Win32
+ {8C89C5D0-4D7C-4A6D-8BFB-57C9B0E1682C}.Release|x64.ActiveCfg = Release|x64
+ {8C89C5D0-4D7C-4A6D-8BFB-57C9B0E1682C}.Release|x64.Build.0 = Release|x64
+ {8C89C5D0-4D7C-4A6D-8BFB-57C9B0E1682C}.Release|x86.ActiveCfg = Release|Win32
+ {8C89C5D0-4D7C-4A6D-8BFB-57C9B0E1682C}.Release|x86.Build.0 = Release|Win32
+ {8C89C5D0-4D7C-4A6D-8BFB-57C9B0E1682C}.SDK|x64.ActiveCfg = SDK|x64
+ {8C89C5D0-4D7C-4A6D-8BFB-57C9B0E1682C}.SDK|x64.Build.0 = SDK|x64
+ {8C89C5D0-4D7C-4A6D-8BFB-57C9B0E1682C}.SDK|x86.ActiveCfg = SDK|Win32
+ {8C89C5D0-4D7C-4A6D-8BFB-57C9B0E1682C}.SDK|x86.Build.0 = SDK|Win32
+ {3CB8B01D-BCB3-4F4E-B60A-9B46D2AF2F69}.Debug|x64.ActiveCfg = Debug|x64
+ {3CB8B01D-BCB3-4F4E-B60A-9B46D2AF2F69}.Debug|x64.Build.0 = Debug|x64
+ {3CB8B01D-BCB3-4F4E-B60A-9B46D2AF2F69}.Debug|x86.ActiveCfg = Debug|Win32
+ {3CB8B01D-BCB3-4F4E-B60A-9B46D2AF2F69}.Debug|x86.Build.0 = Debug|Win32
+ {3CB8B01D-BCB3-4F4E-B60A-9B46D2AF2F69}.Release|x64.ActiveCfg = Release|x64
+ {3CB8B01D-BCB3-4F4E-B60A-9B46D2AF2F69}.Release|x64.Build.0 = Release|x64
+ {3CB8B01D-BCB3-4F4E-B60A-9B46D2AF2F69}.Release|x86.ActiveCfg = Release|Win32
+ {3CB8B01D-BCB3-4F4E-B60A-9B46D2AF2F69}.Release|x86.Build.0 = Release|Win32
+ {3CB8B01D-BCB3-4F4E-B60A-9B46D2AF2F69}.SDK|x64.ActiveCfg = SDK|x64
+ {3CB8B01D-BCB3-4F4E-B60A-9B46D2AF2F69}.SDK|x64.Build.0 = SDK|x64
+ {3CB8B01D-BCB3-4F4E-B60A-9B46D2AF2F69}.SDK|x86.ActiveCfg = SDK|Win32
+ {3CB8B01D-BCB3-4F4E-B60A-9B46D2AF2F69}.SDK|x86.Build.0 = SDK|Win32
+ {E9F70914-3011-4D4F-9E79-3A9540A5E0F3}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {E9F70914-3011-4D4F-9E79-3A9540A5E0F3}.Debug|x64.Build.0 = Debug|Any CPU
+ {E9F70914-3011-4D4F-9E79-3A9540A5E0F3}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {E9F70914-3011-4D4F-9E79-3A9540A5E0F3}.Debug|x86.Build.0 = Debug|Any CPU
+ {E9F70914-3011-4D4F-9E79-3A9540A5E0F3}.Release|x64.ActiveCfg = Release|Any CPU
+ {E9F70914-3011-4D4F-9E79-3A9540A5E0F3}.Release|x64.Build.0 = Release|Any CPU
+ {E9F70914-3011-4D4F-9E79-3A9540A5E0F3}.Release|x86.ActiveCfg = Release|Any CPU
+ {E9F70914-3011-4D4F-9E79-3A9540A5E0F3}.Release|x86.Build.0 = Release|Any CPU
+ {E9F70914-3011-4D4F-9E79-3A9540A5E0F3}.SDK|x64.ActiveCfg = Release|Any CPU
+ {E9F70914-3011-4D4F-9E79-3A9540A5E0F3}.SDK|x64.Build.0 = Release|Any CPU
+ {E9F70914-3011-4D4F-9E79-3A9540A5E0F3}.SDK|x86.ActiveCfg = Release|Any CPU
+ {E9F70914-3011-4D4F-9E79-3A9540A5E0F3}.SDK|x86.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {375C9D55-0C0E-42AE-8696-21DE91B07CCF}
+ EndGlobalSection
+EndGlobal
diff --git a/src/plugins/csdemo/vcxproj/csdemo.vcxproj b/src/plugins/csdemo/vcxproj/csdemo.vcxproj
new file mode 100644
index 000000000..ec20b5aad
--- /dev/null
+++ b/src/plugins/csdemo/vcxproj/csdemo.vcxproj
@@ -0,0 +1,219 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ {8C89C5D0-4D7C-4A6D-8BFB-57C9B0E1682C}
+ csdemo
+ 10.0
+
+
+
+
+ false
+ v143
+ DynamicLibrary
+
+
+ true
+ v143
+ DynamicLibrary
+
+
+ false
+ v143
+ DynamicLibrary
+
+
+ true
+ v143
+ DynamicLibrary
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $([System.IO.Path]::Combine('$(OPENSAL_BUILD_DIR)', 'salamander'))\
+
+
+ $(ProjectDir)..\..\..\..\build\salamander\
+
+
+ $(CSDemoBuildRoot)$(Configuration)_$(ShortPlatform)\plugins\csdemo\
+ $(CSDemoPluginDir)
+ $(OutDir)Intermediate\
+
+
+
+
+
+ stdcpplatest
+
+
+
+
+ stdcpplatest
+
+
+
+
+ stdcpplatest
+
+
+
+
+ stdcpplatest
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Create
+ Create
+ Create
+ Create
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {3cb8b01d-bcb3-4f4e-b60a-9b46d2af2f69}
+ false
+
+
+ {E9F70914-3011-4D4F-9E79-3A9540A5E0F3}
+ false
+
+
+
+
+ if not exist "$(CSDemoPluginDir)" mkdir "$(CSDemoPluginDir)"
if exist "$(ProjectDir)..\managed\bin\$(Configuration)\CSDemo.Managed.dll" copy /Y "$(ProjectDir)..\managed\bin\$(Configuration)\CSDemo.Managed.dll" "$(CSDemoPluginDir)CSDemo.Managed.dll"
if exist "$(ProjectDir)..\managed\bin\$(Configuration)\CSDemo.Managed.pdb" copy /Y "$(ProjectDir)..\managed\bin\$(Configuration)\CSDemo.Managed.pdb" "$(CSDemoPluginDir)CSDemo.Managed.pdb"
+
+
+
+
+
+
+
diff --git a/src/plugins/csdemo/vcxproj/csdemo.vcxproj.filters b/src/plugins/csdemo/vcxproj/csdemo.vcxproj.filters
new file mode 100644
index 000000000..4dcca5c2f
--- /dev/null
+++ b/src/plugins/csdemo/vcxproj/csdemo.vcxproj.filters
@@ -0,0 +1,100 @@
+
+
+
+
+ {7ec3b1ea-c9ff-4c6d-a33d-01d4cc9259e3}
+
+
+ {b358cda3-ea28-4487-886c-6e8d3e40ba6d}
+
+
+ {70c292f6-5208-42dd-8264-933d8a862f5b}
+
+
+ {199e8645-6a17-4b65-a388-f9700eb782af}
+
+
+
+
+ cpp
+
+
+ cpp
+
+
+ cpp
+
+
+ shared
+
+
+ shared
+
+
+ shared
+
+
+
+
+ h
+
+
+ h
+
+
+ shared
+
+
+ shared
+
+
+ shared
+
+
+ shared
+
+
+ shared
+
+
+ shared
+
+
+ shared
+
+
+ shared
+
+
+ shared
+
+
+ shared
+
+
+
+
+ rc
+
+
+ rc
+
+
+ rc
+
+
+ rc
+
+
+ rc
+
+
+ rc
+
+
+
+
+ rc
+
+
+
\ No newline at end of file
diff --git a/src/plugins/csdemo/vcxproj/lang_csdemo.props b/src/plugins/csdemo/vcxproj/lang_csdemo.props
new file mode 100644
index 000000000..1f15c5bbe
--- /dev/null
+++ b/src/plugins/csdemo/vcxproj/lang_csdemo.props
@@ -0,0 +1,13 @@
+
+
+
+
+
+ csdemo
+
+
+
+ $(ShortProjectName)
+
+
+
diff --git a/src/plugins/csdemo/vcxproj/lang_csdemo.vcxproj b/src/plugins/csdemo/vcxproj/lang_csdemo.vcxproj
new file mode 100644
index 000000000..1db2d2bd1
--- /dev/null
+++ b/src/plugins/csdemo/vcxproj/lang_csdemo.vcxproj
@@ -0,0 +1,151 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ {3CB8B01D-BCB3-4F4E-B60A-9B46D2AF2F69}
+ lang_csdemo
+ 10.0
+ Win32Proj
+
+
+
+
+ false
+ v143
+ DynamicLibrary
+
+
+ true
+ v143
+ DynamicLibrary
+
+
+ false
+ v143
+ DynamicLibrary
+
+
+ true
+ v143
+ DynamicLibrary
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $([System.IO.Path]::Combine('$(OPENSAL_BUILD_DIR)', 'salamander'))\
+
+
+ $(ProjectDir)..\..\..\..\build\salamander\
+
+
+ $(CSDemoBuildRoot)$(Configuration)_$(ShortPlatform)\plugins\csdemo\lang\
+ $(CSDemoLangDir)
+ $(OutDir)Intermediate\
+
+
+
+
+
+ stdcpplatest
+
+
+
+
+ stdcpplatest
+
+
+
+
+ stdcpplatest
+
+
+
+
+ stdcpplatest
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/plugins/csdemo/versinfo.rh2 b/src/plugins/csdemo/versinfo.rh2
new file mode 100644
index 000000000..66598ceee
--- /dev/null
+++ b/src/plugins/csdemo/versinfo.rh2
@@ -0,0 +1,43 @@
+//****************************************************************************
+//
+// Copyright (c) 2023 Open Salamander Authors
+//
+// This is a part of the Open Salamander SDK library.
+//
+//****************************************************************************
+
+// WARNING: cannot be replaced by "#pragma once" because it is included from .rc file and it seems resource compiler does not support "#pragma once"
+#ifndef __CSDEMO_VERSINFO_RH2
+#define __CSDEMO_VERSINFO_RH2
+
+#if defined(APSTUDIO_INVOKED) && !defined(APSTUDIO_READONLY_SYMBOLS)
+#error this file is not editable by Microsoft Visual C++
+#endif //defined(APSTUDIO_INVOKED) && !defined(APSTUDIO_READONLY_SYMBOLS)
+
+// defines for plugin.SPL and plugin.SLG VERSIONINFO
+// look at shared\versinfo.rc
+
+#define VERSINFO_MAJOR 1
+#define VERSINFO_MINORA 0
+#define VERSINFO_MINORB 2
+
+#include "spl_vers.h" // get version and build numbers
+
+#define VERSINFO_COPYRIGHT "Copyright © 2009-2023 Open Salamander Authors"
+#define VERSINFO_COMPANY "Open Salamander"
+
+#define VERSINFO_DESCRIPTION "Managed demo plugin for Open Salamander"
+
+#ifdef _LANG
+#define VERSINFO_INTERNAL "ENGLISH"
+#define VERSINFO_ORIGINAL VERSINFO_INTERNAL ".SLG"
+#else
+#define VERSINFO_INTERNAL "CSDEMO"
+#define VERSINFO_ORIGINAL VERSINFO_INTERNAL ".SPL"
+#endif
+
+// for SLG translators
+#define VERSINFO_SLG_WEB "www.altap.cz"
+#define VERSINFO_SLG_COMMENT "English version"
+
+#endif // __CSDEMO_VERSINFO_RH2
diff --git a/src/plugins/shared/baseaddr_x64.txt b/src/plugins/shared/baseaddr_x64.txt
index 256af78f1..4c417cbe9 100644
--- a/src/plugins/shared/baseaddr_x64.txt
+++ b/src/plugins/shared/baseaddr_x64.txt
@@ -103,4 +103,6 @@ lang_renamer 0x0000010039c00000
portables 0x0000010029d00000
lang_portables 0x0000010039d00000
regliba 0x0000010029e00000
+csdemo 0x0000010029f00000
+lang_csdemo 0x0000010039f00000
diff --git a/src/plugins/shared/baseaddr_x86.txt b/src/plugins/shared/baseaddr_x86.txt
index 989f3760f..641c76bbd 100644
--- a/src/plugins/shared/baseaddr_x86.txt
+++ b/src/plugins/shared/baseaddr_x86.txt
@@ -103,4 +103,6 @@ lang_renamer 0x39c00000
portables 0x29d00000
lang_portables 0x39d00000
regliba 0x29e00000
+csdemo 0x29f00000
+lang_csdemo 0x39f00000
diff --git a/src/vcxproj/salamand.sln b/src/vcxproj/salamand.sln
index f45010095..4c5007845 100644
--- a/src/vcxproj/salamand.sln
+++ b/src/vcxproj/salamand.sln
@@ -37,6 +37,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lang_dbviewer", "..\plugins
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lang_demomenu", "..\plugins\demomenu\vcxproj\lang_demomenu.vcxproj", "{694D8E3F-FCBD-4F88-AA49-FFAD994377CC}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lang_csdemo", "..\plugins\csdemo\vcxproj\lang_csdemo.vcxproj", "{3CB8B01D-BCB3-4F4E-B60A-9B46D2AF2F69}"
+EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lang_demoplug", "..\plugins\demoplug\vcxproj\lang_demoplug.vcxproj", "{3742BD58-B25B-46A6-9834-60FE8819E3D6}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lang_demoview", "..\plugins\demoview\vcxproj\lang_demoview.vcxproj", "{42D388F6-A8CC-4EA5-BE0F-15220B4BA200}"
@@ -99,6 +101,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dbviewer", "..\plugins\dbvi
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "demomenu", "..\plugins\demomenu\vcxproj\demomenu.vcxproj", "{9154D733-3414-41AB-8322-FD44D5BD311C}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "csdemo", "..\plugins\csdemo\vcxproj\csdemo.vcxproj", "{8C89C5D0-4D7C-4A6D-8BFB-57C9B0E1682C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSDemo.Managed", "..\plugins\csdemo\managed\CSDemo.Managed.csproj", "{E9F70914-3011-4D4F-9E79-3A9540A5E0F3}"
+EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "demoplug", "..\plugins\demoplug\vcxproj\demoplug.vcxproj", "{C355231B-65C2-4826-B419-37518E187F78}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "demoview", "..\plugins\demoview\vcxproj\demoview.vcxproj", "{B6636FCB-B76E-4DD5-8E08-350F2F8C5163}"
@@ -1074,6 +1080,36 @@ Global
{3D197204-77AD-4B0D-B2E3-45A20CCF9140}.Release|x64.Build.0 = Release|x64
{3D197204-77AD-4B0D-B2E3-45A20CCF9140}.Utils (Release)|Win32.ActiveCfg = Release|Win32
{3D197204-77AD-4B0D-B2E3-45A20CCF9140}.Utils (Release)|x64.ActiveCfg = Release|x64
+ {3CB8B01D-BCB3-4F4E-B60A-9B46D2AF2F69}.Debug|Win32.ActiveCfg = Debug|Win32
+ {3CB8B01D-BCB3-4F4E-B60A-9B46D2AF2F69}.Debug|Win32.Build.0 = Debug|Win32
+ {3CB8B01D-BCB3-4F4E-B60A-9B46D2AF2F69}.Debug|x64.ActiveCfg = Debug|x64
+ {3CB8B01D-BCB3-4F4E-B60A-9B46D2AF2F69}.Debug|x64.Build.0 = Debug|x64
+ {3CB8B01D-BCB3-4F4E-B60A-9B46D2AF2F69}.Release|Win32.ActiveCfg = Release|Win32
+ {3CB8B01D-BCB3-4F4E-B60A-9B46D2AF2F69}.Release|Win32.Build.0 = Release|Win32
+ {3CB8B01D-BCB3-4F4E-B60A-9B46D2AF2F69}.Release|x64.ActiveCfg = Release|x64
+ {3CB8B01D-BCB3-4F4E-B60A-9B46D2AF2F69}.Release|x64.Build.0 = Release|x64
+ {3CB8B01D-BCB3-4F4E-B60A-9B46D2AF2F69}.Utils (Release)|Win32.ActiveCfg = Release|Win32
+ {3CB8B01D-BCB3-4F4E-B60A-9B46D2AF2F69}.Utils (Release)|x64.ActiveCfg = Release|x64
+ {8C89C5D0-4D7C-4A6D-8BFB-57C9B0E1682C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {8C89C5D0-4D7C-4A6D-8BFB-57C9B0E1682C}.Debug|Win32.Build.0 = Debug|Win32
+ {8C89C5D0-4D7C-4A6D-8BFB-57C9B0E1682C}.Debug|x64.ActiveCfg = Debug|x64
+ {8C89C5D0-4D7C-4A6D-8BFB-57C9B0E1682C}.Debug|x64.Build.0 = Debug|x64
+ {8C89C5D0-4D7C-4A6D-8BFB-57C9B0E1682C}.Release|Win32.ActiveCfg = Release|Win32
+ {8C89C5D0-4D7C-4A6D-8BFB-57C9B0E1682C}.Release|Win32.Build.0 = Release|Win32
+ {8C89C5D0-4D7C-4A6D-8BFB-57C9B0E1682C}.Release|x64.ActiveCfg = Release|x64
+ {8C89C5D0-4D7C-4A6D-8BFB-57C9B0E1682C}.Release|x64.Build.0 = Release|x64
+ {8C89C5D0-4D7C-4A6D-8BFB-57C9B0E1682C}.Utils (Release)|Win32.ActiveCfg = Release|Win32
+ {8C89C5D0-4D7C-4A6D-8BFB-57C9B0E1682C}.Utils (Release)|x64.ActiveCfg = Release|x64
+ {E9F70914-3011-4D4F-9E79-3A9540A5E0F3}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {E9F70914-3011-4D4F-9E79-3A9540A5E0F3}.Debug|Win32.Build.0 = Debug|Any CPU
+ {E9F70914-3011-4D4F-9E79-3A9540A5E0F3}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {E9F70914-3011-4D4F-9E79-3A9540A5E0F3}.Debug|x64.Build.0 = Debug|Any CPU
+ {E9F70914-3011-4D4F-9E79-3A9540A5E0F3}.Release|Win32.ActiveCfg = Release|Any CPU
+ {E9F70914-3011-4D4F-9E79-3A9540A5E0F3}.Release|Win32.Build.0 = Release|Any CPU
+ {E9F70914-3011-4D4F-9E79-3A9540A5E0F3}.Release|x64.ActiveCfg = Release|Any CPU
+ {E9F70914-3011-4D4F-9E79-3A9540A5E0F3}.Release|x64.Build.0 = Release|Any CPU
+ {E9F70914-3011-4D4F-9E79-3A9540A5E0F3}.Utils (Release)|Win32.ActiveCfg = Release|Any CPU
+ {E9F70914-3011-4D4F-9E79-3A9540A5E0F3}.Utils (Release)|x64.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE