Click here to Skip to main content
Click here to Skip to main content

Property Sheet Shell Extension in C#

, 21 Oct 2011
Rate this:
Please Sign up or sign in to vote.
A managed .NET user-control that implements Win32 (COM) property sheet shell extensions.

Introduction

According to the platform SDK: "OLE property pages enable an object to display its properties in a tabbed dialog box known as a property sheet. An end user can then view and change the object’s properties."

These property pages are used extensively in Windows. Examples are the tabs shown when viewing the properties of a file, or when viewing the properties of an object in Active Directory (or any other MMC in fact), or pages used in some Control Panel applets and wizards, etc.

By default, there is no support for creating these controls in the .NET Framework. Here, we present a user control that can be used for this purpose.

Sample Image

Background

When you select the properties of a file, Explorer looks up all the registered property pages to load for that file type in the Registry, and loads them. Equally, when you view the properties of a User in Active Directory, the MMC looks at the display-specifiers and calls all the extension pages. The technology that enables all this is COM. Traditionally, in Visual C++, you would use ATL for the COM server and the MFC CPropertyPage control for the interface. CPropertyPage is basically a CDialog (equivalent to a Form in .NET) that fills in a PROPSHEETPAGE structure.

Our goal was to write an Active Directory MMC extension in C#. This has many obvious benefits, but proved to be quite a tricky task. In this article, we will describe some of the main points involved, and present a user-control that wraps the tricky parts. It should be noted that our team has used this component successfully and commercially (including a similar control for Wizards), but our work is in no way complete, and improvements are highly welcome.

Using the Code

The sample project will add a tab-page to the properties of a .EXE file in Windows Explorer. To use the sample, just extract the program files and run INSTALL.BAT. To change the sample, you should do the following:

  1. Create an inherited user control, inheriting from SheetControl. (Sheet control is a base user control class, containing all code for handling TABs and the other messages.) Your control will be the property page that will be added. Design it according to your needs.
  2. The actual loading of the page happens in the SheetLoader class. You must generate a GUID for your pages, and also create a new instance of it in IShellPropSheetExt.AddPages(), as demonstrated in the sample.
  3. Finally, build the DLL, and register it according to the place it is intended to be used. In our sample, install.bat does this.

Points of Interest

There are actually quite a few tricks here!

  1. First of all, we have a COM server which inherits and exports the needed IShellPropSheetExt, IShellExtInit, and IDataObject interfaces. If you look up these COM interfaces, you will notice that marshaling has been used extensively in the definitions.
  2. After our COM is built and registered, when Win32 needs to show our property page, it will call IShellPropSheetExt.AddPages(). This is were we initialize our user-control, and ...
  3. We use a plain resource file (i.e., an empty Win32 dialog window) as a "placeholder" for our .NET Framework classes placed controls (i.e., the user control). This is how:
    1. The PROPSHEETPAGE and DLGTEMPLATE structures are filled minimally. (Again, marshaling is extensively used to keep the code safe.)
    2. Using the SetParent() API call, the hWND handle to the empty dialog is set as the parent of our user-control.
    3. We can design this user-control as needed. The reason we create and pass our form this way is that Win32 expects a dialog, and Windows Forms aren't dialogs.
  4. Setting the parent of a form to any unmanaged container except IE is officially unsupported! This causes some form events to break. For example, tab stops work almost randomly, and focus events don't get called. (I have tried adding another layer in between, but that didn't work either.) Any workaround or documentation that explains what is happening is appreciated.
  5. Our user-control contains its own message loop to handle WM_NOTIFY correctly.
  6. Our user-control, SheetControl, encapsulates all the needed logic. You should simply inherit, and visually design your page as usual.
  7. To have Win32 show the pages, a passed pointer function (lpfnAddPage) must be called. Unfortunately, a C++ pointer function can't be marshaled as a C# delegate - it will cause a runtime error. This means we can't call lpfnAddPage in managed code! A very small C++ wrapper does this for us.
  8. We are almost finished, except that as soon as AddPages() finishes, our form will be deleted by the Garbage Collector! This is because there are no active references to it. .KeepAlive() fixes this by fooling the garbage collector.
  9. Extending the wizards has similar concepts involved. You should be able to write the code for that yourself. Smile | :)

History

Our source is based on a Microsoft sample presented in PDC 2001, which was later removed from GOTDOTNET.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Hadi A
Web Developer
Netherlands Netherlands
No Biography provided

Comments and Discussions

 
QuestionA newer project from CodeProject PinmemberVincent DUVERNET (Nolmë Informatique)15-May-14 7:45 
QuestionWhere can i see that newly added sheet ? PinmemberMember 105703164-Feb-14 19:11 
GeneralTab stop order PinmemberSeth Dingwell17-Aug-10 10:23 
QuestionHow do I add functionality to get and save user attributes? Pinmembergilmore.adam25-Nov-09 7:43 
GeneralNo need for dwWrapper.dll PinmemberEric Garnier7-Oct-09 6:03 
GeneralRe: No need for dwWrapper.dll PinmemberPJonDevelopment16-Jan-10 12:48 
GeneralRe: No need for dwWrapper.dll PinmemberSeth Dingwell26-Jul-10 9:28 
Generalthis code is not working on 64 bit windows XP. Pinmembershreekruth27-Nov-08 16:35 
GeneralExample dont work PinmemberMember 43297745-Jun-08 14:50 
QuestionHow to access AD objects ? Pinmembermudshark20035-Oct-07 2:34 
QuestionShow AD-attributes on property sheet Pinmembermanulei5-Jun-07 3:41 
QuestionRe: Show AD-attributes on property sheet Pinmembersmyers18-Mar-08 4:45 
QuestionHow to find a name of a file? PinmemberVglaz12310-Mar-07 2:04 
AnswerRe: How to find a name of a file? PinmemberVglaz12310-Mar-07 9:41 
GeneralRe: How to find a name of a file? Pinmemberkesfaw28-Oct-08 15:15 
Questionshow property sheets from C# application Pinmemberkillers0721-Dec-06 14:11 
GeneralDo not write in-process shell extensions in managed code PinmemberSteveKing20-Dec-06 2:17 
GeneralRe: Do not write in-process shell extensions in managed code PinmemberRay Cassick15-Sep-07 19:55 
GeneralCurrent Object. PinmemberMichael Sync25-Sep-06 4:49 
GeneralOne Issue. PinmemberMichael Sync24-Sep-06 23:41 
GeneralRe: One Issue. PinmemberMichael Sync25-Sep-06 0:02 
GeneralAbout this project PinmemberHadi A13-Feb-06 13:05 
QuestionHow to add(register) as a Extended property sheet in C# & MMC 2.0? PinmemberAlpha Davis2-Feb-06 8:38 
GeneralAdding To AD User Properties Page Pinmemberjcairns1-Feb-06 11:01 
GeneralRe: Adding To AD User Properties Page PinmemberMichael Sync25-Sep-06 1:04 
GeneralHunt the filename Pinmembermat1t5-Dec-05 23:31 
GeneralRe: Hunt the filename Pinmemberformat133714-Jul-06 9:15 
GeneralRe: Hunt the filename Pinmembertomas_ruzicka11-Sep-06 23:04 
GeneralCOM registration problems Pinmembergxdata23-Jul-05 18:35 
GeneralADIComponent Code Pinmemberwkc0734069-Jun-05 5:48 
GeneralRe: ADIComponent Code Pinmemberwkc07340621-Jun-05 13:02 
QuestionRe: ADIComponent Code PinmemberJ.Liss23-Oct-06 17:26 
GeneralRe: ADIComponent Code Pinmembersmyers18-Mar-08 4:55 
QuestionRe: ADIComponent Code PinmemberLDawggie9-Nov-09 10:01 
GeneralDisplaying multiple PropertySheet Page Pinmemberm_rtk23-May-05 4:43 
QuestionRe: Displaying multiple PropertySheet Page PinmemberAlpha Davis6-Feb-06 8:00 
GeneralAdding a property sheet to an MMC plugin Pinmemberchuckles7775-May-05 13:07 
GeneralRe: Adding a property sheet to an MMC plugin Pinmemberchuckles7776-May-05 10:38 
AnswerRe: Adding a property sheet to an MMC plugin PinmemberTehTarget21-Mar-06 11:18 
GeneralRestriction to just your APP Pinmembernigelbogle8-Apr-05 1:53 
GeneralRe: Restriction to just your APP PinmemberHadi A8-Apr-05 21:35 
GeneralshellPropertyPages != adminPropertyPages Pinmemberandrew butson25-Jan-05 2:13 
GeneralRe: shellPropertyPages != adminPropertyPages PinmemberHadi A8-Apr-05 21:38 
GeneralApply button Pinmemberwooyek6-Oct-04 23:48 
GeneralRe: Apply button PinmemberHadi A7-Oct-04 21:50 
GeneralRe: Apply button PinsussAli Bashivan8-Oct-04 21:35 
GeneralRe: Apply button Pinmembersuryahg1-Sep-08 1:26 
GeneralSendMessage + PSM enum PinmemberLDawggie18-Nov-09 8:36 
GeneralSource Code. Pinmemberwooyek6-Oct-04 23:00 
GeneralRe: Source Code. PinmemberHadi A7-Oct-04 21:48 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140721.1 | Last Updated 21 Oct 2011
Article Copyright 2004 by Hadi A
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid