Created
April 12, 2016 18:43
-
-
Save armornick/9fa1e9790e353deb77a56192b0234e02 to your computer and use it in GitHub Desktop.
List control panel applets and allow the user to open them
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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