首页 > 系统相关 >PropertySheet Shell Extension AppWizard

PropertySheet Shell Extension AppWizard

时间:2022-12-13 14:25:36浏览次数:76  
标签:Shell dtControl PropertySheet pPage IDC file st property AppWizard

PropertySheet Shell Extension AppWizard

 

This article aims at making implementation of a property sheet shell extension easier. It follows my first article dealing with context menu shell extension and was inspired by Michael Dunn's most excellent series of tutorials about writing shell extensions. I strongly encourage you to read through it in order to have a good understanding of what follows.

This time, we will tackle a solution to implementing a property sheet shell extension. We will reuse material found on my previous article and add a few lines of code. All this is packaged in a neat PropertySheet Shell Extension AppWizard.

Installing and running the Wizard

The Property Sheet Shell Extension Wizard comes in a self-contained propsheetapp.awx file that needs to be copied in your template folder. The template folder can be found under your main Microsoft Visual Studio installation folder, under the \Common\MSDev98\Template folder.

The wizard is activated by using the File|New menu item that triggers a New Projects dialog box.

 [VC New dialog - 3K]

Selecting the Property Sheet Shell Extension item brings the following wizard dialog box. This step allows to specify the type of files the shell extension will be registered against, as well as the C++ class name that will be generated by the wizard.

 [AppWizard dialog - 10K]

What does the Wizard give you?

The wizard produces a Visual Studio project similar to those created by the ATL/COM AppWizard. The main difference is that the project already contains a class implementing the skeleton of a property sheet shell extension.

Recall from Michael Dunn's tutorial that a property sheet shell extension is a COM object that should implement the IShellExtInit and IShellPropSheetExt interfaces. The class generated by the wizard already provides all that is required to support these implementations in the form of one header file atlshellex.h that is identical to the one used in my previous article, albeit updated, and a few extra lines of code to flesh out the implementation of the IShellPropSheetExt interface.

The Wizard produces code that make use of the WTL extensions to ATL. These are really convenient and there is no obvious reason not to use them. These extensions simplify programming the property page itself and the dialog controls. A initial property page class has been generated by the wizard. It already knows how to react to WM_INITDIALOG and PSM_APPLY messages.

Let's start with a sample

Let's attempt to write a shell extension similar to the one described in the tutorial. It's not as easy this time, because a property sheet is somewhat complicated and you'll have to do most of the work yourself. However, all the grunge work to actually create and display the property page is already generated by the wizard.

From the screen shot above, notice that we choose to hook our shell extension to .TXT files, just like Michael's. Notice also that the class in which the extension will be implemented in our example is called CShellExt.

If you look at the implementation of the AddPages() method in CShellExt, you will see those lines:

 
STDMETHODIMP CShellExt::AddPages(LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam)
{
	CSamplePropPage* m_pPage;

	m_pPage = new CSamplePropPage;
	m_pPage->SetTitle(_T("Sample"));
	m_pPage->SetFile(m_files[0]);

	HPROPSHEETPAGE hPage = m_pPage->Create();
	if (!lpfnAddPage(hPage, lParam)) delete m_pPage;
	return S_OK;
}

This code, generated by the wizard, actually creates an instance of a property page and assigns it a dummy title based on your project name. It also passes the name of the first selected file to the property sheet, and calls the shell's callback function that performs page addition to the property sheet. Please, notice that the property page class name is synthesized based upon your project name, in our case, the project is Sample, hence the CSamplePropPage class.

If we need to add more pages, like Michael is doing in his example, that's the place to put them. I won't do that for my example here. Suffice it to say that you just need to iterate over the m_files array and create additional instances of the property page for each of them.

Suprisingly enough, the WTL implementation of property pages doesn't provide a way to set the small icon in the property page tab. So we will need to add it ourselves. Besides, we would like the filename to be displayed in the tab as well. The changes needed are outlined below:

 
<FONT COLOR="red">#include </FONT><FONT COLOR="red">"shlwapi.h"</FONT>
...
STDMETHODIMP CShellExt::AddPages(LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam)
{
	CSamplePropPage* m_pPage;
	m_pPage = new CSamplePropPage;

	<FONT COLOR="red">// Add a small icon (assuming a resource identifier IDI_ICON)</FONT><FONT
COLOR="red">
	m_pPage->m_psp.pszIcon = MAKEINTRESOURCE(IDI_ICON);
	m_pPage->m_psp.dwFlags |= PSP_USEICONID;</FONT>

	<FONT COLOR="red">// Use the file name as the title</FONT><FONT COLOR="red">
	TCHAR szFile[_MAX_FNAME];
	lstrcpy(szFile, m_files[</FONT><FONT COLOR="red">0</FONT><FONT COLOR="red">]);
	::PathStripPath(szFile);</FONT>	

	m_pPage->SetTitle(<FONT COLOR="red">szFile</FONT>);
	m_pPage->SetFile(m_files[0]);

	HPROPSHEETPAGE hPage = m_pPage->Create();
	if (!lpfnAddPage(hPage, lParam)) delete m_pPage;
	return S_OK;
}

Be sure to add shlwapi.lib to the list of libraries in your project settings.

Now that we have the basics of our property sheet up and running, we need to add more interesting features to the CSamplePropPage class. We will add five Date and Time Picker controls to our dialog template in order to display the various date and times, and an extra static control to display the complete file path.

 [Property page dlg - 3K]

To make our life simpler, we will make use of the SetCombinedDatetime() and GetCombinedDateTime() helper functions which, respectively set and get the date and time portions from a couple of Date and Time Picker controls. The code for these functions is adapted from Michael's project:

 
void GetCombinedDateTime ( HWND hwnd, UINT idcDatePicker, UINT idcTimePicker,
                           FILETIME* pFiletime )
{
	SYSTEMTIME st = {0}, stDate = {0}, stTime = {0};
	FILETIME   ftLocal;

	CDateTimePickerCtrl dtControl;
	dtControl.Attach(::GetDlgItem(hwnd, idcDatePicker));
	dtControl.GetSystemTime(&stDate);

	if (idcTimePicker != 0) {
		dtControl.Attach(::GetDlgItem(hwnd, idcTimePicker));
		dtControl.GetSystemTime(&stTime);
	}

	st.wMonth  = stDate.wMonth;
	st.wDay    = stDate.wDay;
	st.wYear   = stDate.wYear;
	st.wHour   = stTime.wHour;
	st.wMinute = stTime.wMinute;
	st.wSecond = stTime.wSecond;

	::SystemTimeToFileTime (&st, &ftLocal);
	::LocalFileTimeToFileTime (&ftLocal, pFiletime);

	dtControl.Detach();
}
 
void SetCombinedDateTime ( HWND hwnd, UINT idcDatePicker, UINT idcTimePicker,
                           const FILETIME* pFiletime )
{
	SYSTEMTIME st;
	FILETIME   ftLocal;

	::FileTimeToLocalFileTime (pFiletime, &ftLocal);
	::FileTimeToSystemTime (&ftLocal, &st);

	CDateTimePickerCtrl dtControl;
	dtControl.Attach(::GetDlgItem(hwnd, idcDatePicker));
	dtControl.SetSystemTime(GDT_VALID, &st);

	if (idcTimePicker != 0) {
		dtControl.Attach(::GetDlgItem(hwnd, idcTimePicker));
		dtControl.SetSystemTime(GDT_VALID, &st);
	}

	dtControl.Detach();
}

The code to update these controls is pretty standard WTL control programming and happens in the OnInitDialog() function. This function was generated by the Wizard, so here are the lines you need to add:

 
LRESULT CSamplePropPage::OnInitDialog(HWND /*hWnd*/, LPARAM /*lParam*/)
{
	// Display the full path
	CStatic sPath;
	sPath.Attach(::GetDlgItem(m_hWnd, IDC_FILE));
	sPath.SetWindowText(m_file);
	sPath.Detach();

	// Get the file dates and times

	FILETIME creationTime;
	FILETIME accessTime;
	FILETIME modificationTime;

	HANDLE hFile;

	hFile = ::CreateFile(m_file, GENERIC_READ,
					FILE_SHARE_READ, 0,
					OPEN_EXISTING, 0, 0);
	ATLASSERT(hFile != INVALID_HANDLE_VALUE);

	::GetFileTime(hFile, &creationTime, &accessTime, &modificationTime);
	::CloseHandle(hFile);

	// Display the creation/modification/access date and time

	SetCombinedDateTime(m_hWnd, IDC_CREATIONDATE, IDC_CREATIONTIME, &creationTime);
	SetCombinedDateTime(m_hWnd, IDC_MODIFICATIONDATE, IDC_MODIFICATIONTIME, &modificationTime);
	SetCombinedDateTime(m_hWnd, IDC_ACCESSDATE, 0, &accessTime);

	return 0L;
}

To enable the Apply button, we need to capture the notifications sent from the Date and Time Picker controls. These send a DTN_DATETIMECHANGE notification to the property sheet. We just need to add a macro to our message map and a corresponding message handler in the class to get the job done. Notice that since we are using WTL, I use the _EX versions of the message map macros which perform message cracking, but you can always use the one supplied with ATL if you prefer.

 

 
class CSamplePropPage : public CPropertyPageImpl<CSamplePropPage>
{
...
	LRESULT OnDateTimeChanged(LPNMHDR lpnmhdr);
...
// Message map
public:
BEGIN_MSG_MAP_EX(CSamplePropPage)
	CHAIN_MSG_MAP(CPropertyPageImpll<CSamplePropPage>)
	MSG_WM_INITDIALOG(OnInitDialog)
	<FONT COLOR="red">NOTIFY_RANGE_CODE_HANDLER_EX(IDC_CREATIONDATE, IDC_ACCESSDATE, DTN_DATETIMECHANGE, OnDateTimeChanged)</FONT>
END_MSG_MAP()
};

I'm assuming that the resource identifiers of the Date and Time Picker controls are sequential, so that I can use the range handler to route notifications from all these controls to one single message handler. The implementation of the OnDateTimeChanged() function is straightforward. Just enable the Apply button...

 
LRESULT CSamplePropPage::OnDateTimeChanged(LPNMHDR /*lpnmhdr*/)
{
	SetModified(TRUE);
	return 0L;
}

Hitting the Apply button will now trigger the OnApply() function, that was generated by the Wizard. This is an overridden function that gets called whenever the user hits the OK or Apply button. We need to apply the date and time modifications that were made back to the file.

 
BOOL CSamplePropPage::OnApply(void)
{
	FILETIME creationTime;
	FILETIME accessTime;
	FILETIME modificationTime;

	// Get the new creation/modification/access date and time

	GetCombinedDateTime(m_hWnd, IDC_CREATIONDATE, IDC_CREATIONTIME, &creationTime);
	GetCombinedDateTime(m_hWnd, IDC_MODIFICATIONDATE, IDC_MODIFICATIONTIME, &modificationTime);
	GetCombinedDateTime(m_hWnd, IDC_ACCESSDATE, 0, &accessTime);

	// Set the file dates and times
	HANDLE hFile;

	hFile = ::CreateFile(m_file, GENERIC_WRITE,
					0, 0, OPEN_EXISTING,
					FILE_ATTRIBUTE_NORMAL, 0);
	ATLASSERT(hFile != INVALID_HANDLE_VALUE);

	::SetFileTime(hFile, &creationTime, &accessTime, &modificationTime);
	::CloseHandle(hFile);

	return TRUE;
}

That's it! The project is now complete.

Conclusion

As you have seen, implementing a context menu extension is now faster and easier. Besides, you can reuse the provided atlshellex.h files in your own projects. This file, atlshellex.h implements the IShellExtInit interface in a way that is also directly relevant to implementing Context Menu Shell Extension as outlined in my previous article.

I hope this article is clear enough. Please let me know if you have some trouble.

标签:Shell,dtControl,PropertySheet,pPage,IDC,file,st,property,AppWizard
From: https://www.cnblogs.com/qzxff/p/16978625.html

相关文章

  • 【转载】shell格式化打印
    转载自shell格式化打印......
  • 【Shell文本三剑客--awk】
    awk简介awk是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入(stdin)、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达......
  • 【Shell文本三剑客--sed,grep】
    一、sed简介sed是streameditor的缩写,流编辑器,主要用于对标准输出或文件进行逐行处理。二、语法语法格式stdout|sed[option]"patterncommand"#对|前面输出的内......
  • 【Linux】PHP 执行 shell脚本
    需要去除禁用的函数 去php.ini 查询php是哪个用户执行的psaux|grepphp  需要配置执行php的用户权限vi/etc/sudoers##Allowroottorunanycommandsanywhereroo......
  • Shell数组基本概述
    1.数组基本概述01.什么是数组?数组其实也算是变量,传统的变量只能存储一个值,但数组可以存储多个值。02.数组的分类Shell数组分为普通数组和关联数组。普通数组:只能使......
  • android开发adb shell ps无法列出进程列表的解决方法
    问题:C:\WINDOWS\System32>adbshellpsUSERPIDPPIDVSZRSSWCHANADDRSNAMEshell168172271213345633360......
  • S02.shell图形化编程
    whiptail使用消息框语法:whiptail--title"<messageboxtitle>"--msgbox"<texttoshow>"<height><width>示例:#!/bin/bash#--title:表示指定标题内容#--msgbox:......
  • 基本shell命令
    浏览文件系统cd命令cd./进入下一级目录cd../进入上一级目录cd/+绝对路径文件和目录列表ls命令-F 区分文件和目录目录名后加/-a 将以.开头的文件显......
  • Shell 起停脚本 专题
     Tolistanyprocesslisteningtotheport8080:lsof-i:8080Tokillanyprocesslisteningtotheport8080:kill$(lsof-t-i:8080)ormoreviolently:kill-9$(l......
  • 【Shell脚本(三) -- echo及printf输出】
    一、Shellecho命令Shell的echo指令用于字符串的输出。命令格式:echostring1.显示普通字符串:echo"Itisatest"echoItisatest加不加引号效果一样2.显示转义字符如......