From 92b23186aebd3e54e52a51bb5ed98d79c56ce8a2 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Fri, 23 Feb 2001 01:12:26 +0000 Subject: [PATCH] A first stab at implementing the RunDll features. --- dlls/shell32/Makefile.in | 1 + dlls/shell32/control.c | 386 ++++++++++++++++++++++++++++++++++++ dlls/shell32/iconcache.c | 2 +- dlls/shell32/shell32.spec | 10 +- dlls/shell32/shell32_main.c | 14 -- dlls/shell32/shellord.c | 52 +++-- include/Makefile.in | 1 + include/cpl.h | 71 +++++++ include/winuser.h | 4 - 9 files changed, 501 insertions(+), 40 deletions(-) create mode 100644 dlls/shell32/control.c create mode 100644 include/cpl.h diff --git a/dlls/shell32/Makefile.in b/dlls/shell32/Makefile.in index ef80323de4d..b2627e665b9 100644 --- a/dlls/shell32/Makefile.in +++ b/dlls/shell32/Makefile.in @@ -14,6 +14,7 @@ C_SRCS = \ changenotify.c \ classes.c \ clipboard.c \ + control.c \ dataobject.c \ dialogs.c \ enumidlist.c \ diff --git a/dlls/shell32/control.c b/dlls/shell32/control.c new file mode 100644 index 00000000000..fbcf2f75bdb --- /dev/null +++ b/dlls/shell32/control.c @@ -0,0 +1,386 @@ +/* Control Panel management */ +/* Eric Pouech 2001 */ + +#include +#include +#include +#include + +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "debugtools.h" +#include "cpl.h" + +DEFAULT_DEBUG_CHANNEL(shlctrl); + +typedef struct CPlApplet { + struct CPlApplet* next; /* linked list */ + HWND hWnd; + unsigned count; /* number of subprograms */ + HMODULE hModule; /* module of loaded applet */ + APPLET_PROC proc; /* entry point address */ + NEWCPLINFOA info[1]; /* array of count information. + * dwSize field is 0 if entry is invalid */ +} CPlApplet; + +typedef struct CPanel { + CPlApplet* first; /* linked list */ + HWND hWnd; + unsigned status; + CPlApplet* clkApplet; + unsigned clkSP; +} CPanel; + +static CPlApplet* Control_UnloadApplet(CPlApplet* applet) +{ + unsigned i; + CPlApplet* next; + + for (i = 0; i < applet->count; i++) { + if (!applet->info[i].dwSize) continue; + applet->proc(applet->hWnd, CPL_STOP, i, applet->info[i].lData); + } + if (applet->proc) applet->proc(applet->hWnd, CPL_EXIT, 0L, 0L); + FreeLibrary(applet->hModule); + next = applet->next; + HeapFree(GetProcessHeap(), 0, applet); + return next; +} + +static CPlApplet* Control_LoadApplet(HWND hWnd, LPCSTR cmd, CPanel* panel) +{ + CPlApplet* applet; + unsigned i; + CPLINFO info; + + if (!(applet = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*applet)))) + return applet; + + applet->hWnd = hWnd; + + if (!(applet->hModule = LoadLibraryA(cmd))) { + WARN("Cannot load control panel applet %s\n", cmd); + goto theError; + } + if (!(applet->proc = (APPLET_PROC)GetProcAddress(applet->hModule, "CPlApplet"))) { + WARN("Not a valid control panel applet %s\n", cmd); + goto theError; + } + if (!applet->proc(hWnd, CPL_INIT, 0L, 0L)) { + WARN("Init of applet has failed\n"); + goto theError; + } + if ((applet->count = applet->proc(hWnd, CPL_GETCOUNT, 0L, 0L)) == 0) { + WARN("No subprogram in applet\n"); + goto theError; + } + + applet = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, applet, + sizeof(*applet) + (applet->count - 1) * sizeof(NEWCPLINFOA)); + + for (i = 0; i < applet->count; i++) { + applet->info[i].dwSize = sizeof(NEWCPLINFOA); + /* proc is supposed to return a null value upon success for + * CPL_INQUIRE and CPL_NEWINQUIRE + * However, real drivers don't seem to behave like this + * So, use introspection rather than return value + */ + applet->proc(hWnd, CPL_NEWINQUIRE, i, (LPARAM)&applet->info[i]); + if (applet->info[i].hIcon == 0) { + applet->proc(hWnd, CPL_INQUIRE, i, (LPARAM)&info); + if (info.idIcon == 0 || info.idName == 0) { + WARN("Couldn't get info from sp %u\n", i); + applet->info[i].dwSize = 0; + } else { + /* convert the old data into the new structure */ + applet->info[i].dwFlags = 0; + applet->info[i].dwHelpContext = 0; + applet->info[i].lData = info.lData; + applet->info[i].hIcon = LoadIconA(applet->hModule, + MAKEINTRESOURCEA(info.idIcon)); + LoadStringA(applet->hModule, info.idName, + applet->info[i].szName, sizeof(applet->info[i].szName)); + LoadStringA(applet->hModule, info.idInfo, + applet->info[i].szInfo, sizeof(applet->info[i].szInfo)); + applet->info[i].szHelpFile[0] = '\0'; + } + } + } + + applet->next = panel->first; + panel->first = applet; + + return applet; + + theError: + Control_UnloadApplet(applet); + return NULL; +} + +static void Control_WndProc_Create(HWND hWnd, const CREATESTRUCTA* cs) +{ + CPanel* panel = (CPanel*)cs->lpCreateParams; + + SetWindowLongA(hWnd, 0, (LPARAM)panel); + panel->status = 0; + panel->hWnd = hWnd; +} + +#define XICON 32 +#define XSTEP 128 +#define YICON 32 +#define YSTEP 64 + +static BOOL Control_Localize(const CPanel* panel, unsigned cx, unsigned cy, + CPlApplet** papplet, unsigned* psp) +{ + unsigned i, x = (XSTEP-XICON)/2, y = 0; + CPlApplet* applet; + RECT rc; + + GetClientRect(panel->hWnd, &rc); + for (applet = panel->first; applet; applet = applet = applet->next) { + for (i = 0; i < applet->count; i++) { + if (!applet->info[i].dwSize) continue; + if (x + XSTEP >= rc.right - rc.left) { + x = (XSTEP-XICON)/2; + y += YSTEP; + } + if (cx >= x && cx < x + XICON && cy >= y && cy < y + YSTEP) { + *papplet = applet; + *psp = i; + return TRUE; + } + x += XSTEP; + } + } + return FALSE; +} + +static LRESULT Control_WndProc_Paint(const CPanel* panel, WPARAM wParam) +{ + HDC hdc; + PAINTSTRUCT ps; + RECT rc, txtRect; + unsigned i, x = 0, y = 0; + CPlApplet* applet; + HGDIOBJ hOldFont; + + hdc = (wParam) ? (HDC)wParam : BeginPaint(panel->hWnd, &ps); + hOldFont = SelectObject(hdc, GetStockObject(ANSI_VAR_FONT)); + GetClientRect(panel->hWnd, &rc); + for (applet = panel->first; applet; applet = applet = applet->next) { + for (i = 0; i < applet->count; i++) { + if (x + XSTEP >= rc.right - rc.left) { + x = 0; + y += YSTEP; + } + if (!applet->info[i].dwSize) continue; + DrawIcon(hdc, x + (XSTEP-XICON)/2, y, applet->info[i].hIcon); + txtRect.left = x; + txtRect.right = x + XSTEP; + txtRect.top = y + YICON; + txtRect.bottom = y + YSTEP; + DrawTextA(hdc, applet->info[i].szName, -1, &txtRect, + DT_CENTER | DT_VCENTER); + x += XSTEP; + } + } + SelectObject(hdc, hOldFont); + if (!wParam) EndPaint(panel->hWnd, &ps); + return 0; +} + +static LRESULT Control_WndProc_LButton(CPanel* panel, LPARAM lParam, BOOL up) +{ + unsigned i; + CPlApplet* applet; + + if (Control_Localize(panel, LOWORD(lParam), HIWORD(lParam), &applet, &i)) { + if (up) { + if (panel->clkApplet == applet && panel->clkSP == i) { + applet->proc(applet->hWnd, CPL_DBLCLK, i, applet->info[i].lData); + } + } else { + panel->clkApplet = applet; + panel->clkSP = i; + } + } + return 0; +} + +static LRESULT WINAPI Control_WndProc(HWND hWnd, UINT wMsg, + WPARAM lParam1, LPARAM lParam2) +{ + CPanel* panel = (CPanel*)GetWindowLongA(hWnd, 0); + + if (panel || wMsg == WM_CREATE) { + switch (wMsg) { + case WM_CREATE: + Control_WndProc_Create(hWnd, (CREATESTRUCTA*)lParam2); + return 0; + case WM_DESTROY: + while ((panel->first = Control_UnloadApplet(panel->first))); + break; + case WM_PAINT: + return Control_WndProc_Paint(panel, lParam1); + case WM_LBUTTONUP: + return Control_WndProc_LButton(panel, lParam2, TRUE); + case WM_LBUTTONDOWN: + return Control_WndProc_LButton(panel, lParam2, FALSE); +/* EPP case WM_COMMAND: */ +/* EPP return Control_WndProc_Command(mwi, lParam1, lParam2); */ + } + } + + return DefWindowProcA(hWnd, wMsg, lParam1, lParam2); +} + +static void Control_DoInterface(CPanel* panel, HWND hWnd, HINSTANCE hInst) +{ + WNDCLASSA wc; + MSG msg; + + wc.style = CS_HREDRAW|CS_VREDRAW; + wc.lpfnWndProc = Control_WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = sizeof(CPlApplet*); + wc.hInstance = hInst; + wc.hIcon = 0; + wc.hCursor = 0; + wc.hbrBackground = GetStockObject(WHITE_BRUSH); + wc.lpszMenuName = NULL; + wc.lpszClassName = "Shell_Control_WndClass"; + + if (!RegisterClassA(&wc)) return; + + CreateWindowExA(0, wc.lpszClassName, "Wine Control Panel", + WS_OVERLAPPEDWINDOW | WS_VISIBLE, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + hWnd, (HMENU)0, hInst, panel); + if (!panel->hWnd) return; + while (GetMessageA(&msg, panel->hWnd, 0, 0)) { + TranslateMessage(&msg); + DispatchMessageA(&msg); + if (!panel->first) break; + } +} + +static void Control_DoWindow(CPanel* panel, HWND hWnd, HINSTANCE hInst) +{ + HANDLE h; + WIN32_FIND_DATAA fd; + char buffer[MAX_PATH]; + + /* FIXME: should grab path somewhere from configuration */ + if ((h = FindFirstFileA("c:\\windows\\system\\*.cpl", &fd)) != 0) { + do { + sprintf(buffer, "c:\\windows\\system\\%s", fd.cFileName); + Control_LoadApplet(hWnd, buffer, panel); + } while (FindNextFileA(h, &fd)); + FindClose(h); + } + + if (panel->first) Control_DoInterface(panel, hWnd, hInst); +} + +static void Control_DoLaunch(CPanel* panel, HWND hWnd, LPCSTR cmd) + /* forms to parse: + * foo.cpl,@sp,str + * foo.cpl,@sp + * foo.cpl,,str + * foo.cpl @sp + * foo.cpl str + */ +{ + char* buffer; + char* beg = NULL; + char* end; + char ch; + unsigned sp = 0; + char* extraPmts = NULL; + + buffer = HeapAlloc(GetProcessHeap(), 0, strlen(cmd) + 1); + if (!buffer) return; + + end = strcpy(buffer, cmd); + + for (;;) { + ch = *end; + if (ch == ' ' || ch == ',' || ch == '\0') { + *end = '\0'; + if (beg) { + if (*beg == '@') { + sp = atoi(beg + 1); + } else if (*beg == '\0') { + sp = 0; + } else { + extraPmts = beg; + } + } + if (ch == '\0') break; + beg = end + 1; + if (ch == ' ') while (end[1] == ' ') end++; + } + end++; + } + Control_LoadApplet(hWnd, buffer, panel); + + if (panel->first) { + CPlApplet* applet = panel->first; + + assert(applet && applet->next == NULL); + if (sp >= applet->count) { + WARN("Out of bounds (%u >= %u), setting to 0\n", sp, applet->count); + sp = 0; + } + if (applet->info[sp].dwSize) { + if (!applet->proc(applet->hWnd, CPL_STARTWPARMSA, sp, (LPARAM)extraPmts)) + applet->proc(applet->hWnd, CPL_DBLCLK, sp, applet->info[sp].lData); + } + Control_UnloadApplet(applet); + } + HeapFree(GetProcessHeap(), 0, buffer); +} + +/************************************************************************* + * Control_RunDLL [SHELL32.12] + * + */ +void WINAPI Control_RunDLL(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow) +{ + CPanel panel; + + TRACE("(0x%08x, 0x%08lx, %s, 0x%08lx)\n", + hWnd, (DWORD)hInst, debugstr_a(cmd), nCmdShow); + + memset(&panel, 0, sizeof(panel)); + + if (!cmd || !*cmd) { + Control_DoWindow(&panel, hWnd, hInst); + } else { + Control_DoLaunch(&panel, hWnd, cmd); + } +} + +/************************************************************************* + * Control_FillCache_RunDLL [SHELL32.8] + * + */ +HRESULT WINAPI Control_FillCache_RunDLL(HWND hWnd, HANDLE hModule, DWORD w, DWORD x) +{ + FIXME("0x%04x 0x%04x 0x%04lx 0x%04lx stub\n",hWnd, hModule, w, x); + return 0; +} + +/************************************************************************* + * RunDLL_CallEntry16 [SHELL32.122] + * the name is propably wrong + */ +HRESULT WINAPI RunDLL_CallEntry16(DWORD v, DWORD w, DWORD x, DWORD y, DWORD z) +{ + FIXME("0x%04lx 0x%04lx 0x%04lx 0x%04lx 0x%04lx stub\n",v,w,x,y,z); + return 0; +} diff --git a/dlls/shell32/iconcache.c b/dlls/shell32/iconcache.c index 68f8c1b541d..1658ea52995 100644 --- a/dlls/shell32/iconcache.c +++ b/dlls/shell32/iconcache.c @@ -157,7 +157,7 @@ INT SIC_GetIconIndex (LPCSTR sSourceFile, INT dwSourceIndex ) return ret; } /**************************************************************************** - * SIC_LoadIcon [internal] + * SIC_GetIcon [internal] * * NOTES * retrives the specified icon from the iconcache. if not found try's to load the icon diff --git a/dlls/shell32/shell32.spec b/dlls/shell32/shell32.spec index c8bb63b4c2d..5f5346c5c1c 100644 --- a/dlls/shell32/shell32.spec +++ b/dlls/shell32/shell32.spec @@ -14,7 +14,7 @@ import advapi32.dll import kernel32.dll import ntdll.dll -debug_channels (exec pidl shell) +debug_channels (exec pidl shell shlctrl) # Functions exported by the Win95 shell32.dll # (these need to have these exact ordinals, for some @@ -172,10 +172,10 @@ debug_channels (exec pidl shell) 164 stdcall Win32DeleteFile(str) Win32DeleteFile 165 stdcall SHCreateDirectory(long long) SHCreateDirectory 166 stub CallCPLEntry16 - 167 stub SHAddFromPropSheetExtArray - 168 stub SHCreatePropSheetExtArray - 169 stub SHDestroyPropSheetExtArray - 170 stub SHReplaceFromPropSheetExtArray + 167 stdcall SHAddFromPropSheetExtArray(long long long) SHAddFromPropSheetExtArray + 168 stdcall SHCreatePropSheetExtArray(long str long) SHCreatePropSheetExtArray + 169 stdcall SHDestroyPropSheetExtArray(long) SHDestroyPropSheetExtArray + 170 stdcall SHReplaceFromPropSheetExtArray(long long long long) SHReplaceFromPropSheetExtArray 171 stdcall PathCleanupSpec(ptr ptr) PathCleanupSpecAW 172 stub SHCreateLinks 173 stdcall SHValidateUNC(long long long)SHValidateUNC diff --git a/dlls/shell32/shell32_main.c b/dlls/shell32/shell32_main.c index 3cfe8b64cb3..3147badd03c 100644 --- a/dlls/shell32/shell32_main.c +++ b/dlls/shell32/shell32_main.c @@ -76,20 +76,6 @@ LPWSTR* WINAPI CommandLineToArgvW(LPWSTR cmdline,LPDWORD numargs) return argv; } -/************************************************************************* - * Control_RunDLL [SHELL32.12] - * - * Wild speculation in the following! - * - * http://premium.microsoft.com/msdn/library/techart/msdn193.htm - */ - -void WINAPI Control_RunDLL( HWND hwnd, LPCVOID code, LPCSTR cmd, DWORD arg4 ) -{ - FIXME("(0x%08x, %p, %s, 0x%08lx): stub\n", hwnd, code, - debugstr_a(cmd), arg4); -} - /************************************************************************* * SHGetFileInfoA [SHELL32.@] * diff --git a/dlls/shell32/shellord.c b/dlls/shell32/shellord.c index 458752044cb..a14c6e570bb 100644 --- a/dlls/shell32/shellord.c +++ b/dlls/shell32/shellord.c @@ -881,22 +881,6 @@ BOOL WINAPI SHWaitForFileToOpen( FIXME("%p 0x%08lx 0x%08lx stub\n", pidl, dwFlags, dwTimeout); return 0; } -/************************************************************************* - * Control_FillCache_RunDLL [SHELL32.8] - * - */ -HRESULT WINAPI Control_FillCache_RunDLL(HWND hWnd, HANDLE hModule, DWORD w, DWORD x) -{ FIXME("0x%04x 0x%04x 0x%04lx 0x%04lx stub\n",hWnd, hModule,w,x); - return 0; -} -/************************************************************************* - * RunDLL_CallEntry16 [SHELL32.122] - * the name is propably wrong - */ -HRESULT WINAPI RunDLL_CallEntry16(DWORD v, DWORD w, DWORD x, DWORD y, DWORD z) -{ FIXME("0x%04lx 0x%04lx 0x%04lx 0x%04lx 0x%04lx stub\n",v,w,x,y,z); - return 0; -} /************************************************************************ * shell32_654 [SHELL32.654] @@ -983,3 +967,39 @@ DWORD WINAPI SHELL32_714(LPVOID x) FIXME("(%s)stub\n", debugstr_w(x)); return 0; } + +/************************************************************************* + * SHAddFromPropSheetExtArray [SHELL32] + */ +DWORD WINAPI SHAddFromPropSheetExtArray(DWORD a, DWORD b, DWORD c) +{ + FIXME("(%08lx,%08lx,%08lx)stub\n", a, b, c); + return 0; +} + +/************************************************************************* + * SHCreatePropSheetExtArray [SHELL32] + */ +DWORD WINAPI SHCreatePropSheetExtArray(DWORD a, LPCSTR b, DWORD c) +{ + FIXME("(%08lx,%s,%08lx)stub\n", a, debugstr_a(b), c); + return 0; +} + +/************************************************************************* + * SHReplaceFromPropSheetExtArray [SHELL] + */ +DWORD WINAPI SHReplaceFromPropSheetExtArray(DWORD a, DWORD b, DWORD c, DWORD d) +{ + FIXME("(%08lx,%08lx,%08lx,%08lx)stub\n", a, b, c, d); + return 0; +} + +/************************************************************************* + * SHDestroyPropSheetExtArray [SHELL32] + */ +DWORD WINAPI SHDestroyPropSheetExtArray(DWORD a) +{ + FIXME("(%08lx)stub\n", a); + return 0; +} diff --git a/include/Makefile.in b/include/Makefile.in index 4fe7b4c396f..b4c4574df14 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -12,6 +12,7 @@ INSTALLED_INCLUDES = \ commctrl.h \ commdlg.h \ compobj.h \ + cpl.h \ d3d.h \ d3dcaps.h \ d3dtypes.h \ diff --git a/include/cpl.h b/include/cpl.h new file mode 100644 index 00000000000..c0ade8671ed --- /dev/null +++ b/include/cpl.h @@ -0,0 +1,71 @@ +/* Control panel definitions */ + +#ifndef _INC_CPL +#define _INC_CPL + +#include "pshpack1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define WM_CPL_LAUNCH (WM_USER+1000) +#define WM_CPL_LAUNCHED (WM_USER+1001) + +typedef LONG (APIENTRY *APPLET_PROC)(HWND hwndCpl, UINT msg, LPARAM lParam1, LPARAM lParam2); + +typedef struct tagCPLINFO { + int idIcon; + int idName; + int idInfo; + LONG lData; +} CPLINFO, *LPCPLINFO; + +typedef struct tagNEWCPLINFOA +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwHelpContext; + LONG lData; + HICON hIcon; + CHAR szName[32]; + CHAR szInfo[64]; + CHAR szHelpFile[128]; +} NEWCPLINFOA, *LPNEWCPLINFOA; + +typedef struct tagNEWCPLINFOW +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwHelpContext; + LONG lData; + HICON hIcon; + WCHAR szName[32]; + WCHAR szInfo[64]; + WCHAR szHelpFile[128]; +} NEWCPLINFOW, *LPNEWCPLINFOW; + +DECL_WINELIB_TYPE_AW(NEWCPLINFO) +DECL_WINELIB_TYPE_AW(LPNEWCPLINFO) + +#define CPL_DYNAMIC_RES 0 +#define CPL_INIT 1 +#define CPL_GETCOUNT 2 +#define CPL_INQUIRE 3 +#define CPL_SELECT 4 +#define CPL_DBLCLK 5 +#define CPL_STOP 6 +#define CPL_EXIT 7 +#define CPL_NEWINQUIRE 8 +#define CPL_STARTWPARMSA 9 +#define CPL_STARTWPARMSW 10 +#define CPL_STARTWPARMS WINELIB_NAME_AW(CPL_STARTWPARMS) +#define CPL_SETUP 200 + +#ifdef __cplusplus +} +#endif + +#include "poppack.h" + +#endif /* _INC_CPL */ diff --git a/include/winuser.h b/include/winuser.h index a7db639b995..500f12712c2 100644 --- a/include/winuser.h +++ b/include/winuser.h @@ -3083,10 +3083,6 @@ typedef struct #define DI_COMPAT 4 #define DI_DEFAULTSIZE 8 - /* misc messages */ -#define WM_CPL_LAUNCH (WM_USER + 1000) -#define WM_CPL_LAUNCHED (WM_USER + 1001) - /* WM_NOTIFYFORMAT commands and return values */ #define NFR_ANSI 1 #define NFR_UNICODE 2