From c756dee8110a63700f479a1fb3ccb8a18873f873 Mon Sep 17 00:00:00 2001 From: zenden2k Date: Sun, 26 Jul 2015 20:31:57 +0300 Subject: [PATCH] Initial commit --- singleinstance.sln | 22 ++ singleinstance/Resource.h | 31 +++ singleinstance/singleinstance.cpp | 258 ++++++++++++++++++ singleinstance/singleinstance.ico | Bin 0 -> 2998 bytes singleinstance/singleinstance.rc | Bin 0 -> 6962 bytes singleinstance/singleinstance.vcxproj | 104 +++++++ singleinstance/singleinstance.vcxproj.filters | 52 ++++ singleinstance/small.ico | Bin 0 -> 2998 bytes singleinstance/stdafx.cpp | 8 + singleinstance/stdafx.h | 21 ++ singleinstance/targetver.h | 8 + 11 files changed, 504 insertions(+) create mode 100644 singleinstance.sln create mode 100644 singleinstance/Resource.h create mode 100644 singleinstance/singleinstance.cpp create mode 100644 singleinstance/singleinstance.ico create mode 100644 singleinstance/singleinstance.rc create mode 100644 singleinstance/singleinstance.vcxproj create mode 100644 singleinstance/singleinstance.vcxproj.filters create mode 100644 singleinstance/small.ico create mode 100644 singleinstance/stdafx.cpp create mode 100644 singleinstance/stdafx.h create mode 100644 singleinstance/targetver.h diff --git a/singleinstance.sln b/singleinstance.sln new file mode 100644 index 0000000..0f37d07 --- /dev/null +++ b/singleinstance.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.40418.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "singleinstance", "singleinstance\singleinstance.vcxproj", "{95C5CED1-7955-43FC-9EA3-E20D2CE1DEB1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {95C5CED1-7955-43FC-9EA3-E20D2CE1DEB1}.Debug|Win32.ActiveCfg = Debug|Win32 + {95C5CED1-7955-43FC-9EA3-E20D2CE1DEB1}.Debug|Win32.Build.0 = Debug|Win32 + {95C5CED1-7955-43FC-9EA3-E20D2CE1DEB1}.Release|Win32.ActiveCfg = Release|Win32 + {95C5CED1-7955-43FC-9EA3-E20D2CE1DEB1}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/singleinstance/Resource.h b/singleinstance/Resource.h new file mode 100644 index 0000000..61f9908 --- /dev/null +++ b/singleinstance/Resource.h @@ -0,0 +1,31 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by singleinstance.rc +// + +#define IDS_APP_TITLE 103 + +#define IDR_MAINFRAME 128 +#define IDD_SINGLEINSTANCE_DIALOG 102 +#define IDD_ABOUTBOX 103 +#define IDM_ABOUT 104 +#define IDM_EXIT 105 +#define IDI_SINGLEINSTANCE 107 +#define IDI_SMALL 108 +#define IDC_SINGLEINSTANCE 109 +#define IDC_MYICON 2 +#ifndef IDC_STATIC +#define IDC_STATIC -1 +#endif +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS + +#define _APS_NO_MFC 130 +#define _APS_NEXT_RESOURCE_VALUE 129 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 110 +#endif +#endif diff --git a/singleinstance/singleinstance.cpp b/singleinstance/singleinstance.cpp new file mode 100644 index 0000000..1c40a39 --- /dev/null +++ b/singleinstance/singleinstance.cpp @@ -0,0 +1,258 @@ +// singleinstance.cpp : Defines the entry point for the application. +// + +#include "stdafx.h" + +/** +This app allows to select multiple files and launch one instance of command process from windows explorer's context menu. + +Example of usage: + +Windows Registry Editor Version 5.00 + +[HKEY_CLASSES_ROOT\SystemFileAssociations\.txt\Shell\p4merge] +"MultiSelectModel"="Player" + +[HKEY_CLASSES_ROOT\SystemFileAssociations\.txt\Shell\p4merge\Command] +@="\"d:\\singleinstance.exe\" %1 \"C:\\Program Files\\Perforce\\p4merge.exe\" $files --si-timeout 400" + +*/ +#include +#include +#include + +class CLimitSingleInstance { +protected: + DWORD m_dwLastError; + HANDLE m_hMutex; + +public: + CLimitSingleInstance(TCHAR *strMutexName) + { + m_hMutex = CreateMutex(NULL, FALSE, strMutexName); //do early + m_dwLastError = GetLastError(); //save for use later... + } + + ~CLimitSingleInstance(){ + if (m_hMutex) //Do not forget to close handles. + { + CloseHandle(m_hMutex); //Do as late as possible. + m_hMutex = NULL; //Good habit to be in. + } + } + + BOOL IsAnotherInstanceRunning(){ + return (ERROR_ALREADY_EXISTS == m_dwLastError); + } +}; + +int timeout = 400; // ms +enum { TIMER_ID = 1 }; +LPTSTR *szArgList; +int argCount; +CLimitSingleInstance singleInstance(TEXT("Global\\{C30D92DD-DEE6-41A1-8907-B42FBE58C8A6}")); +std::vector files; +HINSTANCE hInst; // current instance +TCHAR szWindowClass[256] = _T("SingleInstance_WindowClass"); // the main window class name + +// Forward declarations of functions included in this code module: +ATOM MyRegisterClass(HINSTANCE hInstance); +BOOL InitInstance(HINSTANCE, int); +LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); + +int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { + szArgList = CommandLineToArgvW(GetCommandLine(), &argCount); + for (int i = 0; i < argCount; i++) { + if (!lstrcmp(szArgList[i], _T("--si-timeout")) && i + 1 < argCount ) { + timeout = std::stoi(szArgList[i + 1]); + } + } + + if (singleInstance.IsAnotherInstanceRunning()) { + for (;;) { + DWORD startTime = GetTickCount(); + HWND wnd = FindWindow(szWindowClass, NULL); + if (wnd) { + LPCTSTR lpszString = szArgList[1]; + COPYDATASTRUCT cds; + cds.dwData = 1; // can be anything + cds.cbData = sizeof(TCHAR) * (_tcslen(lpszString) + 1); + cds.lpData = (void*)lpszString; + SendMessage(wnd, WM_COPYDATA, (WPARAM)wnd, (LPARAM)(LPVOID)&cds); + break; + } else { + Sleep(50); + if (GetTickCount() - startTime > timeout ) { + break; // failure + } + } + } + LocalFree(szArgList); + return 0; + } + + if (szArgList ) { + if (argCount > 3) { + files.push_back(szArgList[1]); + } else { + MessageBox(0, L"Usage: singleinstance.exe \"%1\" $files [arguments]\r\n\r\n" + L"Optional arguments for singleinstance (not passed to command):\r\n" + L"--si-timeout