Skip to content

Instantly share code, notes, and snippets.

@armornick
Created April 12, 2016 18:43
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save armornick/9fa1e9790e353deb77a56192b0234e02 to your computer and use it in GitHub Desktop.
Save armornick/9fa1e9790e353deb77a56192b0234e02 to your computer and use it in GitHub Desktop.
List control panel applets and allow the user to open them
/*
List and load Control Panel applets
Based on this article:
https://blogs.msdn.microsoft.com/oldnewthing/archive/2003/12/26/45979.aspx
And this section of MSDN:
https://msdn.microsoft.com/en-us/library/windows/desktop/cc144185(v=vs.85).aspx
KNOWN BUGS:
- should call STOP once per applet at end and EXIT once for the applet library
*/
#define STRICT
#include <windows.h>
#include <windowsx.h>
#include <ole2.h>
#include <commctrl.h>
#include <shlwapi.h>
#include <cpl.h>
#include <string>
#include <vector>
#include <stdio.h>
#define IDC_LISTBOX 101
typedef std::basic_string<TCHAR> tstring;
struct ControlPanelApplet
{
tstring name;
int index;
// tstring filepath;
APPLET_PROC pfnCPlApplet;
CPLINFO cpli;
ACTCTX act;
HANDLE hctx;
ULONG_PTR ulCookie;
HINSTANCE hinstCPL;
};
class MyApplication
{
// ----------------------------------------------
// Public Methods
// ----------------------------------------------
public:
static const int padding = 20;
MyApplication(HINSTANCE);
~MyApplication();
// handle window message
LRESULT handleMessage(UINT uiMsg, WPARAM wParam, LPARAM lParam);
// run the main message loop
void run(int nShowCmd);
// ----------------------------------------------
// Private Methods
// ----------------------------------------------
private:
void registerClass();
void fatalError(LPCTSTR msg);
void createListBox();
void addListBoxItem(LPCTSTR item);
void loadApplets();
void loadApplet(LPCTSTR appletName);
void unloadApplets();
LPCTSTR className() { return TEXT("NiaApplicationWindow"); }
// Window event methods
void onResize(long request, int width, int height);
void onKeyUp(unsigned long keyCode);
void onCommand(long notification, long identifier, HWND control);
// ----------------------------------------------
// Instance Variables
// ----------------------------------------------
private:
std::vector<ControlPanelApplet> applets;
bool cleared;
HINSTANCE hinst;
HWND topWindow, listBox;
HFONT defaultFont;
};
// ----------------------------------------------
// Window Procedure
// ----------------------------------------------
LRESULT CALLBACK
WndProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
if (uiMsg == WM_CREATE)
{
CREATESTRUCT *lpCreateStruct = reinterpret_cast<CREATESTRUCT*>(lParam);
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(lpCreateStruct->lpCreateParams));
}
else
{
MyApplication *self = reinterpret_cast<MyApplication*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
if (self != NULL)
{
return self->handleMessage(uiMsg, wParam, lParam);
}
else
{
return DefWindowProc(hwnd, uiMsg, wParam, lParam);
}
}
}
// ----------------------------------------------
// Application Entry Point
// ----------------------------------------------
int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpCmdLine, int nShowCmd)
{
MyApplication app(hinst);
app.run(nShowCmd);
}
void MyApplication::fatalError(LPCTSTR msg)
{
MessageBox(topWindow, msg, TEXT("Fatal Error"), MB_OK|MB_ICONEXCLAMATION);
DestroyWindow(topWindow);
}
MyApplication::MyApplication(HINSTANCE hinst) : hinst(hinst), cleared(false)
{
registerClass();
INITCOMMONCONTROLSEX icc;
icc.dwSize = sizeof(INITCOMMONCONTROLSEX);
icc.dwICC = ICC_STANDARD_CLASSES;
InitCommonControlsEx(&icc);
NONCLIENTMETRICS metrics;
metrics.cbSize = sizeof(NONCLIENTMETRICS);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &metrics, 0);
defaultFont = ::CreateFontIndirect(&metrics.lfMessageFont);
topWindow = CreateWindow(
className(), TEXT("My Control Panel"), WS_OVERLAPPEDWINDOW,
// WS_POPUPWINDOW | WS_CAPTION ,
100, 100, 800, 600,
NULL, NULL, hinst, this
);
createListBox();
}
MyApplication::~MyApplication()
{
DeleteObject(defaultFont);
unloadApplets();
}
void MyApplication::unloadApplets()
{
printf("unloading applets\n");
for (std::vector<ControlPanelApplet>::iterator it = applets.begin();
it != applets.end();
++it)
{
it->pfnCPlApplet(topWindow, CPL_STOP, 0, it->cpli.lData);
it->pfnCPlApplet(topWindow, CPL_EXIT, 0, 0);
FreeLibrary(it->hinstCPL);
}
}
void MyApplication::registerClass()
{
WNDCLASS wc;
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hinst;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = className();
RegisterClass(&wc);
}
void MyApplication::createListBox()
{
RECT r;
GetClientRect(topWindow, &r);
listBox = CreateWindow(
WC_LISTBOX, NULL, WS_CHILD | WS_VISIBLE | LBS_NOTIFY,
padding, padding, r.right - padding, r.bottom - padding,
topWindow, (HMENU) IDC_LISTBOX, hinst, NULL
);
SendMessage(listBox, WM_SETFONT, reinterpret_cast<WPARAM>(defaultFont), MAKELPARAM(TRUE, 0));
loadApplets();
}
void MyApplication::addListBoxItem(LPCTSTR item)
{
SendMessage(listBox, LB_ADDSTRING, 0, reinterpret_cast<LPARAM>(item));
}
void MyApplication::loadApplets()
{
LONG ret;
HKEY cpls;
DWORD amountKeys, maxKeySize;
ret = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls"),
0, KEY_READ, &cpls
);
if (ret != ERROR_SUCCESS)
{
fatalError(TEXT("Could not load Cpls registry key"));
}
ret = RegQueryInfoKey(cpls, NULL, NULL, NULL, &amountKeys, &maxKeySize, NULL, NULL, NULL, NULL, NULL, NULL);
if (ret != ERROR_SUCCESS)
{
fatalError(TEXT("Could not query Cpls registry key"));
}
if (amountKeys)
{
DWORD keyBufsize = maxKeySize+1;
// printf("%d subkeys - max subkey length: %d\n", amountKeys, keyBufsize);
TCHAR keyBuff[keyBufsize];
for (int i = 0; i < amountKeys; i++)
{
keyBufsize = maxKeySize+1;
ret = RegEnumKeyEx(cpls, i, keyBuff, &keyBufsize, NULL, NULL, NULL, NULL);
if (ret == ERROR_SUCCESS)
{
// addListBoxItem(keyBuff);
loadApplet(keyBuff);
}
else
{
printf("error detected for subkey %d (error code: %d)\n", i, ret);
}
}
}
RegCloseKey(cpls);
}
void MyApplication::loadApplet(LPCTSTR appletName)
{
TCHAR szPath[MAX_PATH];
LPTSTR pszLast;
DWORD cch = SearchPath(NULL, appletName,
NULL, MAX_PATH, szPath, &pszLast);
if (cch < 0 && cch > MAX_PATH) {
return;
}
ControlPanelApplet applet;
// applet.filepath = szPath;
// applet.act = { 0 };
applet.act.cbSize = sizeof(applet.act);
applet.act.dwFlags = 0;
applet.act.lpSource = szPath;
applet.act.lpResourceName = MAKEINTRESOURCE(123);
applet.hctx = CreateActCtx(&applet.act);
if (applet.hctx == INVALID_HANDLE_VALUE || ActivateActCtx(applet.hctx, &applet.ulCookie))
{
applet.hinstCPL = LoadLibrary(szPath);
if (applet.hinstCPL)
{
applet.pfnCPlApplet = (APPLET_PROC) GetProcAddress(applet.hinstCPL, "CPlApplet");
if (applet.pfnCPlApplet)
{
int cApplets = applet.pfnCPlApplet(topWindow, CPL_GETCOUNT, 0, 0);
// printf("%d applet(s) detected\n", cApplets);
if (cApplets)
{
for (int i = 0; i < cApplets; i++)
{
TCHAR szAppletName[256];
applet.pfnCPlApplet(topWindow, CPL_INQUIRE, 0, (LPARAM)&applet.cpli);
LoadString(applet.hinstCPL, applet.cpli.idName, szAppletName, 256);
applet.index = i;
applet.name = szAppletName;
applets.push_back(applet);
addListBoxItem(applet.name.c_str());
}
}
}
else
{
FreeLibrary(applet.hinstCPL);
}
}
}
}
void MyApplication::run(int nShowCmd)
{
ShowWindow(topWindow, nShowCmd);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
LRESULT MyApplication::handleMessage(UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
switch(uiMsg)
{
case WM_SIZE: {
onResize(wParam, LOWORD(lParam), HIWORD(lParam));
return 0;
}
/*
case WM_CLOSE: {
// unloadApplets();
return DefWindowProc(topWindow, uiMsg, wParam, lParam);
}
*/
case WM_DESTROY: {
PostQuitMessage(0);
return 0;
}
case WM_KEYUP: {
onKeyUp(wParam);
return 0;
}
case WM_COMMAND: {
onCommand(HIWORD(wParam), LOWORD(wParam), reinterpret_cast<HWND>(lParam));
return 0;
}
default: {
return DefWindowProc(topWindow, uiMsg, wParam, lParam);
}
}
}
void MyApplication::onResize(long request, int width, int height)
{
RECT rc;
GetClientRect(topWindow, &rc);
// printf("width: %d, height: %d -- width: %d, height: %d\n", rc.right, rc.bottom, rc.right - padding, rc.bottom - padding);
SetWindowPos(listBox, NULL, 0, 0, rc.right - (padding*2), rc.bottom - (padding*2), SWP_NOMOVE | SWP_NOOWNERZORDER);
// SetWindowPos(listBox, NULL, 0, 0, 200, 200, SWP_NOMOVE | SWP_NOOWNERZORDER);
}
void MyApplication::onKeyUp(unsigned long keyCode)
{
if (keyCode == VK_ESCAPE)
{
DestroyWindow(topWindow);
}
}
void MyApplication::onCommand(long notification, long identifier, HWND control)
{
if (identifier == IDC_LISTBOX && notification == LBN_DBLCLK)
{
long selectedItem = SendMessage(listBox, LB_GETCURSEL, 0, 0);
if (selectedItem < applets.size())
{
ControlPanelApplet& applet = applets[selectedItem];
applet.pfnCPlApplet(topWindow, CPL_DBLCLK, 0, applet.cpli.lData);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment