You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
836 lines
22 KiB
836 lines
22 KiB
#include "precomp.h"
|
|
#include "mcinc.h"
|
|
#include "util.h"
|
|
#include "intshcut.h"
|
|
#include "optary.h"
|
|
|
|
#define COMPILE_MULTIMON_STUBS
|
|
#include "multimon.h"
|
|
#undef COMPILE_MULTIMON_STUBS
|
|
|
|
BOOL IsSysKeyMessage(MSG *pMsg)
|
|
{
|
|
switch(pMsg->message)
|
|
{
|
|
case WM_SYSKEYDOWN:
|
|
case WM_SYSKEYUP :
|
|
case WM_SYSCHAR :
|
|
if(pMsg->wParam == VK_MENU) break; // Alt key alone.
|
|
|
|
if(pMsg->wParam >= L'0' && pMsg->wParam <= L'9' ) break; // ALT+<digit> should pass through.
|
|
if(pMsg->wParam >= VK_NUMPAD0 && pMsg->wParam <= VK_NUMPAD9) break; // ALT+<numpad> should pass through.
|
|
|
|
|
|
case WM_SYSDEADCHAR:
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL IsGlobalKeyMessage(MSG *pMsg)
|
|
{
|
|
BOOL fRet = IsSysKeyMessage( pMsg );
|
|
|
|
if(!fRet)
|
|
{
|
|
switch(pMsg->message)
|
|
{
|
|
case WM_KEYDOWN:
|
|
case WM_KEYUP:
|
|
// Allow ESC and CTRL-E as well...
|
|
fRet = ((pMsg->wParam == VK_ESCAPE ) ||
|
|
(pMsg->wParam == L'E' && GetAsyncKeyState( VK_CONTROL ) < 0) );
|
|
}
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
int IsVK_TABCycler(MSG *pMsg)
|
|
{
|
|
int result;
|
|
|
|
if (pMsg &&
|
|
(pMsg->message == WM_KEYDOWN) &&
|
|
((pMsg->wParam == VK_TAB) || (pMsg->wParam == VK_F6)))
|
|
{
|
|
result = (GetKeyState(VK_SHIFT) < 0) ? -1 : 1;
|
|
}
|
|
else
|
|
{
|
|
result = 0;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
DWORD CThreadData::s_dwTlsIndex = 0xffffffff;
|
|
|
|
CThreadData::CThreadData()
|
|
{
|
|
}
|
|
|
|
CThreadData::~CThreadData()
|
|
{
|
|
}
|
|
|
|
|
|
BOOL CThreadData::TlsSetValue(CThreadData *ptd)
|
|
{
|
|
ATLASSERT(s_dwTlsIndex != 0xffffffff);
|
|
|
|
// Don't call set twice except to clear
|
|
ATLASSERT((NULL == ptd) || (NULL == ::TlsGetValue(s_dwTlsIndex)));
|
|
|
|
return ::TlsSetValue(s_dwTlsIndex, ptd);
|
|
}
|
|
|
|
BOOL CThreadData::HaveData()
|
|
{
|
|
ATLASSERT(s_dwTlsIndex != 0xffffffff);
|
|
|
|
return NULL != ::TlsGetValue(s_dwTlsIndex);
|
|
}
|
|
|
|
CThreadData *CThreadData::TlsGetValue()
|
|
{
|
|
ATLASSERT(s_dwTlsIndex != 0xffffffff);
|
|
|
|
CThreadData *ptd = (CThreadData *)::TlsGetValue(s_dwTlsIndex);
|
|
|
|
ATLASSERT(NULL != ptd);
|
|
|
|
return ptd;
|
|
}
|
|
|
|
BOOL CThreadData::TlsAlloc()
|
|
{
|
|
ATLASSERT(s_dwTlsIndex == 0xffffffff); // Don't call this twice
|
|
|
|
s_dwTlsIndex = ::TlsAlloc();
|
|
|
|
return (s_dwTlsIndex != 0xffffffff) ? TRUE : FALSE;
|
|
}
|
|
|
|
BOOL CThreadData::TlsFree()
|
|
{
|
|
BOOL bResult;
|
|
|
|
if (s_dwTlsIndex != 0xffffffff)
|
|
{
|
|
bResult = ::TlsFree(s_dwTlsIndex);
|
|
s_dwTlsIndex = 0xffffffff;
|
|
}
|
|
else
|
|
{
|
|
bResult = FALSE;
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
HRESULT GetMarsTypeLib(ITypeLib **ppTypeLib)
|
|
{
|
|
ATLASSERT(NULL != ppTypeLib);
|
|
|
|
CThreadData *pThreadData = CThreadData::TlsGetValue();
|
|
|
|
if (!pThreadData->m_spTypeLib)
|
|
{
|
|
// Load our typelib, to be used for our automation interfaces
|
|
WCHAR wszModule[_MAX_PATH+10];
|
|
GetModuleFileNameW(_Module.GetModuleInstance(), wszModule, _MAX_PATH);
|
|
LoadTypeLib(wszModule, &pThreadData->m_spTypeLib);
|
|
}
|
|
|
|
pThreadData->m_spTypeLib.CopyTo(ppTypeLib);
|
|
|
|
return ((NULL != ppTypeLib) && (NULL != *ppTypeLib)) ? S_OK : E_FAIL;
|
|
}
|
|
|
|
|
|
UINT HashKey(LPCWSTR pwszName)
|
|
{
|
|
int hash = 0;
|
|
|
|
while (*pwszName)
|
|
{
|
|
hash += (hash << 5) + *pwszName++;
|
|
}
|
|
return hash;
|
|
}
|
|
|
|
|
|
void AsciiToLower(LPWSTR pwsz)
|
|
{
|
|
while (*pwsz)
|
|
{
|
|
if ((*pwsz >= L'A') && (*pwsz <= L'Z'))
|
|
{
|
|
*pwsz += L'a' - L'A';
|
|
}
|
|
pwsz++;
|
|
}
|
|
}
|
|
|
|
HRESULT PIDLToVariant(LPCITEMIDLIST pidl, CComVariant& v)
|
|
{
|
|
// the variant must be empty since we don't clear or initialize it
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
// NULL pidls are valid, so we just leave the variant empty and return S_OK
|
|
if (pidl)
|
|
{
|
|
v.bstrVal = SysAllocStringLen(NULL, MAX_PATH);
|
|
if (v.bstrVal)
|
|
{
|
|
// make this an official BSTR since the alloc succeeded
|
|
v.vt = VT_BSTR;
|
|
|
|
if (!SHGetPathFromIDListW(pidl, v.bstrVal))
|
|
{
|
|
// CComVariant will handle cleanup
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// Checks if global state is offline
|
|
BOOL IsGlobalOffline(void)
|
|
{
|
|
DWORD dwState = 0, dwSize = sizeof(DWORD);
|
|
BOOL fRet = FALSE;
|
|
HANDLE hModuleHandle = LoadLibraryA("wininet.dll");
|
|
|
|
if (!hModuleHandle)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (InternetQueryOption(NULL, INTERNET_OPTION_CONNECTED_STATE, &dwState, &dwSize))
|
|
{
|
|
if(dwState & INTERNET_STATE_DISCONNECTED_BY_USER)
|
|
fRet = TRUE;
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
void SetGlobalOffline(BOOL fOffline)
|
|
{
|
|
INTERNET_CONNECTED_INFO ci;
|
|
|
|
memset(&ci, 0, sizeof(ci));
|
|
if (fOffline)
|
|
{
|
|
ci.dwConnectedState = INTERNET_STATE_DISCONNECTED_BY_USER;
|
|
ci.dwFlags = ISO_FORCE_DISCONNECTED;
|
|
}
|
|
else
|
|
{
|
|
ci.dwConnectedState = INTERNET_STATE_CONNECTED;
|
|
}
|
|
|
|
InternetSetOption(NULL, INTERNET_OPTION_CONNECTED_STATE, &ci, sizeof(ci));
|
|
}
|
|
|
|
HRESULT
|
|
_WriteDIBToFile(HBITMAP hDib, HANDLE hFile)
|
|
{
|
|
if (!hDib)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// Make sure this is a valid DIB and get this useful info.
|
|
DIBSECTION ds;
|
|
if (!GetObject( hDib, sizeof(DIBSECTION), &ds ))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// We only deal with DIBs
|
|
if (ds.dsBm.bmPlanes != 1)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// Calculate some color table sizes
|
|
int nColors = ds.dsBmih.biBitCount <= 8 ? 1 << ds.dsBmih.biBitCount : 0;
|
|
int nBitfields = ds.dsBmih.biCompression == BI_BITFIELDS ? 3 : 0;
|
|
|
|
// Calculate the data size
|
|
int nImageDataSize = ds.dsBmih.biSizeImage ? ds.dsBmih.biSizeImage : ds.dsBm.bmWidthBytes * ds.dsBm.bmHeight;
|
|
|
|
// Get the color table (if needed)
|
|
RGBQUAD rgbqaColorTable[256] = {0};
|
|
if (nColors)
|
|
{
|
|
HDC hDC = CreateCompatibleDC(NULL);
|
|
if (hDC)
|
|
{
|
|
HBITMAP hOldBitmap = reinterpret_cast<HBITMAP>(SelectObject(hDC,hDib));
|
|
GetDIBColorTable( hDC, 0, nColors, rgbqaColorTable );
|
|
SelectObject(hDC,hOldBitmap);
|
|
DeleteDC( hDC );
|
|
}
|
|
}
|
|
|
|
// Create the file header
|
|
BITMAPFILEHEADER bmfh;
|
|
bmfh.bfType = 'MB';
|
|
bmfh.bfSize = 0;
|
|
bmfh.bfReserved1 = 0;
|
|
bmfh.bfReserved2 = 0;
|
|
bmfh.bfOffBits = sizeof(bmfh) + sizeof(ds.dsBmih) + nBitfields*sizeof(DWORD) + nColors*sizeof(RGBQUAD);
|
|
|
|
// Start writing! Note that we write out the bitfields and the color table. Only one,
|
|
// at most, will actually result in data being written
|
|
DWORD dwBytesWritten;
|
|
if (!WriteFile( hFile, &bmfh, sizeof(bmfh), &dwBytesWritten, NULL ))
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
if (!WriteFile( hFile, &ds.dsBmih, sizeof(ds.dsBmih), &dwBytesWritten, NULL ))
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
if (!WriteFile( hFile, &ds.dsBitfields, nBitfields*sizeof(DWORD), &dwBytesWritten, NULL ))
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
if (!WriteFile( hFile, rgbqaColorTable, nColors*sizeof(RGBQUAD), &dwBytesWritten, NULL ))
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
if (!WriteFile( hFile, ds.dsBm.bmBits, nImageDataSize, &dwBytesWritten, NULL ))
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT SaveDIBToFile(HBITMAP hbm, WCHAR *pszPath)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (hbm != NULL &&
|
|
hbm != INVALID_HANDLE_VALUE)
|
|
{
|
|
HANDLE hFile;
|
|
|
|
hr = E_FAIL;
|
|
|
|
hFile = CreateFileWrapW(pszPath, GENERIC_WRITE, FILE_SHARE_READ, NULL,
|
|
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
hr = _WriteDIBToFile(hbm, hFile);
|
|
|
|
CloseHandle(hFile);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
// BoundWindowRect will nudge a rectangle so that it stays fully on its current monitor.
|
|
// pRect must be in workspace coordinates
|
|
|
|
void BoundWindowRectToMonitor(HWND hwnd, RECT *pRect)
|
|
{
|
|
MONITORINFO mi;
|
|
mi.cbSize = sizeof(mi);
|
|
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST), &mi);
|
|
|
|
OffsetRect(&mi.rcWork,
|
|
mi.rcMonitor.left - mi.rcWork.left,
|
|
mi.rcMonitor.top - mi.rcWork.top);
|
|
|
|
LONG lDeltaX = 0, lDeltaY = 0;
|
|
|
|
if (pRect->left < mi.rcWork.left)
|
|
lDeltaX = mi.rcWork.left - pRect->left;
|
|
|
|
if (pRect->top < mi.rcWork.top)
|
|
lDeltaY = mi.rcWork.top - pRect->top;
|
|
|
|
if (pRect->right > mi.rcWork.right)
|
|
lDeltaX = mi.rcWork.right - pRect->right;
|
|
|
|
if (pRect->bottom > mi.rcWork.bottom)
|
|
lDeltaY = mi.rcWork.bottom - pRect->bottom;
|
|
|
|
RECT rc = *pRect;
|
|
OffsetRect(&rc, lDeltaX, lDeltaY);
|
|
IntersectRect(pRect, &rc, &mi.rcWork);
|
|
}
|
|
|
|
|
|
|
|
// Moves a rectangle down and to the right, by the same amount Windows would use
|
|
// to cascade. If the new position is partially off-screen, then the rect is either
|
|
// moved up to the top, or back to the origin.
|
|
|
|
void CascadeWindowRectOnMonitor(HWND hwnd, RECT *pRect)
|
|
{
|
|
int delta = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYSIZEFRAME) - 1;
|
|
OffsetRect(pRect, delta, delta);
|
|
|
|
// test if the new rect will end up getting moved later on
|
|
RECT rc = *pRect;
|
|
BoundWindowRectToMonitor(hwnd, &rc);
|
|
|
|
if (!EqualRect(pRect, &rc))
|
|
{
|
|
// rc had to be moved, so we'll restart the cascade using the best monitor
|
|
MONITORINFO mi;
|
|
mi.cbSize = sizeof(mi);
|
|
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST), &mi);
|
|
|
|
if (rc.bottom < pRect->bottom && rc.left == pRect->left)
|
|
{
|
|
// Too tall to cascade further down, but we can keep the X and just
|
|
// reset the Y. This fixes the bug of having a tall windows piling up
|
|
// on the top left corner -- instead they will be offset to the right
|
|
OffsetRect(pRect, 0, mi.rcMonitor.top - pRect->top);
|
|
}
|
|
else
|
|
{
|
|
// we've really run out of room, so restart cascade at top left
|
|
OffsetRect(pRect,
|
|
mi.rcMonitor.left - pRect->left,
|
|
mi.rcMonitor.top - pRect->top);
|
|
}
|
|
}
|
|
}
|
|
|
|
struct WINDOWSEARCHSTRUCT
|
|
{
|
|
LONG x;
|
|
LONG y;
|
|
ATOM atomClass;
|
|
BOOL fFoundWindow;
|
|
};
|
|
|
|
BOOL CALLBACK EnumWindowSearchProc(HWND hwnd, LPARAM lParam)
|
|
{
|
|
WINDOWSEARCHSTRUCT *pSearch = (WINDOWSEARCHSTRUCT *) lParam;
|
|
|
|
if ((ATOM) GetClassLong(hwnd, GCW_ATOM) == pSearch->atomClass)
|
|
{
|
|
// Only check the rest if we find a window that matches our class
|
|
|
|
WINDOWPLACEMENT wp;
|
|
wp.length = sizeof(wp);
|
|
GetWindowPlacement(hwnd, &wp);
|
|
|
|
pSearch->fFoundWindow =
|
|
pSearch->x == wp.rcNormalPosition.left &&
|
|
pSearch->y == wp.rcNormalPosition.top &&
|
|
IsWindowVisible(hwnd);
|
|
}
|
|
|
|
// return TRUE if we want to continue the enumeration
|
|
return !pSearch->fFoundWindow;
|
|
}
|
|
|
|
|
|
// Checks whether there is a window of the same class at some location on screen.
|
|
// x and y are in workspace coords because we need to use GetWindowPlacement to
|
|
// retrieve the rect of the restored window.
|
|
|
|
|
|
BOOL IsWindowOverlayed(HWND hwndMatch, LONG x, LONG y)
|
|
{
|
|
WINDOWSEARCHSTRUCT search = { x, y, (ATOM) GetClassLong(hwndMatch, GCW_ATOM), FALSE };
|
|
EnumWindows(EnumWindowSearchProc, (LPARAM) &search);
|
|
return search.fFoundWindow;
|
|
}
|
|
|
|
|
|
|
|
BOOL CInterfaceMarshal::Init()
|
|
{
|
|
m_hresMarshal = E_FAIL;
|
|
m_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
return m_hEvent != NULL;
|
|
}
|
|
|
|
|
|
CInterfaceMarshal::~CInterfaceMarshal()
|
|
{
|
|
if (m_hEvent)
|
|
CloseHandle(m_hEvent);
|
|
|
|
SAFERELEASE2(m_pStream);
|
|
}
|
|
|
|
|
|
HRESULT CInterfaceMarshal::Marshal(REFIID riid, IUnknown *pUnk)
|
|
{
|
|
ATLASSERT(pUnk);
|
|
|
|
m_hresMarshal = CoMarshalInterThreadInterfaceInStream(riid, pUnk, &m_pStream);
|
|
|
|
// We must signal the other thread regardless of whether the marshal was
|
|
// successful, otherwise it will be blocked for a very long time.
|
|
|
|
Signal();
|
|
|
|
return m_hresMarshal;
|
|
}
|
|
|
|
|
|
HRESULT CInterfaceMarshal::UnMarshal(REFIID riid, void ** ppv)
|
|
{
|
|
HRESULT hr;
|
|
ATLASSERT(ppv);
|
|
|
|
if (S_OK == m_hresMarshal)
|
|
{
|
|
hr = CoGetInterfaceAndReleaseStream(m_pStream, riid, ppv);
|
|
m_pStream = NULL;
|
|
}
|
|
else
|
|
{
|
|
hr = m_hresMarshal;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
void CInterfaceMarshal::Signal()
|
|
{
|
|
ATLASSERT(m_hEvent);
|
|
SetEvent(m_hEvent);
|
|
}
|
|
|
|
|
|
// This waiting code was copied from Shdocvw iedisp.cpp
|
|
//
|
|
// hSignallingThread is the handle of the thread that will be setting the m_hEvent.
|
|
// If that thread terminates before marshalling an interface, we can detect this
|
|
// condition and not hang around pointlessly.
|
|
|
|
HRESULT CInterfaceMarshal::WaitForSignal(HANDLE hSignallingThread, DWORD dwSecondsTimeout)
|
|
{
|
|
ATLASSERT(m_hEvent);
|
|
|
|
HANDLE ah[] = { m_hEvent, hSignallingThread };
|
|
DWORD dwStart = GetTickCount();
|
|
DWORD dwMaxWait = 1000 * dwSecondsTimeout;
|
|
DWORD dwWait = dwMaxWait;
|
|
DWORD dwWaitResult;
|
|
|
|
do {
|
|
// dwWait is the number of millseconds we still need to wait for
|
|
|
|
dwWaitResult = MsgWaitForMultipleObjects(
|
|
ARRAYSIZE(ah), ah, FALSE, dwWait, QS_SENDMESSAGE);
|
|
|
|
if (dwWaitResult == WAIT_OBJECT_0 + ARRAYSIZE(ah))
|
|
{
|
|
// Msg input. We allow the pending SendMessage() to go through
|
|
MSG msg;
|
|
PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
|
|
}
|
|
else
|
|
{
|
|
// signaled or timed out, so we exit the loop
|
|
break;
|
|
}
|
|
|
|
// Update dwWait. It will become larger than dwMaxWait if we
|
|
// wait more than that
|
|
|
|
dwWait = dwStart + dwMaxWait - GetTickCount();
|
|
|
|
} while (dwWait <= dwMaxWait);
|
|
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
switch (dwWaitResult)
|
|
{
|
|
case WAIT_OBJECT_0:
|
|
// Event signaled -- this is what should happen every time
|
|
hr = m_hresMarshal;
|
|
break;
|
|
|
|
case WAIT_OBJECT_0 + 1:
|
|
// Thread terminated before signalling
|
|
break;
|
|
|
|
case WAIT_OBJECT_0 + ARRAYSIZE(ah): // msg input -- fall through
|
|
case WAIT_TIMEOUT:
|
|
// Timed out while waiting for signal
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
HRESULT MarsNavigateShortcut(IUnknown *pBrowser, IUniformResourceLocator* pUrl, LPCWSTR pszPath)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (pBrowser )
|
|
{
|
|
CComPtr<IMoniker> spMkUrl;
|
|
CComPtr<IBindCtx> spBindCtx;
|
|
|
|
// Create moniker
|
|
LPWSTR pszURL = NULL;
|
|
hr = pUrl->GetURL(&pszURL);
|
|
|
|
if (pszURL)
|
|
{
|
|
hr = CreateURLMoniker(NULL, pszURL, &spMkUrl);
|
|
SHFree(pszURL);
|
|
}
|
|
|
|
if (SUCCEEDED(hr) && spMkUrl)
|
|
{
|
|
// create bind context and register load options
|
|
// NOTE: errors here are not fatal, as the bind context is optional, so hr is not set
|
|
CreateBindCtx(0, &spBindCtx);
|
|
if (spBindCtx)
|
|
{
|
|
CComPtr<IHtmlLoadOptions> spLoadOpt;
|
|
if (SUCCEEDED(CoCreateInstance(CLSID_HTMLLoadOptions, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IHtmlLoadOptions, (void**)&spLoadOpt)))
|
|
{
|
|
if (pszPath)
|
|
{
|
|
spLoadOpt->SetOption(HTMLLOADOPTION_INETSHORTCUTPATH, (void*)pszPath,
|
|
(lstrlen(pszPath) + 1) * sizeof(WCHAR));
|
|
}
|
|
|
|
spBindCtx->RegisterObjectParam(L"__HTMLLOADOPTIONS", spLoadOpt);
|
|
}
|
|
}
|
|
|
|
// create hyperlink using URL moniker
|
|
CComPtr<IHlink> spHlink;
|
|
hr = HlinkCreateFromMoniker(spMkUrl, NULL, NULL, NULL, 0, NULL, IID_IHlink, (void **)&spHlink);
|
|
if (spHlink)
|
|
{
|
|
// navigate frame using hyperlink and bind context
|
|
CComQIPtr<IHlinkFrame> spFrame(pBrowser);
|
|
if (spFrame)
|
|
{
|
|
hr = spFrame->Navigate(0, spBindCtx, NULL, spHlink);
|
|
}
|
|
else
|
|
{
|
|
hr = E_NOINTERFACE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// L"MarsNavigateShortcut: target or path is NULL";
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT MarsNavigateShortcut(IUnknown *pBrowser, LPCWSTR lpszPath)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (pBrowser && lpszPath)
|
|
{
|
|
// create internet shortcut object
|
|
CComPtr<IPersistFile> spPersistFile;
|
|
hr = CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IPersistFile, (void **)&spPersistFile);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// persist from file
|
|
hr = spPersistFile->Load(lpszPath, STGM_READ);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CComQIPtr<IUniformResourceLocator, &IID_IUniformResourceLocator> spURL(spPersistFile);
|
|
if (spURL)
|
|
{
|
|
hr = MarsNavigateShortcut(pBrowser, spURL, lpszPath);
|
|
|
|
}
|
|
else
|
|
{
|
|
hr = E_NOINTERFACE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT MarsVariantToPath(VARIANT &varItem, CComBSTR &strPath)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (API_IsValidVariant(varItem))
|
|
{
|
|
switch (varItem.vt)
|
|
{
|
|
case VT_EMPTY:
|
|
case VT_NULL:
|
|
case VT_ERROR:
|
|
// return path empty when undefined, null, or omitted
|
|
strPath.Empty();
|
|
hr = S_OK;
|
|
break;
|
|
|
|
case VT_BSTR:
|
|
// make a copy of the supplied path
|
|
strPath = varItem.bstrVal;
|
|
hr = S_OK;
|
|
break;
|
|
|
|
case VT_DISPATCH:
|
|
{
|
|
// query for FolderItem interface
|
|
CComQIPtr<FolderItem> spFolderItem(varItem.pdispVal);
|
|
|
|
// if we don't have a FolderItem, try to get one
|
|
if (!spFolderItem)
|
|
{
|
|
// if we got a Folder2 object instead of a FolderItem object
|
|
CComQIPtr<Folder2> spFolder2(varItem.pdispVal);
|
|
if (spFolder2)
|
|
{
|
|
// get FolderItem object from Folder2 interface
|
|
spFolder2->get_Self(&spFolderItem);
|
|
}
|
|
}
|
|
|
|
// if we managed to get a folder item
|
|
if (spFolderItem)
|
|
{
|
|
// get the path from it
|
|
CComBSTR bstr;
|
|
hr = spFolderItem->get_Path(&bstr);
|
|
strPath = bstr;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
BOOL PathIsURLFileW(LPCWSTR lpszPath)
|
|
{
|
|
BOOL fDoesMatch = FALSE;
|
|
|
|
if (lpszPath)
|
|
{
|
|
LPCWSTR lpszExt = PathFindExtensionW(lpszPath);
|
|
if (lpszExt && (StrCmpIW(lpszExt, L".url") == 0))
|
|
{
|
|
fDoesMatch = TRUE;
|
|
}
|
|
}
|
|
|
|
return fDoesMatch;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define GLOBAL_SETTINGS_PATH L"Software\\Microsoft\\PCHealth\\Global"
|
|
|
|
//==================================================================
|
|
// Registry helpers
|
|
//==================================================================
|
|
|
|
LONG CRegistryKey::QueryLongValue(LONG& lValue, LPCWSTR pwszValueName)
|
|
{
|
|
DWORD dwValue;
|
|
LONG lResult = QueryValue(dwValue, pwszValueName);
|
|
|
|
if (lResult == ERROR_SUCCESS)
|
|
{
|
|
lValue = (LONG) dwValue;
|
|
}
|
|
return lResult;
|
|
}
|
|
|
|
LONG CRegistryKey::SetLongValue(LONG lValue, LPCWSTR pwszValueName)
|
|
{
|
|
return SetValue((DWORD) lValue, pwszValueName);
|
|
}
|
|
|
|
LONG CRegistryKey::QueryBoolValue(BOOL& bValue, LPCWSTR pwszValueName)
|
|
{
|
|
DWORD dwValue;
|
|
LONG lResult = QueryValue(dwValue, pwszValueName);
|
|
|
|
if (lResult == ERROR_SUCCESS)
|
|
{
|
|
bValue = (BOOL) dwValue;
|
|
}
|
|
return lResult;
|
|
}
|
|
|
|
LONG CRegistryKey::SetBoolValue(BOOL bValue, LPCWSTR pwszValueName)
|
|
{
|
|
return SetValue((DWORD) bValue, pwszValueName);
|
|
}
|
|
|
|
LONG CRegistryKey::QueryBinaryValue(LPVOID pData, DWORD cbData, LPCWSTR pwszValueName)
|
|
{
|
|
DWORD dwType;
|
|
DWORD lResult = RegQueryValueEx(m_hKey, pwszValueName, NULL, &dwType, (BYTE *) pData, &cbData);
|
|
|
|
return (lResult == ERROR_SUCCESS) && (dwType != REG_BINARY) ? ERROR_INVALID_DATA : lResult;
|
|
}
|
|
|
|
LONG CRegistryKey::SetBinaryValue(LPVOID pData, DWORD cbData, LPCWSTR pwszValueName)
|
|
{
|
|
return RegSetValueEx(m_hKey, pwszValueName, NULL, REG_BINARY, (BYTE *) pData, cbData);
|
|
}
|
|
|
|
|
|
|
|
LONG CGlobalSettingsRegKey::CreateGlobalSubkey(LPCWSTR pwszSubkey)
|
|
{
|
|
CComBSTR strPath = GLOBAL_SETTINGS_PATH;
|
|
|
|
if (pwszSubkey)
|
|
{
|
|
strPath += L"\\";
|
|
strPath += pwszSubkey;
|
|
}
|
|
|
|
return Create(HKEY_CURRENT_USER, strPath);
|
|
}
|
|
|
|
|
|
LONG CGlobalSettingsRegKey::OpenGlobalSubkey(LPCWSTR pwszSubkey)
|
|
{
|
|
CComBSTR strPath = GLOBAL_SETTINGS_PATH;
|
|
|
|
if (pwszSubkey)
|
|
{
|
|
strPath += L"\\";
|
|
strPath += pwszSubkey;
|
|
}
|
|
|
|
return Open(HKEY_CURRENT_USER, strPath);
|
|
}
|