Click here to Skip to main content
15,884,472 members
Articles / Programming Languages / C#

Enumerate and Host Control Panel Applets using C#.

Rate me:
Please Sign up or sign in to vote.
4.90/5 (18 votes)
15 Feb 200424 min read 98.9K   2.5K   56  
Demonstrates how to enumerate and host Windows Control Panel Applets using C# and unmanaged C++.
using System;
using System.Text;
using System.Drawing;
using System.Collections;
using System.Runtime.InteropServices;

namespace AppletEngine
{
	/// <summary>
	/// The standard Control Panel Applet Information structure
	/// </summary>
	[StructLayout(LayoutKind.Sequential)]
	public struct CPLINFO
	{
		/// <summary>
		/// The resource Id of the icon the applet wishes to display
		/// </summary>
		public int IconResourceId;

		/// <summary>
		/// The resource Id of the name the applet wishes to display
		/// </summary>
		public int NameResourceId;     

		/// <summary>
		/// The resource Id of the information the applet wishes to display (aka. Description)
		/// </summary>
		public int InformationResourceId;

		/// <summary>
		/// A pointer to applet defined data
		/// </summary>
		public IntPtr AppletDefinedData;    

		/// <summary>
		/// A simple override to display some debugging information about the resource ids returned from each applet
		/// </summary>
		/// <returns></returns>
		public override string ToString()
		{
			return string.Format("IconResourceId: {0}, NameResourceId: {1}, InformationResourceId: {2}, AppletDefinedData: {3}", IconResourceId.ToString(), NameResourceId.ToString(), InformationResourceId.ToString(), AppletDefinedData.ToInt32().ToString("X"));
		}
	}

	/// <summary>
	/// The advanced Control Panel Applet Information structure
	/// </summary>
	[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
	public struct NEWCPLINFO
	{
		/// <summary>
		/// The size of the NEWCPLINFO structure 
		/// </summary>
		public int Size;

		/// <summary>
		/// This field is unused
		/// </summary>
		public int Flags;

		/// <summary>
		/// This field is unused
		/// </summary>
		public int HelpContext;

		/// <summary>
		/// A pointer to applet defined data
		/// </summary>
		public IntPtr AppletDefinedData;

		/// <summary>
		/// A handle to an icon that the applet wishes to display
		/// </summary>
		public IntPtr hIcon;

		/// <summary>
		/// An array of chars that contains the name that the applet wishes to display
		/// </summary>
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]
		public string NameCharArray;

		/// <summary>
		/// An array of chars that contains the information that the applet wishes to display
		/// </summary>
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst=64)]
		public string InfoCharArray;

		/// <summary>
		/// An array of chars that contains the help file that the applet wishes to display for further help
		/// </summary>
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]
		public string HelpFileCharArray;
	}

	/// <summary>
	/// The Applet class exposes methods for displaying information about a single Control Panel Applet as well as opening and closing the applet. Some applets may not function properly without Windows Explorer (explorer.exe) running as the Windows Shell.
	/// </summary>
	public class Applet : DisposableObject
	{
		private Bitmap _smallImage;
		private Bitmap _largeImage;		
		private string _name = null;
		private string _description = null;
		private AppletLibrary _appletLibrary = null;
		private int _appletIndex = 0;
		private CPLINFO _info;
		private IntPtr _infoPtr;
		private NEWCPLINFO _dynInfo;
		private IntPtr _dynInfoPtr;
		public const int DynamicResource = 0;

		#region P/Invoke

		[DllImport("User32")]
		public static extern IntPtr GetDesktopWindow();

		[DllImport("User32")]
		public static extern int LoadString(IntPtr hLib, uint uID, StringBuilder sb, int sbSize);
		
		[DllImport("AppletProxy")]
		public static extern IntPtr LoadAppletIcon(IntPtr hLib, int resId);

		[DllImport("AppletProxy")]
		public static extern IntPtr LoadAppletImage(IntPtr hLib, int resId, int width, int height);

		#endregion

		#region DisposableObject Overrides

		public override void Dispose(bool disposing)
		{
			base.Dispose (disposing);

			if (disposing)
			{

			}
			
			if (!base.IsNullPtr(_infoPtr))
			{
				Marshal.FreeHGlobal(_infoPtr);
				_infoPtr = IntPtr.Zero;
			}

			if (!base.IsNullPtr(_dynInfoPtr))
			{
				Marshal.FreeHGlobal(_dynInfoPtr);
				_dynInfoPtr = IntPtr.Zero;
			}
		}

		#endregion

		/// <summary>
		/// Initializes a new instance of the Applet class
		/// </summary>
		/// <param name="appletLibrary">The AppletLibrary that contains this Applet</param>
		/// <param name="appletIndex">The index of the Applet in it's AppletLibrary</param>
		public Applet(AppletLibrary appletLibrary, int appletIndex)
		{
			_appletLibrary = appletLibrary;
			_appletIndex = appletIndex;
			this.Inquire();	
		}

		/// <summary>
		/// Inquires the information about the Applet, caches items such as Name, Description, and Icon.
		/// </summary>
		public void Inquire()
		{
			unsafe
			{
				_info = new CPLINFO();
				_infoPtr = Marshal.AllocHGlobal(sizeof(CPLINFO));
				Marshal.StructureToPtr(_info, _infoPtr, true);
				if (!base.IsNullPtr(_infoPtr))
				{
					_appletLibrary.CPlApplet(AppletMessages.Inquire, new IntPtr(_appletIndex), _infoPtr);
					_info = (CPLINFO)Marshal.PtrToStructure(_infoPtr, typeof(CPLINFO));
					
					if (!this.IsUsingDynamicResources)
					{
						this.ExtractNameFromResources();
						this.ExtractDescriptionFromResources();
						this.ExtractIconFromResources();
					}
					else
					{
						this.NewInquire();
					}
				}
			}
		}

		public void NewInquire()
		{
		//			unsafe
		//			{
				_dynInfo = new NEWCPLINFO();
				_dynInfo.Size = Marshal.SizeOf(_dynInfo); 
				_dynInfoPtr = Marshal.AllocHGlobal(_dynInfo.Size);
				Marshal.StructureToPtr(_dynInfo, _dynInfoPtr, true);
				if (!base.IsNullPtr(_dynInfoPtr))
				{
					_appletLibrary.CPlApplet(AppletMessages.NewInquire, new IntPtr(_appletIndex), _dynInfoPtr);
					_dynInfo = (NEWCPLINFO)Marshal.PtrToStructure(_dynInfoPtr, typeof(NEWCPLINFO));

					_smallImage = Bitmap.FromHicon(_dynInfo.hIcon);
					_largeImage = Bitmap.FromHicon(_dynInfo.hIcon);					
					_name = _dynInfo.NameCharArray.ToString();					
					_description = _dynInfo.InfoCharArray.ToString();
				}
		//			}
		}

		public bool IsUsingDynamicResources
		{
			get
			{
				return (_info.IconResourceId == DynamicResource || _info.NameResourceId == DynamicResource || _info.InformationResourceId == DynamicResource);
			}
		}

		

		private void ExtractNameFromResources()
		{
			try
			{
				int size = 260;
				StringBuilder sb = new StringBuilder(size);
				int length = LoadString(_appletLibrary.LibraryHandle, (uint)_info.NameResourceId, sb, size);
				if (length > 0)
				{
					_name = sb.ToString();
				}
			}
			catch(System.Exception systemException)
			{
				System.Diagnostics.Trace.WriteLine(systemException);
			}
		}

		private void ExtractDescriptionFromResources()
		{
			try
			{
				int size = 260;
				StringBuilder sb = new StringBuilder(size);
				int length = LoadString(_appletLibrary.LibraryHandle, (uint)_info.InformationResourceId, sb, size);
				if (length > 0)
				{
					_description = sb.ToString();
				}
			}
			catch(System.Exception systemException)
			{
				System.Diagnostics.Trace.WriteLine(systemException);
			}
		}

		private void ExtractIconFromResources()
		{
			try
			{				
				IntPtr hSmall = LoadAppletImage(_appletLibrary.LibraryHandle, _info.IconResourceId, 16, 16);
				IntPtr hLarge = LoadAppletImage(_appletLibrary.LibraryHandle, _info.IconResourceId, 32, 32);

				if (!base.IsNullPtr(hSmall))
				{
					_smallImage = Bitmap.FromHicon(hSmall);
				}

				if (!base.IsNullPtr(hLarge))
				{
					_largeImage = Bitmap.FromHicon(hLarge);
				}
			}
			catch(System.Exception systemException)
			{
				System.Diagnostics.Trace.WriteLine(systemException);
			}
		}

		public Bitmap SmallImage
		{
			get
			{
				return _smallImage;
			}
		}

		public Bitmap LargeImage
		{
			get
			{
				return _largeImage;
			}
		}

		/// <summary>
		/// Gets the Name to display for the Applet
		/// </summary>
		public string Name
		{
			get
			{
				return _name;
			}
		}

		/// <summary>
		/// Gets the Description to display for the Applet
		/// </summary>
		public string Description
		{
			get
			{
				return _description;
			}
		}

		/// <summary>
		/// Opens the Applet's configuration dialog
		/// </summary>
		public void Open()
		{
			IntPtr userData = (this.IsUsingDynamicResources ? _info.AppletDefinedData : _dynInfo.AppletDefinedData);
			int result = _appletLibrary.CPlApplet(AppletMessages.DoubleClick, new IntPtr(_appletIndex), userData);
			if (result != 0)
			{
				System.ComponentModel.Win32Exception e = new System.ComponentModel.Win32Exception();
				System.Diagnostics.Trace.WriteLine(e);
			}
		}

		/// <summary>
		/// Closes the Applet's configuration dialog
		/// </summary>
		public void Close()
		{
			IntPtr userData = (this.IsUsingDynamicResources ? _info.AppletDefinedData : _dynInfo.AppletDefinedData);
			_appletLibrary.CPlApplet(AppletMessages.Stop, new IntPtr(_appletIndex), userData);
		}

		public override string ToString()
		{
			return string.Format("Applet ({0}), Name: {1}, Description: {2}", System.IO.Path.GetFileName(_appletLibrary.Path), _name, _description);
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior)
United States United States
Senior Application Developer specializing in Windows desktop and network development.

Professional Experience
- B.S. of Computer Science (Graduated 2001 - PSU)
- Senior Application Developer (8+ yrs)
- Microsoft Certified Professional

Primary Interests
- C#, C++, HTML, Javascript
- XML, ASP.NET, Web Services, SOAP, UDDI
- Socket programming and anything network related
- Reflection, Serialization, and Plugin Frameworks
- Owner-drawn controls and GDI+ goodness

Comments and Discussions