您的位置:首页 > 编程语言

Windows核心编程学习三:利用专有命名空间实现单一实例

2013-04-18 23:45 429 查看
注:源码为学习《Windows核心编程》的一些尝试,非原创。若能有助于一二访客,幸甚。

1.基本框架

/*******************************************************************************
 * File:	ErrorShow.cpp
 * Time:	2013-04-16
 * 描述:	修改试验原书同名程序
 *******************************************************************************/

#include <Windows.h>
#include <Windowsx.h>
#include <tchar.h>
#include "resource.h"

// Always compiler using Unicode.
#ifndef UNICODE
	#define UNICODE
#endif

#define chHANDLE_DLGMSG(hWnd, message, fn)                 \
   case (message): return (SetDlgMsgResult(hWnd, uMsg,     \
      HANDLE_##message((hWnd), (wParam), (lParam), (fn))))

BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
{
	return TRUE;
}

void Dlg_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
	switch (id) {
		case IDOK:
		case IDCANCEL:
			EndDialog(hwnd, id);
			break;
	}
}

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);

	DialogBox(hInstance, MAKEINTRESOURCE(IDD_SINGLETON), NULL, Dlg_Proc);

	return 0;
}




2.使用可变参数

// Main dialog
HWND	g_hDlg;

// 添加一个字符串到编辑框
void AddText(PCTSTR pszFormat, ...)
{
	/* VA_LIST的用法:
	 *(1)首先在函数里定义一具VA_LIST型的变量,这个变量是指向参数的指针;
	 *(2)然后用VA_START宏初始化变量刚定义的VA_LIST变量;
	 *(3)然后用VA_ARG返回可变的参数,VA_ARG的第二个参数是你要返回的参数的
	 *		类型(如果函数有多个可变参数的,依次调用VA_ARG获取各个参数);
	 *(4)最后用VA_END宏结束可变参数的获取。 */
	va_list argList;

	va_start(argList, pszFormat);

	TCHAR sz[20 * 1024];

	Edit_GetText(GetDlgItem(g_hDlg, IDC_EDIT_DETAILS), sz, _countof(sz));
	_vstprintf_s(_tcschr(sz, TEXT('\0')), _countof(sz) - _tcslen(sz), pszFormat, argList);
	Edit_SetText(GetDlgItem(g_hDlg, IDC_EDIT_DETAILS), sz);

	va_end(argList);
}

BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
{
	g_hDlg = hwnd;

	AddText(TEXT("a~z: \r\n"));
	for (char c = 'a'; c <= 'z'; c++)
		AddText(TEXT("%c "), c);

	return TRUE;
}



3.利用专有命名空间实现单实例应用程序

void CheckInstances()
{
	// 创建边界描述符
	g_hBoundary = CreateBoundaryDescriptor(g_szBoundary, 0);

	// 创建一个对应于本地管理员组的安全描述符SID
	BYTE localAdminSID[SECURITY_MAX_SID_SIZE];
	PSID pLocalAdminSID = &localAdminSID;
	DWORD cbSID = sizeof(localAdminSID);
		
	/*
		The CreateWellKnownSid function creates a SID for predefined aliases.
		BOOL WINAPI CreateWellKnownSid(
		  __in       WELL_KNOWN_SID_TYPE WellKnownSidType,
		  __in_opt   PSID DomainSid,
		  __out_opt  PSID pSid,
		  __inout    DWORD* cbSid
		);

		Parameters
		WellKnownSidType 
		Member of the WELL_KNOWN_SID_TYPE enumeration that specifies what the SID will identify.
		DomainSid 
		A pointer to a SID that identifies the domain control to use when creating the SID. 
		Pass NULL to use the local computer.
		pSid 
		A pointer to memory where CreateWellKnownSid will store the new SID.
		cbSid 
		A pointer to a DWORD that contains the number of bytes available at pSid. 
		The CreateWellKnownSid function stores the number of bytes actually used at this location.
	*/
	if (!CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, pLocalAdminSID, &cbSID))
	{
		AddText(TEXT("添加安全描述符到边界描述符失败: %u\r\n"), GetLastError());
		return;
	}

	// 将本地管理员组的安全描述符与边界描述符关联起来
	// 只有管理员身份运行的应用程序能获得该命名空间下的内核对象
	if (!AddSIDToBoundaryDescriptor(&g_hBoundary, pLocalAdminSID))
	{
		AddText(TEXT("添加安全描述符到边界描述符失败: %u\r\n"), GetLastError());
		return;
	}

	// 为本地管理员创建命名空间
	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("安全描述符创建失败: %u\r\n"),  GetLastError());
		return;
	}

	g_hNamespace = CreatePrivateNamespace(&sa, g_hBoundary, g_szNamespace);

	LocalFree(sa.lpSecurityDescriptor);

	// 检查私有命名空间创建是否成功
	DWORD dwLastError = GetLastError();

	// 创建失败
	if (g_hNamespace == NULL)
	{
		// 如果被拒绝访问,则直接返回
		// 这段代码必须在本地管理员账户运行
		if (dwLastError == ERROR_ACCESS_DENIED)
		{
			AddText(TEXT("创建命名空间时访问被拒绝.\r\n"));
			AddText(TEXT("	必须以管理员身份运行。\r\n\r\n"));
			return;
		}
		else
		{
			// 如果在该命名空间另一个实例已经被创建
			if (dwLastError == ERROR_ALREADY_EXISTS)
			{
				AddText(TEXT("创建私有命名空间失败: %u\r\n"), dwLastError);
				g_hNamespace = OpenPrivateNamespace(g_hBoundary, g_szNamespace);
				if (g_hNamespace == NULL)
				{
					AddText(TEXT("	并且打开私有命名空间失败: %u\r\n"), dwLastError);
					return;
				}
				else
				{
					g_bNamespaceOpened = TRUE;
					AddText(TEXT("	但是打开私有命名空间成功\r\n\r\n"));
				}
			}
			else
			{
				AddText(TEXT("发生了未知的错误: %u\r\n\r\n"), dwLastError);
				return;
			}
		}
	}

	// 尝试创建命名互斥量对象
	TCHAR szMutexName[64];
	StringCchPrintf(szMutexName, _countof(szMutexName), TEXT("%s\\%s"),
		g_szNamespace, TEXT("单一实例"));

	g_hSingleton = CreateMutex(NULL, FALSE, szMutexName);
	if (GetLastError() == ERROR_ALREADY_EXISTS)
	{
		AddText(TEXT("单一实例应用程序另一个实例已经运行:\r\n"));
		AddText(TEXT("--> 不能访问应用程序功能.\r\n"));
	}
	else
	{
		AddText(TEXT("单一实例应用程序的第一个实例\r\n"));
		AddText(TEXT("--> 现在访问应用程序功能\r\n"));
	}
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: