Skip to content

Instantly share code, notes, and snippets.

@kingsamchen
Created May 20, 2014 10:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kingsamchen/398dd430c6180ecfccc7 to your computer and use it in GitHub Desktop.
Save kingsamchen/398dd430c6180ecfccc7 to your computer and use it in GitHub Desktop.
/******************************************************************************
Module: Singleton.cpp
Notices: Copyright (c) 2008 Jeffrey Richter & Christophe Nasarre
******************************************************************************/
#include "resource.h"
#include "..\CommonFiles\CmnHdr.h" /* See Appendix A. */
#include <windowsx.h>
#include <Sddl.h> // for SID management
#include <tchar.h>
#include <strsafe.h>
///////////////////////////////////////////////////////////////////////////////
// Main dialog
HWND g_hDlg;
// Mutex, boundary and namespace used to detect previous running instance
HANDLE g_hSingleton = NULL;
HANDLE g_hBoundary = NULL;
HANDLE g_hNamespace = NULL;
// Keep track whether or not the namespace was created or open for clean-up
BOOL g_bNamespaceOpened = FALSE;
// Names of boundary and private namespace
PCTSTR g_szBoundary = TEXT("3-Boundary");
PCTSTR g_szNamespace = TEXT("3-Namespace");
#define DETAILS_CTRL GetDlgItem(g_hDlg, IDC_EDIT_DETAILS)
///////////////////////////////////////////////////////////////////////////////
// Adds a string to the "Details" edit control
void AddText(PCTSTR pszFormat, ...) {
va_list argList;
va_start(argList, pszFormat);
TCHAR sz[20 * 1024];
Edit_GetText(DETAILS_CTRL, sz, _countof(sz));
_vstprintf_s(
_tcschr(sz, TEXT('\0')), _countof(sz) - _tcslen(sz),
pszFormat, argList);
Edit_SetText(DETAILS_CTRL, sz);
va_end(argList);
}
///////////////////////////////////////////////////////////////////////////////
void Dlg_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) {
switch (id) {
case IDOK:
case IDCANCEL:
// User has clicked on the Exit button
// or dismissed the dialog with ESCAPE
EndDialog(hwnd, id);
break;
}
}
///////////////////////////////////////////////////////////////////////////////
void CheckInstances() {
// Create the boundary descriptor
g_hBoundary = CreateBoundaryDescriptor(g_szBoundary, 0);
// Create a SID corresponding to the Local Administrator group
BYTE localAdminSID[SECURITY_MAX_SID_SIZE];
PSID pLocalAdminSID = &localAdminSID;
DWORD cbSID = sizeof(localAdminSID);
if (!CreateWellKnownSid(
WinBuiltinAdministratorsSid, NULL, pLocalAdminSID, &cbSID)
) {
AddText(TEXT("AddSIDToBoundaryDescriptor failed: %u\r\n"),
GetLastError());
return;
}
// Associate the Local Admin SID to the boundary descriptor
// --> only applications running under an administrator user
// will be able to access the kernel objects in the same namespace
if (!AddSIDToBoundaryDescriptor(&g_hBoundary, pLocalAdminSID)) {
AddText(TEXT("AddSIDToBoundaryDescriptor failed: %u\r\n"),
GetLastError());
return;
}
// Create the namespace for Local Administrators only
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.bInheritHandle = FALSE;
if (!ConvertStringSecurityDescriptorToSecurityDescriptor(
TEXT("D:(A;;GA;;;BA)"),
SDDL_REVISION_1, &sa.lpSecurityDescriptor, NULL)) {
AddText(TEXT("Security Descriptor creation failed: %u\r\n"), GetLastError());
return;
}
g_hNamespace =
CreatePrivateNamespace(&sa, g_hBoundary, g_szNamespace);
// Don't forget to release memory for the security descriptor
LocalFree(sa.lpSecurityDescriptor);
// Check the private namespace creation result
DWORD dwLastError = GetLastError();
if (g_hNamespace == NULL) {
// Nothing to do if access is denied
// --> this code must run under a Local Administrator account
if (dwLastError == ERROR_ACCESS_DENIED) {
AddText(TEXT("Access denied when creating the namespace.\r\n"));
AddText(TEXT(" You must be running as Administrator.\r\n\r\n"));
return;
} else {
if (dwLastError == ERROR_ALREADY_EXISTS) {
// If another instance has already created the namespace,
// we need to open it instead.
AddText(TEXT("CreatePrivateNamespace failed: %u\r\n"), dwLastError);
g_hNamespace = OpenPrivateNamespace(g_hBoundary, g_szNamespace);
if (g_hNamespace == NULL) {
AddText(TEXT(" and OpenPrivateNamespace failed: %u\r\n"),
dwLastError);
return;
} else {
g_bNamespaceOpened = TRUE;
AddText(TEXT(" but OpenPrivateNamespace succeeded\r\n\r\n"));
}
} else {
AddText(TEXT("Unexpected error occured: %u\r\n\r\n"),
dwLastError);
return;
}
}
}
// Try to create the mutex object with a name
// based on the private namespace
TCHAR szMutexName[64];
StringCchPrintf(szMutexName, _countof(szMutexName), TEXT("%s\\%s"),
g_szNamespace, TEXT("Singleton"));
g_hSingleton = CreateMutex(NULL, FALSE, szMutexName);
if (GetLastError() == ERROR_ALREADY_EXISTS) {
// There is already an instance of this Singleton object
AddText(TEXT("Another instance of Singleton is running:\r\n"));
AddText(TEXT("--> Impossible to access application features.\r\n"));
} else {
// First time the Singleton object is created
AddText(TEXT("First instance of Singleton:\r\n"));
AddText(TEXT("--> Access application features now.\r\n"));
}
}
///////////////////////////////////////////////////////////////////////////////
BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam) {
chSETDLGICONS(hwnd, IDI_SINGLETON);
// Keep track of the main dialog window handle
g_hDlg = hwnd;
// Check whether another instance is already running
CheckInstances();
return(TRUE);
}
///////////////////////////////////////////////////////////////////////////////
INT_PTR WINAPI Dlg_Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
chHANDLE_DLGMSG(hwnd, WM_COMMAND, Dlg_OnCommand);
chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Dlg_OnInitDialog);
}
return(FALSE);
}
///////////////////////////////////////////////////////////////////////////////
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// Show main window
DialogBox(hInstance, MAKEINTRESOURCE(IDD_SINGLETON), NULL, Dlg_Proc);
// Don't forget to clean up and release kernel resources
if (g_hSingleton != NULL) {
CloseHandle(g_hSingleton);
}
if (g_hNamespace != NULL) {
if (g_bNamespaceOpened) { // Open namespace
ClosePrivateNamespace(g_hNamespace, 0);
} else { // Created namespace
ClosePrivateNamespace(g_hNamespace, PRIVATE_NAMESPACE_FLAG_DESTROY);
}
}
if (g_hBoundary != NULL) {
DeleteBoundaryDescriptor(g_hBoundary);
}
return(0);
}
//////////////////////////////// End of File //////////////////////////////////
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment