reactos/dll/shellext/deskmon/deskmon.c

754 lines
21 KiB
C
Raw Normal View History

#include "precomp.h"
#include <tchar.h>
#define NDEBUG
#include <debug.h>
#include "resource.h"
static HINSTANCE hInstance;
#ifdef UNICODE
typedef INT_PTR (WINAPI *PDEVICEPROPERTIES)(HWND,LPCWSTR,LPCWSTR,BOOL);
#define FUNC_DEVICEPROPERTIES "DevicePropertiesW"
#else
typedef INT_PTR (WINAPI *PDEVICEPROPERTIES)(HWND,LPCSTR,LPCSTR,BOOL);
#define FUNC_DEVICEPROPERTIES "DevicePropertiesA"
#endif
static LPTSTR
GetMonitorDevInstID(LPCTSTR lpDeviceID)
{
/* FIXME: Implement, allocate returned string with LocalAlloc! */
return NULL;
}
static VOID
ShowMonitorProperties(PDESKMONITOR This)
{
HMODULE hDevMgr;
PDEVICEPROPERTIES pDeviceProperties;
LPTSTR lpDevInstID;
if (This->SelMonitor != NULL)
{
lpDevInstID = GetMonitorDevInstID(This->SelMonitor->dd.DeviceID);
if (lpDevInstID != NULL)
{
hDevMgr = LoadLibrary(TEXT("devmgr.dll"));
if (hDevMgr != NULL)
{
pDeviceProperties = (PDEVICEPROPERTIES)GetProcAddress(hDevMgr,
FUNC_DEVICEPROPERTIES);
if (pDeviceProperties != NULL)
{
pDeviceProperties(This->hwndDlg,
NULL,
This->SelMonitor->dd.DeviceID,
FALSE);
}
FreeLibrary(hDevMgr);
}
LocalFree((HLOCAL)lpDevInstID);
}
}
}
static VOID
UpdateMonitorSelection(PDESKMONITOR This)
{
INT i;
if (This->dwMonitorCount > 1)
{
This->SelMonitor = NULL;
i = (INT)SendDlgItemMessage(This->hwndDlg,
IDC_MONITORLIST,
LB_GETCURSEL,
0,
0);
if (i >= 0)
{
This->SelMonitor = (PDESKMONINFO)SendDlgItemMessage(This->hwndDlg,
IDC_MONITORLIST,
LB_GETITEMDATA,
(WPARAM)i,
0);
}
}
else
This->SelMonitor = This->Monitors;
EnableWindow(GetDlgItem(This->hwndDlg,
IDC_MONITORPROPERTIES),
This->SelMonitor != NULL);
}
static VOID
UpdatePruningControls(PDESKMONITOR This)
{
EnableWindow(GetDlgItem(This->hwndDlg,
IDC_PRUNINGCHECK),
This->bModesPruned && !This->bKeyIsReadOnly);
CheckDlgButton(This->hwndDlg,
IDC_PRUNINGCHECK,
(This->bModesPruned && This->bPruningOn) ? BST_CHECKED : BST_UNCHECKED);
}
static VOID
GetPruningSettings(PDESKMONITOR This)
{
BOOL bModesPruned = FALSE, bKeyIsReadOnly = FALSE, bPruningOn = FALSE;
if (This->DeskExtInterface != NULL)
{
This->DeskExtInterface->GetPruningMode(This->DeskExtInterface->Context,
&bModesPruned,
&bKeyIsReadOnly,
&bPruningOn);
}
/* Check the boolean values against zero before assigning it to the bitfields! */
This->bModesPruned = (bModesPruned != FALSE);
This->bKeyIsReadOnly = (bKeyIsReadOnly != FALSE);
This->bPruningOn = (bPruningOn != FALSE);
UpdatePruningControls(This);
}
static VOID
UpdateRefreshFrequencyList(PDESKMONITOR This)
{
PDEVMODEW lpCurrentMode, lpMode;
TCHAR szBuffer[64];
DWORD dwIndex;
INT i;
BOOL bHasDef = FALSE;
BOOL bAdded = FALSE;
/* Fill the refresh rate combo box */
SendDlgItemMessage(This->hwndDlg,
IDC_REFRESHRATE,
CB_RESETCONTENT,
0,
0);
lpCurrentMode = This->DeskExtInterface->GetCurrentMode(This->DeskExtInterface->Context);
dwIndex = 0;
do
{
lpMode = This->DeskExtInterface->EnumAllModes(This->DeskExtInterface->Context,
dwIndex++);
if (lpMode != NULL &&
lpMode->dmBitsPerPel == lpCurrentMode->dmBitsPerPel &&
lpMode->dmPelsWidth == lpCurrentMode->dmPelsWidth &&
lpMode->dmPelsHeight == lpCurrentMode->dmPelsHeight)
{
/* We're only interested in refresh rates for the current resolution and color depth */
if (lpMode->dmDisplayFrequency <= 1)
{
/* Default hardware frequency */
if (bHasDef)
continue;
bHasDef = TRUE;
if (!LoadString(hInstance,
IDS_USEDEFFRQUENCY,
szBuffer,
sizeof(szBuffer) / sizeof(szBuffer[0])))
{
szBuffer[0] = TEXT('\0');
}
}
else
{
TCHAR szFmt[64];
if (!LoadString(hInstance,
IDS_FREQFMT,
szFmt,
sizeof(szFmt) / sizeof(szFmt[0])))
{
szFmt[0] = TEXT('\0');
}
_sntprintf(szBuffer,
sizeof(szBuffer) / sizeof(szBuffer[0]),
szFmt,
lpMode->dmDisplayFrequency);
}
i = (INT)SendDlgItemMessage(This->hwndDlg,
IDC_REFRESHRATE,
CB_ADDSTRING,
0,
(LPARAM)szBuffer);
if (i >= 0)
{
bAdded = TRUE;
SendDlgItemMessage(This->hwndDlg,
IDC_REFRESHRATE,
CB_SETITEMDATA,
(WPARAM)i,
(LPARAM)lpMode);
if (lpMode->dmDisplayFrequency == lpCurrentMode->dmDisplayFrequency)
{
SendDlgItemMessage(This->hwndDlg,
IDC_REFRESHRATE,
CB_SETCURSEL,
(WPARAM)i,
0);
}
}
}
} while (lpMode != NULL);
EnableWindow(GetDlgItem(This->hwndDlg,
IDS_MONITORSETTINGSGROUP),
bAdded);
EnableWindow(GetDlgItem(This->hwndDlg,
IDS_REFRESHRATELABEL),
bAdded);
EnableWindow(GetDlgItem(This->hwndDlg,
IDC_REFRESHRATE),
bAdded);
GetPruningSettings(This);
}
static VOID
InitMonitorDialog(PDESKMONITOR This)
{
PDESKMONINFO pmi, pminext, *pmilink;
DISPLAY_DEVICE dd;
BOOL bRet;
INT i;
DWORD dwIndex;
/* Free all allocated monitors */
pmi = This->Monitors;
This->Monitors = NULL;
while (pmi != NULL)
{
pminext = pmi->Next;
LocalFree((HLOCAL)pmi);
pmi = pminext;
}
This->SelMonitor = NULL;
This->dwMonitorCount = 0;
if (This->lpDisplayDevice != NULL)
LocalFree((HLOCAL)This->lpDisplayDevice);
This->lpDisplayDevice = QueryDeskCplString(This->pdtobj,
RegisterClipboardFormat(DESK_EXT_DISPLAYDEVICE));
if (This->DeskExtInterface != NULL)
{
if (This->lpDisplayDevice != NULL)
{
/* Enumerate all monitors */
dwIndex = 0;
pmilink = &This->Monitors;
do
{
dd.cb = sizeof(dd);
bRet = EnumDisplayDevices(This->lpDisplayDevice,
dwIndex++,
&dd,
0);
if (bRet)
{
pmi = LocalAlloc(LMEM_FIXED,
sizeof(*pmi));
if (pmi != NULL)
{
CopyMemory(&pmi->dd,
&dd,
sizeof(dd));
pmi->Next = NULL;
*pmilink = pmi;
pmilink = &pmi->Next;
This->dwMonitorCount++;
}
}
} while (bRet);
}
This->lpDevModeOnInit = This->DeskExtInterface->GetCurrentMode(This->DeskExtInterface->Context);
}
else
This->lpDevModeOnInit = NULL;
This->lpSelDevMode = This->lpDevModeOnInit;
/* Setup the UI depending on how many monitors are attached */
if (This->dwMonitorCount == 0)
{
LPTSTR lpMonitorName;
/* This is a fallback, let's hope that desk.cpl can provide us with a monitor name */
lpMonitorName = QueryDeskCplString(This->pdtobj,
RegisterClipboardFormat(DESK_EXT_MONITORNAME));
SetDlgItemText(This->hwndDlg,
IDC_MONITORNAME,
lpMonitorName);
if (lpMonitorName != NULL)
LocalFree((HLOCAL)lpMonitorName);
}
else if (This->dwMonitorCount == 1)
{
This->SelMonitor = This->Monitors;
SetDlgItemText(This->hwndDlg,
IDC_MONITORNAME,
This->Monitors->dd.DeviceString);
}
else
{
SendDlgItemMessage(This->hwndDlg,
IDC_MONITORLIST,
LB_RESETCONTENT,
0,
0);
pmi = This->Monitors;
while (pmi != NULL)
{
i = (INT)SendDlgItemMessage(This->hwndDlg,
IDC_MONITORLIST,
LB_ADDSTRING,
0,
(LPARAM)pmi->dd.DeviceString);
if (i >= 0)
{
SendDlgItemMessage(This->hwndDlg,
IDC_MONITORLIST,
LB_SETITEMDATA,
(WPARAM)i,
(LPARAM)pmi);
if (This->SelMonitor == NULL)
{
SendDlgItemMessage(This->hwndDlg,
IDC_MONITORLIST,
LB_SETCURSEL,
(WPARAM)i,
0);
This->SelMonitor = pmi;
}
}
pmi = pmi->Next;
}
}
/* Show/Hide controls */
ShowWindow(GetDlgItem(This->hwndDlg,
IDC_MONITORNAME),
(This->dwMonitorCount <= 1 ? SW_SHOW : SW_HIDE));
ShowWindow(GetDlgItem(This->hwndDlg,
IDC_MONITORLIST),
(This->dwMonitorCount > 1 ? SW_SHOW : SW_HIDE));
UpdateRefreshFrequencyList(This);
UpdateMonitorSelection(This);
}
static VOID
UpdatePruningSelection(PDESKMONITOR This)
{
BOOL bPruningOn;
if (This->DeskExtInterface != NULL && This->bModesPruned && !This->bKeyIsReadOnly)
{
bPruningOn = IsDlgButtonChecked(This->hwndDlg,
IDC_PRUNINGCHECK) != BST_UNCHECKED;
if (bPruningOn != This->bPruningOn)
{
/* Tell desk.cpl to turn on/off pruning mode */
This->bPruningOn = bPruningOn;
This->DeskExtInterface->SetPruningMode(This->DeskExtInterface->Context,
bPruningOn);
/* Fill the refresh rate combobox again, we now receive a filtered
or unfiltered device mode list from desk.cpl (depending on whether
pruning is active or not) */
UpdateRefreshFrequencyList(This);
(void)PropSheet_Changed(GetParent(This->hwndDlg),
This->hwndDlg);
}
}
}
static VOID
UpdateRefreshRateSelection(PDESKMONITOR This)
{
PDEVMODEW lpCurrentDevMode;
INT i;
if (This->DeskExtInterface != NULL)
{
i = (INT)SendDlgItemMessage(This->hwndDlg,
IDC_REFRESHRATE,
CB_GETCURSEL,
0,
0);
if (i >= 0)
{
lpCurrentDevMode = This->lpSelDevMode;
This->lpSelDevMode = (PDEVMODEW)SendDlgItemMessage(This->hwndDlg,
IDC_REFRESHRATE,
CB_GETITEMDATA,
(WPARAM)i,
0);
if (This->lpSelDevMode != NULL && This->lpSelDevMode != lpCurrentDevMode)
{
This->DeskExtInterface->SetCurrentMode(This->DeskExtInterface->Context,
This->lpSelDevMode);
UpdateRefreshFrequencyList(This);
(void)PropSheet_Changed(GetParent(This->hwndDlg),
This->hwndDlg);
}
}
}
}
static LONG
ApplyMonitorChanges(PDESKMONITOR This)
{
LONG lChangeRet;
if (This->DeskExtInterface != NULL)
{
/* Change the display settings through desk.cpl */
lChangeRet = DeskCplExtDisplaySaveSettings(This->DeskExtInterface,
This->hwndDlg);
if (lChangeRet == DISP_CHANGE_SUCCESSFUL)
{
/* Save the new mode */
This->lpDevModeOnInit = This->DeskExtInterface->GetCurrentMode(This->DeskExtInterface->Context);
This->lpSelDevMode = This->lpDevModeOnInit;
return PSNRET_NOERROR;
}
else if (lChangeRet == DISP_CHANGE_RESTART)
{
/* Notify desk.cpl that the user needs to reboot */
PropSheet_RestartWindows(GetParent(This->hwndDlg));
return PSNRET_NOERROR;
}
}
InitMonitorDialog(This);
return PSNRET_INVALID_NOCHANGEPAGE;
}
static VOID
ResetMonitorChanges(PDESKMONITOR This)
{
if (This->DeskExtInterface != NULL && This->lpDevModeOnInit != NULL)
{
This->DeskExtInterface->SetCurrentMode(This->DeskExtInterface->Context,
This->lpDevModeOnInit);
}
}
static INT_PTR CALLBACK
MonitorDlgProc(HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
PDESKMONITOR This;
INT_PTR Ret = 0;
if (uMsg != WM_INITDIALOG)
{
This = (PDESKMONITOR)GetWindowLongPtr(hwndDlg, DWLP_USER);
}
switch (uMsg)
{
case WM_INITDIALOG:
This = (PDESKMONITOR)((LPCPROPSHEETPAGE)lParam)->lParam;
This->hwndDlg = hwndDlg;
SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)This);
InitMonitorDialog(This);
Ret = TRUE;
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_MONITORPROPERTIES:
ShowMonitorProperties(This);
break;
case IDC_MONITORLIST:
if (HIWORD(wParam) == LBN_SELCHANGE)
UpdateMonitorSelection(This);
break;
case IDC_PRUNINGCHECK:
if (HIWORD(wParam) == BN_CLICKED)
UpdatePruningSelection(This);
break;
case IDC_REFRESHRATE:
if (HIWORD(wParam) == CBN_SELCHANGE)
UpdateRefreshRateSelection(This);
break;
}
break;
case WM_NOTIFY:
{
NMHDR *nmh = (NMHDR *)lParam;
switch (nmh->code)
{
case PSN_APPLY:
{
SetWindowLongPtr(hwndDlg,
DWLP_MSGRESULT,
ApplyMonitorChanges(This));
break;
}
case PSN_RESET:
ResetMonitorChanges(This);
break;
case PSN_SETACTIVE:
UpdateRefreshFrequencyList(This);
break;
}
break;
}
}
return Ret;
}
static VOID
IDeskMonitor_Destroy(PDESKMONITOR This)
{
PDESKMONINFO pmi, pminext;
if (This->pdtobj != NULL)
{
IDataObject_Release(This->pdtobj);
This->pdtobj = NULL;
}
if (This->DeskExtInterface != NULL)
{
LocalFree((HLOCAL)This->DeskExtInterface);
This->DeskExtInterface = NULL;
}
if (This->lpDisplayDevice != NULL)
{
LocalFree((HLOCAL)This->lpDisplayDevice);
This->lpDisplayDevice = NULL;
}
/* Free all monitors */
pmi = This->Monitors;
This->Monitors = NULL;
while (pmi != NULL)
{
pminext = pmi->Next;
LocalFree((HLOCAL)pmi);
pmi = pminext;
}
}
ULONG
IDeskMonitor_AddRef(PDESKMONITOR This)
{
ULONG ret;
ret = InterlockedIncrement((PLONG)&This->ref);
if (ret == 1)
InterlockedIncrement(&dll_refs);
return ret;
}
ULONG
IDeskMonitor_Release(PDESKMONITOR This)
{
ULONG ret;
ret = InterlockedDecrement((PLONG)&This->ref);
if (ret == 0)
{
IDeskMonitor_Destroy(This);
InterlockedDecrement(&dll_refs);
HeapFree(GetProcessHeap(),
0,
This);
}
return ret;
}
HRESULT STDMETHODCALLTYPE
IDeskMonitor_QueryInterface(PDESKMONITOR This,
REFIID iid,
PVOID *pvObject)
{
*pvObject = NULL;
if (IsEqualIID(iid,
&IID_IShellPropSheetExt) ||
IsEqualIID(iid,
&IID_IUnknown))
{
*pvObject = impl_to_interface(This, IShellPropSheetExt);
}
else if (IsEqualIID(iid,
&IID_IShellExtInit))
{
*pvObject = impl_to_interface(This, IShellExtInit);
}
else if (IsEqualIID(iid,
&IID_IClassFactory))
{
*pvObject = impl_to_interface(This, IClassFactory);
}
else
{
DPRINT1("IDeskMonitor::QueryInterface(%p,%p): E_NOINTERFACE\n", iid, pvObject);
return E_NOINTERFACE;
}
IDeskMonitor_AddRef(This);
return S_OK;
}
HRESULT
IDeskMonitor_Initialize(PDESKMONITOR This,
LPCITEMIDLIST pidlFolder,
IDataObject *pdtobj,
HKEY hkeyProgID)
{
DPRINT1("IDeskMonitor::Initialize(%p,%p,%p)\n", pidlFolder, pdtobj, hkeyProgID);
if (pdtobj != NULL)
{
IDataObject_AddRef(pdtobj);
This->pdtobj = pdtobj;
/* Get a copy of the desk.cpl extension interface */
This->DeskExtInterface = QueryDeskCplExtInterface(This->pdtobj);
if (This->DeskExtInterface != NULL)
return S_OK;
}
return S_FALSE;
}
HRESULT
IDeskMonitor_AddPages(PDESKMONITOR This,
LPFNADDPROPSHEETPAGE pfnAddPage,
LPARAM lParam)
{
HPROPSHEETPAGE hpsp;
PROPSHEETPAGE psp;
DPRINT1("IDeskMonitor::AddPages(%p,%p)\n", pfnAddPage, lParam);
psp.dwSize = sizeof(psp);
psp.dwFlags = PSP_DEFAULT;
psp.hInstance = hInstance;
psp.pszTemplate = MAKEINTRESOURCE(IDD_MONITOR);
psp.pfnDlgProc = MonitorDlgProc;
psp.lParam = (LPARAM)This;
hpsp = CreatePropertySheetPage(&psp);
if (hpsp != NULL && pfnAddPage(hpsp, lParam))
return S_OK;
return S_FALSE;
}
HRESULT
IDeskMonitor_ReplacePage(PDESKMONITOR This,
EXPPS uPageID,
LPFNADDPROPSHEETPAGE pfnReplacePage,
LPARAM lParam)
{
DPRINT1("IDeskMonitor::ReplacePage(%u,%p,%p)\n", uPageID, pfnReplacePage, lParam);
return E_NOTIMPL;
}
HRESULT
IDeskMonitor_Constructor(REFIID riid,
LPVOID *ppv)
{
PDESKMONITOR This;
HRESULT hRet = E_OUTOFMEMORY;
DPRINT1("IDeskMonitor::Constructor(%p,%p)\n", riid, ppv);
This = HeapAlloc(GetProcessHeap(),
0,
sizeof(*This));
if (This != NULL)
{
ZeroMemory(This,
sizeof(*This));
IDeskMonitor_InitIface(This);
hRet = IDeskMonitor_QueryInterface(This,
riid,
ppv);
if (!SUCCEEDED(hRet))
IDeskMonitor_Release(This);
}
return hRet;
}
BOOL WINAPI
DllMain(HINSTANCE hinstDLL,
DWORD dwReason,
LPVOID lpvReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
hInstance = hinstDLL;
DisableThreadLibraryCalls(hInstance);
break;
}
return TRUE;
}