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.
1360 lines
41 KiB
1360 lines
41 KiB
/*
|
|
NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
|
|
|
|
This file is #include'd in browseui\ and shdocvw\ util.cpp. these are too small
|
|
to add an extra dependency, so they're just shared. ideally, these should move
|
|
to shlwapi or comctl32 or some lib or ...
|
|
|
|
NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
|
|
*/
|
|
|
|
#include "ccstock2.h"
|
|
#include "mluisupp.h"
|
|
#include "richedit.h" //for charformat2
|
|
|
|
STDAPI_(BOOL) IsBrowseNewProcess()
|
|
{
|
|
return SHRegGetBoolUSValue(REGSTR_PATH_EXPLORER TEXT("\\BrowseNewProcess"), TEXT("BrowseNewProcess"), FALSE, FALSE);
|
|
}
|
|
|
|
// Should we run browser in a new process?
|
|
STDAPI_(BOOL) IsBrowseNewProcessAndExplorer()
|
|
{
|
|
if (GetModuleHandle(TEXT("EXPLORER.EXE")))
|
|
return IsBrowseNewProcess();
|
|
|
|
return FALSE; // Not in shell process so ignore browse new process flag
|
|
}
|
|
|
|
HRESULT _NavigateFrame(IUnknown *punkFrame, LPCTSTR pszPath, BOOL fIsInternetShortcut)
|
|
{
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
BSTR bstr = SysAllocStringT(pszPath);
|
|
|
|
if (bstr)
|
|
{
|
|
if (fIsInternetShortcut)
|
|
{
|
|
IOleCommandTarget *pcmdt;
|
|
hr = IUnknown_QueryService(punkFrame, SID_SHlinkFrame, IID_PPV_ARG(IOleCommandTarget, &pcmdt));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
VARIANT varShortCutPath = {0};
|
|
VARIANT varFlag = {0};
|
|
|
|
varFlag.vt = VT_BOOL;
|
|
varFlag.boolVal = VARIANT_TRUE;
|
|
|
|
varShortCutPath.vt = VT_BSTR;
|
|
varShortCutPath.bstrVal = bstr;
|
|
|
|
hr = pcmdt->Exec(&CGID_Explorer, SBCMDID_IESHORTCUT, 0, &varShortCutPath, &varFlag);
|
|
pcmdt->Release();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IWebBrowser2 *pwb;
|
|
hr = IUnknown_QueryService(punkFrame, SID_SHlinkFrame, IID_PPV_ARG(IWebBrowser2, &pwb));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pwb->Navigate(bstr, PVAREMPTY, PVAREMPTY, PVAREMPTY, PVAREMPTY);
|
|
hr = pwb->put_Visible(VARIANT_TRUE);
|
|
pwb->Release();
|
|
}
|
|
}
|
|
SysFreeString(bstr);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Take a path or an URL and create a shorcut to navigare to it
|
|
//
|
|
STDAPI IENavigateIEProcess(LPCTSTR pszPath, BOOL fIsInternetShortcut)
|
|
{
|
|
IUnknown *punk;
|
|
HRESULT hr = CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARG(IUnknown, &punk));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = _NavigateFrame(punk, pszPath, fIsInternetShortcut);
|
|
punk->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
// If this is an internet shortcut (.url file), we want it to
|
|
// navigate using using the file name so the frame frame
|
|
// can read data beyond out of that file. this includes frame set
|
|
// navigation and data that script on the page may have stored.
|
|
|
|
/*
|
|
Purpose : This function takes a path to a file. if that file is a .URL we try
|
|
to navigate with that file name. this is because .URL files have extra data stored
|
|
in them that we want to let script on the page get to. the exec we send here
|
|
lets the frame know the .URL file that this came from
|
|
|
|
Parameters : file name of .URL file (maybe) : In param
|
|
pUnk : Pointer to Object from which you can get the IOleCommandTarget
|
|
|
|
returns:
|
|
TRUE handled
|
|
FALSE not handled, file might not be a .URL
|
|
*/
|
|
|
|
STDAPI NavFrameWithFile(LPCTSTR pszPath, IUnknown *punk)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
LPTSTR pszExt = PathFindExtension(pszPath);
|
|
// HACK: we hard code .URL. this should be a property of the file type
|
|
if (0 == StrCmpI(pszExt, TEXT(".url")))
|
|
{
|
|
#ifdef BROWSENEWPROCESS_STRICT // "Nav in new process" has become "Launch in new process", so this is no longer needed
|
|
if (IsBrowseNewProcessAndExplorer())
|
|
hr = IENavigateIEProcess(pszPath, TRUE);
|
|
else
|
|
#endif
|
|
hr = _NavigateFrame(punk, pszPath, TRUE);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// get the win32 file system name (path) for the item
|
|
// and optional attributes
|
|
//
|
|
// pdwAttrib may be NULL
|
|
// in/out:
|
|
// pdwAttrib may be NULL, attributes to query on the item
|
|
|
|
STDAPI GetPathForItem(IShellFolder *psf, LPCITEMIDLIST pidl, LPTSTR pszPath, DWORD *pdwAttrib)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
DWORD dwAttrib;
|
|
|
|
if (pdwAttrib == NULL)
|
|
{
|
|
pdwAttrib = &dwAttrib;
|
|
dwAttrib = SFGAO_FILESYSTEM;
|
|
}
|
|
else
|
|
*pdwAttrib |= SFGAO_FILESYSTEM;
|
|
|
|
if (SUCCEEDED(psf->GetAttributesOf(1, &pidl, pdwAttrib)) &&
|
|
(*pdwAttrib & SFGAO_FILESYSTEM))
|
|
{
|
|
STRRET str;
|
|
hres = psf->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &str);
|
|
if (SUCCEEDED(hres))
|
|
StrRetToBuf(&str, pidl, pszPath, MAX_PATH);
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
STDAPI EditBox_TranslateAcceleratorST(LPMSG lpmsg)
|
|
{
|
|
|
|
switch (lpmsg->message) {
|
|
case WM_KEYUP: // eat these (if we process corresponding WM_KEYDOWN)
|
|
case WM_KEYDOWN: // process these
|
|
if (lpmsg->wParam != VK_TAB)
|
|
{
|
|
// all keydown messages except for the tab key should go straight to
|
|
// the edit control -- unless the Ctrl key is down, in which case there
|
|
// are 9 messages that should go straight to the edit control
|
|
#ifdef DEBUG
|
|
if (lpmsg->wParam == VK_CONTROL)
|
|
return S_FALSE;
|
|
#endif
|
|
|
|
if (GetKeyState(VK_CONTROL) & 0x80000000)
|
|
{
|
|
switch (lpmsg->wParam)
|
|
{
|
|
case VK_RIGHT:
|
|
case VK_LEFT:
|
|
case VK_UP:
|
|
case VK_DOWN:
|
|
case VK_HOME:
|
|
case VK_END:
|
|
case VK_F4:
|
|
case VK_INSERT:
|
|
case VK_DELETE:
|
|
case 'C':
|
|
case 'X':
|
|
case 'V':
|
|
case 'A':
|
|
case 'Z':
|
|
// these Ctrl+key messages are used by the edit control
|
|
// send 'em straight there
|
|
break;
|
|
|
|
default:
|
|
return(S_FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch(lpmsg->wParam)
|
|
{
|
|
case VK_F5: // for refresh
|
|
case VK_F6: // for cycle focus
|
|
return(S_FALSE);
|
|
}
|
|
}
|
|
|
|
// Note that we return S_OK.
|
|
goto TranslateDispatch;
|
|
}
|
|
break;
|
|
|
|
|
|
case WM_CHAR:
|
|
TranslateDispatch:
|
|
TranslateMessage(lpmsg);
|
|
DispatchMessage(lpmsg);
|
|
return(S_OK);
|
|
}
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
// NOTE: dupe with shell32 util.cpp function
|
|
// like OLE GetClassFile(), but it only works on ProgID\CLSID type registration
|
|
// not real doc files or pattern matched files
|
|
//
|
|
STDAPI _CLSIDFromExtension(LPCTSTR pszExt, CLSID *pclsid)
|
|
{
|
|
TCHAR szProgID[80];
|
|
DWORD cb = SIZEOF(szProgID);
|
|
if (SHGetValue(HKEY_CLASSES_ROOT, pszExt, NULL, NULL, szProgID, &cb) == ERROR_SUCCESS)
|
|
{
|
|
TCHAR szCLSID[80];
|
|
|
|
StrCatBuff(szProgID, TEXT("\\CLSID"), ARRAYSIZE(szProgID));
|
|
cb = SIZEOF(szCLSID);
|
|
|
|
if (SHGetValue(HKEY_CLASSES_ROOT, szProgID, NULL, NULL, szCLSID, &cb) == ERROR_SUCCESS)
|
|
{
|
|
return GUIDFromString(szCLSID, pclsid) ? S_OK : E_FAIL;
|
|
}
|
|
}
|
|
return E_FAIL;
|
|
}
|
|
|
|
#if 0 // not used yet
|
|
// IShellLink is #defined to IShellLinkA or IShellLinkW depending on compile flags,
|
|
// bug Win95 did not support IShellLinkW. So call this function instead and you
|
|
// get the correct results regardless of what platform you are running on.
|
|
// REVIEW: In fact, we probably want these for ALL IShellLink functions...
|
|
//
|
|
LWSTDAPI IShellLink_GetPathA(IUnknown *punk, LPSTR pszBuf, UINT cchBuf, DWORD dwFlags)
|
|
{
|
|
HRESULT hres = E_INVALIDARG;
|
|
|
|
RIPMSG(cchBuf && pszBuf && IS_VALID_WRITE_BUFFER(pszBuf, char, cchBuf), "IShellLink_GetPathA: callre passed bad pszBuf/cchBuf");
|
|
DEBUGWhackPathBufferA(pszBuf, cchBuf);
|
|
|
|
if (cchBuf && pszBuf)
|
|
{
|
|
// In case of gross failure, NULL output buffer
|
|
*pszBuf = 0;
|
|
|
|
IShellLinkA * pslA;
|
|
hres = punk->QueryInterface(IID_IShellLinkA, (void**)&pslA);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = pslA->GetPath(pszBuf, cchBuf, NULL, dwFlags);
|
|
pslA->Release();
|
|
}
|
|
else if (FAILED(hres))
|
|
{
|
|
#ifdef UNICODE
|
|
IShellLinkW *pslW;
|
|
hres = punk->QueryInterface(IID_IShellLinkW, (void**)&pslW);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
WCHAR wszPath[MAX_BUF];
|
|
LPWSTR pwszBuf = wszPath;
|
|
UINT cch = ARRAYSIZE(wszPath);
|
|
|
|
// Our stack buffer is too small, allocate one of the output buffer size
|
|
if (cchBuf > cch)
|
|
{
|
|
LPWSTR pwsz = LocalAlloc(LPTR, cchBuf * sizeof(WCHAR));
|
|
if (pwsz)
|
|
{
|
|
pwszBuf = pwsz;
|
|
cch = cchBuf;
|
|
}
|
|
}
|
|
|
|
hres = pslW->GetPath(pwszBuf, cch, NULL, dwFlags);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
SHUnicodeToAnsi(pwszBuf, pszBuf, cchBuf);
|
|
}
|
|
|
|
pslW->Release();
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
LWSTDAPI IShellLink_GetPathW(IUnknown *punk, LPWSTR pwszBuf, UINT cchBuf, DWORD dwFlags)
|
|
{
|
|
HRESULT hres = E_INVALIDARG;
|
|
|
|
RIPMSG(cchBuf && pwszBuf && IS_VALID_WRITE_BUFFER(pwszBuf, WCHAR, cchBuf), "IShellLink_GetPathW: caller passed bad pwszBuf/cchBuf");
|
|
DEBUGWhackPathBufferW(pwszBuf, cchBuf);
|
|
|
|
if (cchBuf && pwszBuf)
|
|
{
|
|
// In case of gross failure, NULL output buffer
|
|
*pwszBuf = 0;
|
|
|
|
#ifdef UNICODE
|
|
IShellLinkW * pslW;
|
|
hres = punk->QueryInterface(IID_IShellLinkW, (void**)&pslW);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = pslW->GetPath(pszBuf, cchBuf, NULL, dwFlags);
|
|
pslW->Release();
|
|
}
|
|
else if (FAILED(hres))
|
|
#endif
|
|
{
|
|
IShellLinkA *pslA;
|
|
hres = punk->QueryInterface(IID_IShellLinkA, (void**)&pslA);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
char szPath[MAX_BUF];
|
|
LPSTR pszBuf = szPath;
|
|
UINT cch = ARRAYSIZE(szPath);
|
|
|
|
// Our stack buffer is too small, allocate one of the output buffer size
|
|
if (cchBuf > cch)
|
|
{
|
|
LPSTR psz = LocalAlloc(LPTR, cchBuf * sizeof(char));
|
|
if (psz)
|
|
{
|
|
pszBuf = psz;
|
|
cch = cchBuf;
|
|
}
|
|
}
|
|
|
|
hres = pslA->GetPath(pszBuf, cch, NULL, dwFlags);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
SHAnsiToUnicode(pszBuf, pwszBuf, cchBuf);
|
|
}
|
|
|
|
pslA->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
#endif // 0
|
|
|
|
HRESULT IShellLinkAorW_GetPath(IShellLinkA *pslA, LPTSTR pszBuf, UINT cchBuf, DWORD dwFlags)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
|
|
// If we store the string unicode, we could be losing file information by asking
|
|
// through A version. Be unicode friendly and use the W version if it exists
|
|
//
|
|
#ifdef UNICODE
|
|
IShellLinkW *pslW;
|
|
hres = pslA->QueryInterface(IID_PPV_ARG(IShellLinkW, &pslW));
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = pslW->GetPath(pszBuf, cchBuf, NULL, dwFlags);
|
|
pslW->Release();
|
|
}
|
|
#endif
|
|
|
|
if (FAILED(hres))
|
|
{
|
|
char szBuf[MAX_URL_STRING]; // BOGUS, but this is a common size used, perhaps we should LocalAlloc...
|
|
|
|
cchBuf = ARRAYSIZE(szBuf);
|
|
|
|
hres = pslA->GetPath(szBuf, cchBuf, NULL, dwFlags);
|
|
|
|
SHAnsiToTChar(szBuf, pszBuf, cchBuf);
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
STDAPI GetLinkTargetIDList(LPCTSTR pszPath, LPTSTR pszTarget, DWORD cchTarget, LPITEMIDLIST *ppidl)
|
|
{
|
|
IShellLinkA *psl;
|
|
CLSID clsid;
|
|
HRESULT hres;
|
|
|
|
*ppidl = NULL; // assume failure
|
|
|
|
// WARNING: we really should call GetClassFile() but this could
|
|
// slow this down a lot... so chicken out and just look in the registry
|
|
|
|
if (FAILED(_CLSIDFromExtension(PathFindExtension(pszPath), &clsid)))
|
|
clsid = CLSID_ShellLink; // assume it's a shell link
|
|
|
|
hres = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellLinkA, &psl));
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
IPersistFile *ppf;
|
|
hres = psl->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
WCHAR wszPath[MAX_PATH];
|
|
|
|
SHTCharToUnicode(pszPath, wszPath, ARRAYSIZE(wszPath));
|
|
hres = ppf->Load(wszPath, 0);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
psl->GetIDList(ppidl);
|
|
|
|
if (*ppidl == NULL)
|
|
hres = E_FAIL; // NULL pidl is valid, but
|
|
// lets not return that to clients
|
|
if (pszTarget)
|
|
{
|
|
IShellLinkAorW_GetPath(psl, pszTarget, cchTarget, 0);
|
|
}
|
|
}
|
|
ppf->Release();
|
|
}
|
|
psl->Release();
|
|
}
|
|
|
|
// pszPath might == pszTarget so don't null out on entry always
|
|
if (FAILED(hres) && pszTarget)
|
|
*pszTarget = 0;
|
|
return hres;
|
|
}
|
|
|
|
|
|
STDAPI_(void) PathToDisplayNameW(LPCTSTR pszPath, LPTSTR pszDisplayName, UINT cchDisplayName)
|
|
{
|
|
SHFILEINFO sfi;
|
|
if (SHGetFileInfo(pszPath, 0, &sfi, SIZEOF(sfi), SHGFI_DISPLAYNAME))
|
|
{
|
|
StrCpyN(pszDisplayName, sfi.szDisplayName, cchDisplayName);
|
|
}
|
|
else
|
|
{
|
|
StrCpyN(pszDisplayName, PathFindFileName(pszPath), cchDisplayName);
|
|
PathRemoveExtension(pszDisplayName);
|
|
}
|
|
}
|
|
|
|
|
|
STDAPI_(void) PathToDisplayNameA(LPSTR pszPathA, LPSTR pszDisplayNameA, int cchDisplayName)
|
|
{
|
|
SHFILEINFOA sfi;
|
|
if (SHGetFileInfoA(pszPathA, 0, &sfi, SIZEOF(sfi), SHGFI_DISPLAYNAME))
|
|
{
|
|
StrCpyNA(pszDisplayNameA, sfi.szDisplayName, cchDisplayName);
|
|
}
|
|
else
|
|
{
|
|
pszPathA = PathFindFileNameA(pszPathA);
|
|
StrCpyNA(pszDisplayNameA, pszPathA, cchDisplayName);
|
|
PathRemoveExtensionA(pszDisplayNameA);
|
|
}
|
|
}
|
|
|
|
void* DataObj_GetDataOfType(IDataObject* pdtobj, UINT cfType, STGMEDIUM *pstg)
|
|
{
|
|
void * pret = NULL;
|
|
FORMATETC fmte = {(CLIPFORMAT)cfType, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
|
|
|
|
if (pdtobj->GetData(&fmte, pstg) == S_OK)
|
|
{
|
|
pret = GlobalLock(pstg->hGlobal);
|
|
if (!pret)
|
|
ReleaseStgMedium(pstg);
|
|
}
|
|
return pret;
|
|
}
|
|
|
|
void ReleaseStgMediumHGLOBAL(STGMEDIUM *pstg)
|
|
{
|
|
ASSERT(pstg->tymed == TYMED_HGLOBAL);
|
|
|
|
GlobalUnlock(pstg->hGlobal);
|
|
ReleaseStgMedium(pstg);
|
|
}
|
|
|
|
|
|
// this looks for the file descriptor format to get the display name of a data object
|
|
STDAPI DataObj_GetNameFromFileDescriptor(IDataObject *pdtobj, LPWSTR pszDisplayName, UINT cch)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
STGMEDIUM mediumFGD;
|
|
|
|
InitClipboardFormats();
|
|
FILEGROUPDESCRIPTORW * pfgd = (FILEGROUPDESCRIPTORW *)DataObj_GetDataOfType(pdtobj, g_cfFileDescW, &mediumFGD);
|
|
if (pfgd)
|
|
{
|
|
if (pfgd->cItems > 0)
|
|
{
|
|
LPFILEDESCRIPTORW pfd = &(pfgd->fgd[0]);
|
|
SHUnicodeToTChar(pfd->cFileName, pszDisplayName, cch);
|
|
hres = S_OK;
|
|
}
|
|
ReleaseStgMediumHGLOBAL(&mediumFGD);
|
|
}
|
|
else
|
|
{
|
|
FILEGROUPDESCRIPTORA * pfgd = (FILEGROUPDESCRIPTORA *)DataObj_GetDataOfType(pdtobj, g_cfFileDescA, &mediumFGD);
|
|
if (pfgd)
|
|
{
|
|
if (pfgd->cItems > 0)
|
|
{
|
|
LPFILEDESCRIPTORA pfd = &(pfgd->fgd[0]);
|
|
SHAnsiToTChar(pfd->cFileName, pszDisplayName, cch);
|
|
hres = S_OK;
|
|
}
|
|
ReleaseStgMediumHGLOBAL(&mediumFGD);
|
|
}
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
STDAPI SHPidlFromDataObject2(IDataObject *pdtobj, LPITEMIDLIST * ppidl)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
STGMEDIUM medium;
|
|
|
|
InitClipboardFormats();
|
|
void *pdata = DataObj_GetDataOfType(pdtobj, g_cfHIDA, &medium);
|
|
if (pdata)
|
|
{
|
|
*ppidl = IDA_ILClone((LPIDA)pdata, 0);
|
|
if (*ppidl)
|
|
hres = S_OK;
|
|
else
|
|
hres = E_OUTOFMEMORY;
|
|
ReleaseStgMediumHGLOBAL(&medium);
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
STDAPI SHPidlFromDataObject(IDataObject *pdtobj, LPITEMIDLIST *ppidl,
|
|
LPWSTR pszDisplayNameW, DWORD cchDisplayName)
|
|
{
|
|
FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
|
|
STGMEDIUM medium;
|
|
|
|
*ppidl = NULL;
|
|
|
|
HRESULT hres = pdtobj->GetData(&fmte, &medium);
|
|
if (hres == S_OK)
|
|
{
|
|
// This string is also used to store an URL in case it's an URL file
|
|
TCHAR szPath[MAX_URL_STRING];
|
|
hres = E_FAIL;
|
|
if (DragQueryFile((HDROP)medium.hGlobal, 0, szPath, ARRAYSIZE(szPath)))
|
|
{
|
|
SHFILEINFO sfi;
|
|
SHGetFileInfo(szPath, 0, &sfi, SIZEOF(sfi), SHGFI_ATTRIBUTES | SHGFI_DISPLAYNAME);
|
|
|
|
if (pszDisplayNameW)
|
|
SHTCharToUnicode(sfi.szDisplayName, pszDisplayNameW, MAX_PATH);
|
|
|
|
if (sfi.dwAttributes & SFGAO_LINK)
|
|
hres = GetLinkTargetIDList(szPath, szPath, ARRAYSIZE(szPath), ppidl);
|
|
|
|
if (FAILED(hres))
|
|
hres = IECreateFromPath(szPath, ppidl);
|
|
}
|
|
ReleaseStgMedium(&medium);
|
|
}
|
|
else
|
|
{
|
|
hres = SHPidlFromDataObject2(pdtobj, ppidl);
|
|
if (FAILED(hres))
|
|
{
|
|
void *pdata = DataObj_GetDataOfType(pdtobj, g_cfURL, &medium);
|
|
if (pdata)
|
|
{
|
|
LPSTR pszPath = (LPSTR)pdata;
|
|
if (pszDisplayNameW)
|
|
{
|
|
if (FAILED(DataObj_GetNameFromFileDescriptor(pdtobj, pszDisplayNameW, cchDisplayName)))
|
|
{
|
|
CHAR szDisplayNameA[MAX_URL_STRING];
|
|
ASSERT(cchDisplayName < MAX_URL_STRING);
|
|
SHUnicodeToAnsi(pszDisplayNameW, szDisplayNameA, cchDisplayName);
|
|
PathToDisplayNameA(pszPath, szDisplayNameA, cchDisplayName);
|
|
}
|
|
}
|
|
hres = IECreateFromPathA(pszPath, ppidl);
|
|
ReleaseStgMediumHGLOBAL(&medium);
|
|
}
|
|
}
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
|
|
// BharatS - Perhaps all the stuff below here should be moved to shlwapi after beta 2 ?
|
|
|
|
typedef struct _broadcastmsgparams
|
|
{
|
|
BOOL fSendMessage; // If true - we call SendMessageTimeout
|
|
UINT uTimeout; // Only Matters if fSendMessage is set
|
|
UINT uMsg;
|
|
WPARAM wParam;
|
|
LPARAM lParam;
|
|
} BROADCAST_MSG_PARAMS;
|
|
|
|
BOOL CALLBACK EnumShellIEWindowsProc(
|
|
HWND hwnd, // handle to parent window
|
|
LPARAM lParam // application-defined value - this has the info needed for posting/sending the message
|
|
)
|
|
{
|
|
BROADCAST_MSG_PARAMS *pParams = (BROADCAST_MSG_PARAMS *)lParam;
|
|
BOOL fRet = TRUE;
|
|
|
|
if(IsExplorerWindow(hwnd) || IsFolderWindow(hwnd))
|
|
{
|
|
if(pParams->fSendMessage)
|
|
{
|
|
UINT uTimeout = (pParams->uTimeout < 4000) ? pParams->uTimeout : 4000;
|
|
LRESULT lResult;
|
|
DWORD_PTR dwpResult;
|
|
if (g_fRunningOnNT)
|
|
{
|
|
lResult = SendMessageTimeout(hwnd, pParams->uMsg, pParams->wParam, pParams->lParam, SMTO_ABORTIFHUNG | SMTO_NORMAL, uTimeout, &dwpResult);
|
|
}
|
|
else
|
|
{
|
|
lResult = SendMessageTimeoutA(hwnd, pParams->uMsg, pParams->wParam, pParams->lParam, SMTO_ABORTIFHUNG | SMTO_NORMAL, uTimeout, &dwpResult);
|
|
}
|
|
fRet = BOOLIFY(lResult);
|
|
}
|
|
else
|
|
{
|
|
fRet = PostMessage(hwnd, pParams->uMsg, pParams->wParam, pParams->lParam);
|
|
|
|
}
|
|
}
|
|
return fRet;
|
|
|
|
}
|
|
|
|
// PostShellIEBroadcastMessage is commented out since it is not used currentl
|
|
/*
|
|
|
|
STDAPI_(LRESULT) PostShellIEBroadcastMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
BROADCAST_MSG_PARAMS MsgParam;
|
|
|
|
MsgParam.uMsg = uMsg;
|
|
MsgParam.wParam = wParam;
|
|
MsgParam.lParam = lParam;
|
|
MsgParam.fSendMessage = FALSE;
|
|
|
|
return EnumWindows(EnumShellIEWindowsProc, (LPARAM)&MsgParam);
|
|
}
|
|
*/
|
|
|
|
//
|
|
// We can be hung if we use sendMessage, and you can not use pointers with asynchronous
|
|
// calls such as PostMessage or SendNotifyMessage. So we resort to using a timeout.
|
|
// This function should be used to broadcast notification messages, such as WM_SETTINGCHANGE,
|
|
// that pass pointers. (stevepro)
|
|
//
|
|
STDAPI_(LRESULT) SendShellIEBroadcastMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, UINT uTimeout)
|
|
{
|
|
// Note that each this timeout is applied to each window that we broadcast to
|
|
|
|
BROADCAST_MSG_PARAMS MsgParam;
|
|
|
|
MsgParam.uMsg = uMsg;
|
|
MsgParam.wParam = wParam;
|
|
|
|
#ifdef UNICODE
|
|
CHAR szSection[MAX_PATH];
|
|
|
|
if (!g_fRunningOnNT && (uMsg == WM_WININICHANGE) && (0 != lParam))
|
|
{
|
|
SHUnicodeToAnsi((LPCWSTR)lParam, szSection, ARRAYSIZE(szSection));
|
|
lParam = (LPARAM)szSection;
|
|
}
|
|
#endif
|
|
|
|
MsgParam.lParam = lParam;
|
|
MsgParam.fSendMessage = TRUE;
|
|
MsgParam.uTimeout = uTimeout;
|
|
|
|
return EnumWindows(EnumShellIEWindowsProc, (LPARAM)&MsgParam);
|
|
}
|
|
|
|
// Return the parent psf and relative pidl given a pidl.
|
|
STDAPI IEBindToParentFolder(LPCITEMIDLIST pidl, IShellFolder** ppsfParent, LPCITEMIDLIST *ppidlChild)
|
|
{
|
|
HRESULT hres;
|
|
|
|
//
|
|
// if this is a rooted pidl and it is just the root
|
|
// then we can bind to the target pidl of the root instead
|
|
//
|
|
if (ILIsRooted(pidl) && ILIsEmpty(_ILNext(pidl)))
|
|
pidl = ILRootedFindIDList(pidl);
|
|
|
|
LPITEMIDLIST pidlParent = ILCloneParent(pidl);
|
|
|
|
if (pidlParent)
|
|
{
|
|
hres = IEBindToObject(pidlParent, ppsfParent);
|
|
ILFree(pidlParent);
|
|
}
|
|
else
|
|
hres = E_OUTOFMEMORY;
|
|
|
|
if (ppidlChild)
|
|
*ppidlChild = ILFindLastID(pidl);
|
|
|
|
return hres;
|
|
}
|
|
|
|
STDAPI GetDataObjectForPidl(LPCITEMIDLIST pidl, IDataObject ** ppdtobj)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
if (pidl)
|
|
{
|
|
IShellFolder *psfParent;
|
|
LPCITEMIDLIST pidlChild;
|
|
hres = IEBindToParentFolder(pidl, &psfParent, &pidlChild);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = psfParent->GetUIObjectOf(NULL, 1, &pidlChild, IID_PPV_ARG_NULL(IDataObject, ppdtobj));
|
|
psfParent->Release();
|
|
}
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
// Is this pidl a Folder/Directory in the File System?
|
|
STDAPI_(BOOL) ILIsFileSysFolder(LPCITEMIDLIST pidl)
|
|
{
|
|
if (!pidl)
|
|
return FALSE;
|
|
|
|
DWORD dwAttributes = SFGAO_FOLDER | SFGAO_FILESYSTEM;
|
|
HRESULT hr = IEGetAttributesOf(pidl, &dwAttributes);
|
|
return SUCCEEDED(hr) && ((dwAttributes & (SFGAO_FOLDER | SFGAO_FILESYSTEM)) == (SFGAO_FOLDER | SFGAO_FILESYSTEM));
|
|
}
|
|
|
|
|
|
// HACKHACK HACKHACK
|
|
// the following functions are to work around the menu
|
|
// munging that happens in the shlwapi wrappers... when we're
|
|
// manipulating menus which are tracked by the system, the
|
|
// menu munging code in our shlwapi wrappers (necessary
|
|
// for xcp plugUI) trashes them since the system doesn't
|
|
// understand munged menus... hence the work arounds below.
|
|
// note that many of these functions are copies of the shlwapi
|
|
// *WrapW functions (minus the munging).
|
|
|
|
#undef LoadMenuW
|
|
|
|
// from winuser.h
|
|
EXTERN_C WINUSERAPI HMENU WINAPI LoadMenuW(HINSTANCE hInstance, LPCWSTR lpMenuName);
|
|
|
|
STDAPI_(HMENU)
|
|
LoadMenu_PrivateNoMungeW(HINSTANCE hInstance, LPCWSTR lpMenuName)
|
|
{
|
|
ASSERT(HIWORD64(lpMenuName) == 0);
|
|
|
|
if (g_fRunningOnNT)
|
|
{
|
|
return LoadMenuW(hInstance, lpMenuName);
|
|
}
|
|
|
|
return LoadMenuA(hInstance, (LPCSTR) lpMenuName);
|
|
}
|
|
|
|
#define CP_ATOM 0xFFFFFFFF /* not a string at all */
|
|
#undef InsertMenuW
|
|
|
|
// from winuser.h
|
|
EXTERN_C WINUSERAPI BOOL WINAPI InsertMenuW(IN HMENU hMenu, IN UINT uPosition, IN UINT uFlags, IN UINT_PTR uIDNewItem, IN LPCWSTR lpNewItem);
|
|
|
|
STDAPI_(BOOL) InsertMenu_PrivateNoMungeW(HMENU hMenu,
|
|
UINT uPosition,
|
|
UINT uFlags,
|
|
UINT_PTR uIDNewItem,
|
|
LPCWSTR lpNewItem)
|
|
{
|
|
if (g_fRunningOnNT)
|
|
{
|
|
return InsertMenuW(hMenu, uPosition, uFlags, uIDNewItem, lpNewItem);
|
|
}
|
|
|
|
char szMenuItem[CCH_MENUMAX];
|
|
|
|
SHUnicodeToAnsiCP((uFlags & MFT_NONSTRING) ? CP_ATOM : CP_ACP,
|
|
lpNewItem,
|
|
szMenuItem,
|
|
ARRAYSIZE(szMenuItem));
|
|
|
|
return InsertMenuA(hMenu, uPosition, uFlags, uIDNewItem, szMenuItem);
|
|
}
|
|
|
|
#ifndef NO_MLUI_IN_SHELL32
|
|
STDAPI_(HMENU) LoadMenuPopup_PrivateNoMungeW(UINT id)
|
|
{
|
|
HINSTANCE hinst = MLLoadShellLangResources();
|
|
|
|
HMENU hMenuSub = NULL;
|
|
HMENU hMenu = LoadMenu_PrivateNoMungeW(hinst, MAKEINTRESOURCEW(id));
|
|
if (hMenu)
|
|
{
|
|
hMenuSub = GetSubMenu(hMenu, 0);
|
|
if (hMenuSub)
|
|
{
|
|
RemoveMenu(hMenu, 0, MF_BYPOSITION);
|
|
}
|
|
|
|
// note this calls the shlwapi wrapper (that handles
|
|
// destroying munged menus) but it looks like
|
|
// it's safe to do so.
|
|
DestroyMenu(hMenu);
|
|
}
|
|
|
|
MLFreeLibrary(hinst);
|
|
|
|
return hMenuSub;
|
|
}
|
|
#endif // NO_MLUI_IN_SHELL32
|
|
|
|
// determine if a path is just a filespec (contains no path parts)
|
|
//
|
|
// REVIEW: we may want to count the # of elements, and make sure
|
|
// there are no illegal chars, but that is probably another routing
|
|
// PathIsValid()
|
|
//
|
|
// in:
|
|
// lpszPath path to look at
|
|
// returns:
|
|
// TRUE no ":" or "\" chars in this path
|
|
// FALSE there are path chars in there
|
|
//
|
|
//
|
|
|
|
BOOL PathIsFilePathA(LPCSTR lpszPath)
|
|
{
|
|
#ifdef UNIX
|
|
if (lpszPath[0] == '/')
|
|
#else
|
|
if ((lpszPath[0] == '\\') || (lpszPath[1] == ':'))
|
|
#endif
|
|
return TRUE;
|
|
|
|
return IsFileUrl(lpszPath);
|
|
}
|
|
|
|
//
|
|
// PrepareURLForDisplay
|
|
//
|
|
// Decodes without stripping file:// prefix
|
|
//
|
|
STDAPI_(BOOL) PrepareURLForDisplayA(LPCSTR psz, LPSTR pszOut, LPDWORD pcchOut)
|
|
{
|
|
if (PathIsFilePathA(psz))
|
|
{
|
|
if (IsFileUrl(psz))
|
|
return SUCCEEDED(PathCreateFromUrlA(psz, pszOut, pcchOut, 0));
|
|
|
|
StrCpyNA(pszOut, psz, *pcchOut);
|
|
*pcchOut = lstrlenA(pszOut);
|
|
return TRUE;
|
|
}
|
|
return SUCCEEDED(UrlUnescapeA((LPSTR)psz, pszOut, pcchOut, 0));
|
|
}
|
|
|
|
#undef InsertMenuW
|
|
#undef LoadMenuW
|
|
|
|
// from w95wraps.h
|
|
#define InsertMenuW InsertMenuWrapW
|
|
#define LoadMenuW LoadMenuWrapW
|
|
|
|
STDAPI SHTitleFromPidl(LPCITEMIDLIST pidl, LPTSTR psz, DWORD cch, BOOL fFullPath)
|
|
{
|
|
// Tries to get a system-displayable string from a pidl.
|
|
// (On Win9x and NT4, User32 doesn't support font-linking,
|
|
// so we can't display non-system language strings as window
|
|
// titles or menu items. In those cases, we call this function
|
|
// to grab the path/URL instead, which will likely be system-
|
|
// displayable).
|
|
|
|
UINT uType;
|
|
|
|
*psz = NULL;
|
|
TCHAR szName[MAX_URL_STRING];
|
|
|
|
if (fFullPath)
|
|
uType = SHGDN_FORPARSING;
|
|
else
|
|
uType = SHGDN_NORMAL;
|
|
|
|
uType |= SHGDN_FORADDRESSBAR;
|
|
DWORD dwAttrib = SFGAO_LINK;
|
|
|
|
HRESULT hr = IEGetNameAndFlags(pidl, uType, szName, SIZECHARS(szName), &dwAttrib);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if ((uType & SHGDN_FORPARSING) && (dwAttrib & SFGAO_LINK))
|
|
{
|
|
// folder shortcut special case
|
|
IShellLinkA *psl; // Use A version for W95.
|
|
if (SUCCEEDED(SHGetUIObjectFromFullPIDL(pidl, NULL, IID_PPV_ARG(IShellLinkA, &psl))))
|
|
{
|
|
LPITEMIDLIST pidlTarget;
|
|
if (SUCCEEDED(psl->GetIDList(&pidlTarget)) && pidlTarget)
|
|
{
|
|
hr = IEGetNameAndFlags(pidlTarget, uType, szName, SIZECHARS(szName), NULL);
|
|
ILFree(pidlTarget);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// didn't work, try the reverse
|
|
uType ^= SHGDN_FORPARSING; // flip the for parsing bit
|
|
hr = IEGetNameAndFlags(pidl, uType, szName, SIZECHARS(szName), NULL);
|
|
|
|
// some old namespaces get confused by all our funny bits...
|
|
if (FAILED(hr))
|
|
{
|
|
hr = IEGetNameAndFlags(pidl, SHGDN_NORMAL, szName, SIZECHARS(szName), NULL);
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
SHRemoveURLTurd(szName);
|
|
SHCleanupUrlForDisplay(szName);
|
|
|
|
// HTTP URLs are not escaped because they come from the
|
|
// user or web page which is required to create correctly
|
|
// escaped URLs. FTP creates then via results from the
|
|
// FTP session, so their pieces (username, password, path)
|
|
// need to be escaped when put in URL form. However,
|
|
// we are going to put that URL into the Caption Bar, and
|
|
// and we want to unescape it because it's assumed to be
|
|
// a DBCS name. All of this is done because unescaped URLs
|
|
// are pretty. (NT #1272882)
|
|
if (URL_SCHEME_FTP == GetUrlScheme(szName))
|
|
{
|
|
CHAR szUrlTemp[MAX_BROWSER_WINDOW_TITLE];
|
|
CHAR szUnEscaped[MAX_BROWSER_WINDOW_TITLE];
|
|
DWORD cchSizeTemp = ARRAYSIZE(szUnEscaped);
|
|
|
|
// This thunking stuff is necessary. Unescaping won't
|
|
// gell into DBCS chars unless it's in ansi.
|
|
SHTCharToAnsi(szName, szUrlTemp, ARRAYSIZE(szUrlTemp));
|
|
PrepareURLForDisplayA(szUrlTemp, szUnEscaped, &cchSizeTemp);
|
|
SHAnsiToTChar(szUnEscaped, psz, cch);
|
|
}
|
|
else
|
|
{
|
|
StrCpyN(psz, szName, cch);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
BOOL IsSpecialUrl(LPCWSTR pchURL)
|
|
{
|
|
UINT uProt = GetUrlSchemeW(pchURL);
|
|
return (URL_SCHEME_JAVASCRIPT == uProt ||
|
|
URL_SCHEME_VBSCRIPT == uProt ||
|
|
URL_SCHEME_ABOUT == uProt);
|
|
}
|
|
|
|
HRESULT DetectSpecialUrlHacks(PCWSTR pszUrl)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
if (IsSpecialUrl(pszUrl))
|
|
{
|
|
//
|
|
// If this is javascript:, vbscript: or about:, we used to append the
|
|
// url of this document so that on the other side we can
|
|
// decide whether or not to allow script execution.
|
|
//
|
|
// since we did this, there were exploits that would take advantage of this
|
|
// so we block those "exploit-like" URLs even though we dont use the security
|
|
// context anymore.
|
|
//
|
|
// we used to loop with CoInternetParseUrl(PARSE_ENCODE) which is the
|
|
// same as CoInternetParseUrl(PARSE_UNESCAPE) due to a bug in URLMON's
|
|
// original implementation.
|
|
//
|
|
// Unescaping is always lossy, and almost guarantees some kind of bug.
|
|
// therefore we no longer unescape here, although there may be some kind of compatibility issue.
|
|
//
|
|
if (StrChrW(pszUrl, L'\1')
|
|
|| StrStrW(pszUrl, L"%00")
|
|
|| StrStrW(pszUrl, L"%01"))
|
|
{
|
|
hr = E_ACCESSDENIED;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT WrapSpecialUrlFlat(LPWSTR pszUrl, DWORD cchUrl)
|
|
{
|
|
return DetectSpecialUrlHacks(pszUrl);
|
|
}
|
|
|
|
//encode any incoming %1 so that people can't spoof our domain security code
|
|
HRESULT WrapSpecialUrl(BSTR * pbstrUrl)
|
|
{
|
|
return DetectSpecialUrlHacks(*pbstrUrl);
|
|
}
|
|
|
|
STDAPI GetBrowserFrameOptions(IUnknown *punkFolder, IN BROWSERFRAMEOPTIONS dwMask, OUT BROWSERFRAMEOPTIONS * pdwOptions)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
*pdwOptions = BFO_NONE;
|
|
if (punkFolder)
|
|
{
|
|
IBrowserFrameOptions *pbfo;
|
|
hr = punkFolder->QueryInterface(IID_PPV_ARG(IBrowserFrameOptions, &pbfo));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pbfo->GetFrameOptions(dwMask, pdwOptions);
|
|
pbfo->Release();
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDAPI GetBrowserFrameOptionsPidl(IN LPCITEMIDLIST pidl, IN BROWSERFRAMEOPTIONS dwMask, OUT BROWSERFRAMEOPTIONS * pdwOptions)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
*pdwOptions = BFO_NONE;
|
|
if (pidl)
|
|
{
|
|
IBrowserFrameOptions *pbfo;
|
|
hr = IEBindToObjectEx(pidl, NULL, IID_PPV_ARG(IBrowserFrameOptions, &pbfo));
|
|
if (SUCCEEDED(hr) && pbfo)
|
|
{
|
|
hr = pbfo->GetFrameOptions(dwMask, pdwOptions);
|
|
pbfo->Release();
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// Return TRUE only if all the bits in dwMask are set.
|
|
STDAPI_(BOOL) IsBrowserFrameOptionsSet(IN IShellFolder * psf, IN BROWSERFRAMEOPTIONS dwMask)
|
|
{
|
|
BOOL fSet = FALSE;
|
|
BROWSERFRAMEOPTIONS dwOptions = 0;
|
|
|
|
if (SUCCEEDED(GetBrowserFrameOptions(psf, dwMask, &dwOptions)) &&
|
|
(dwOptions == dwMask))
|
|
{
|
|
fSet = TRUE;
|
|
}
|
|
|
|
return fSet;
|
|
}
|
|
|
|
|
|
// Return TRUE only if all the bits in dwMask are set.
|
|
STDAPI_(BOOL) IsBrowserFrameOptionsPidlSet(IN LPCITEMIDLIST pidl, IN BROWSERFRAMEOPTIONS dwMask)
|
|
{
|
|
BOOL fSet = FALSE;
|
|
BROWSERFRAMEOPTIONS dwOptions = 0;
|
|
|
|
if (SUCCEEDED(GetBrowserFrameOptionsPidl(pidl, dwMask, &dwOptions)) &&
|
|
(dwOptions == dwMask))
|
|
{
|
|
fSet = TRUE;
|
|
}
|
|
|
|
return fSet;
|
|
}
|
|
|
|
|
|
STDAPI_(BOOL) IsFTPFolder(IShellFolder * psf)
|
|
{
|
|
BOOL fIsFTPFolder = FALSE;
|
|
CLSID clsid;
|
|
|
|
if (psf && SUCCEEDED(IUnknown_GetClassID(psf, &clsid)))
|
|
{
|
|
// Is this an FTP Folder?
|
|
if (IsEqualIID(clsid, CLSID_FtpFolder))
|
|
fIsFTPFolder = TRUE;
|
|
else
|
|
{
|
|
// Not directly, but let's see if it is an Folder Shortcut to
|
|
// an FTP Folder
|
|
if (IsEqualIID(clsid, CLSID_FolderShortcut))
|
|
{
|
|
IShellLinkA * psl;
|
|
HRESULT hr = psf->QueryInterface(IID_PPV_ARG(IShellLinkA, &psl));
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LPITEMIDLIST pidl;
|
|
|
|
hr = psl->GetIDList(&pidl);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IShellFolder * psfTarget;
|
|
|
|
hr = IEBindToObject(pidl, &psfTarget);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (SUCCEEDED(IUnknown_GetClassID(psfTarget, &clsid)) &&
|
|
IsEqualIID(clsid, CLSID_FtpFolder))
|
|
{
|
|
fIsFTPFolder = TRUE;
|
|
}
|
|
|
|
psfTarget->Release();
|
|
}
|
|
|
|
ILFree(pidl);
|
|
}
|
|
|
|
psl->Release();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return fIsFTPFolder;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: DrawFocusRectangle
|
|
//
|
|
// Synopsis: draws the focus rectangle for the edit control
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
void DrawFocusRectangle (HWND hwnd, HDC hdc)
|
|
{
|
|
RECT rect;
|
|
BOOL fReleaseDC = FALSE;
|
|
|
|
if ( hdc == NULL )
|
|
{
|
|
hdc = GetDC(hwnd);
|
|
if ( hdc == NULL )
|
|
{
|
|
return;
|
|
}
|
|
fReleaseDC = TRUE;
|
|
}
|
|
|
|
GetClientRect(hwnd, &rect);
|
|
DrawFocusRect(hdc, &rect);
|
|
|
|
if ( fReleaseDC == TRUE )
|
|
{
|
|
ReleaseDC(hwnd, hdc);
|
|
}
|
|
}
|
|
|
|
typedef struct {
|
|
LPSTR psz;
|
|
LPCWSTR pwsz;
|
|
LONG byteoffset;
|
|
BOOL fStreamIn;
|
|
} STREAMIN_HELPER_STRUCT;
|
|
|
|
DWORD CALLBACK SetRicheditTextWCallback(
|
|
DWORD_PTR dwCookie, // application-defined value
|
|
LPBYTE pbBuff, // pointer to a buffer
|
|
LONG cb, // number of bytes to read or write
|
|
LONG *pcb // pointer to number of bytes transferred
|
|
)
|
|
{
|
|
STREAMIN_HELPER_STRUCT *pHelpStruct = (STREAMIN_HELPER_STRUCT *) dwCookie;
|
|
LONG lRemain = ((wcslen(pHelpStruct->pwsz) * sizeof(WCHAR)) - pHelpStruct->byteoffset);
|
|
|
|
if (pHelpStruct->fStreamIn)
|
|
{
|
|
//
|
|
// The whole string can be copied first time
|
|
//
|
|
if ((cb >= (LONG) (wcslen(pHelpStruct->pwsz) * sizeof(WCHAR))) && (pHelpStruct->byteoffset == 0))
|
|
{
|
|
memcpy(pbBuff, pHelpStruct->pwsz, wcslen(pHelpStruct->pwsz) * sizeof(WCHAR));
|
|
*pcb = wcslen(pHelpStruct->pwsz) * sizeof(WCHAR);
|
|
pHelpStruct->byteoffset = *pcb;
|
|
}
|
|
//
|
|
// The whole string has been copied, so terminate the streamin callbacks
|
|
// by setting the num bytes copied to 0
|
|
//
|
|
else if (((LONG)(wcslen(pHelpStruct->pwsz) * sizeof(WCHAR))) <= pHelpStruct->byteoffset)
|
|
{
|
|
*pcb = 0;
|
|
}
|
|
//
|
|
// The rest of the string will fit in this buffer
|
|
//
|
|
else if (cb >= (LONG) ((wcslen(pHelpStruct->pwsz) * sizeof(WCHAR)) - pHelpStruct->byteoffset))
|
|
{
|
|
memcpy(
|
|
pbBuff,
|
|
((BYTE *)pHelpStruct->pwsz) + pHelpStruct->byteoffset,
|
|
((wcslen(pHelpStruct->pwsz) * sizeof(WCHAR)) - pHelpStruct->byteoffset));
|
|
*pcb = ((wcslen(pHelpStruct->pwsz) * sizeof(WCHAR)) - pHelpStruct->byteoffset);
|
|
pHelpStruct->byteoffset += ((wcslen(pHelpStruct->pwsz) * sizeof(WCHAR)) - pHelpStruct->byteoffset);
|
|
}
|
|
//
|
|
// copy as much as possible
|
|
//
|
|
else
|
|
{
|
|
memcpy(
|
|
pbBuff,
|
|
((BYTE *)pHelpStruct->pwsz) + pHelpStruct->byteoffset,
|
|
cb);
|
|
*pcb = cb;
|
|
pHelpStruct->byteoffset += cb;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This is the EM_STREAMOUT which is only used during the testing of
|
|
// the richedit2.0 functionality. (we know our buffer is 32 bytes)
|
|
//
|
|
if (cb <= 32)
|
|
{
|
|
memcpy(pHelpStruct->psz, pbBuff, cb);
|
|
}
|
|
*pcb = cb;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void SetRicheditIMFOption(HWND hWndRichEdit)
|
|
{
|
|
DWORD dwOptions;
|
|
|
|
dwOptions = (DWORD)SendMessageW(hWndRichEdit, EM_GETLANGOPTIONS, 0, 0);
|
|
dwOptions |= IMF_UIFONTS;
|
|
SendMessageW(hWndRichEdit, EM_SETLANGOPTIONS, 0, dwOptions);
|
|
}
|
|
|
|
DWORD SetRicheditTextW(HWND hwndDlg, UINT id, LPCWSTR pwsz)
|
|
{
|
|
EDITSTREAM editStream;
|
|
STREAMIN_HELPER_STRUCT helpStruct;
|
|
|
|
SetRicheditIMFOption(GetDlgItem(hwndDlg, id));
|
|
|
|
//
|
|
// setup the edit stream struct since it is the same no matter what
|
|
//
|
|
editStream.dwCookie = (DWORD_PTR) &helpStruct;
|
|
editStream.dwError = 0;
|
|
editStream.pfnCallback = SetRicheditTextWCallback;
|
|
|
|
helpStruct.pwsz = pwsz;
|
|
helpStruct.byteoffset = 0;
|
|
helpStruct.fStreamIn = TRUE;
|
|
|
|
SendDlgItemMessageW(hwndDlg, id, EM_STREAMIN, SF_TEXT | SF_UNICODE, (LPARAM) &editStream);
|
|
|
|
return editStream.dwError;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: RenderStringToEditControlW
|
|
//
|
|
// Synopsis: renders a string to the control given and if requested, gives
|
|
// it a link look and feel, subclassed to the wndproc given
|
|
//
|
|
// Arguments: [hwndDlg] -- dialog window handle
|
|
// [pwsz] -- string
|
|
// [wndproc] -- wndproc
|
|
// [uID] -- ID of control
|
|
//
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
void RenderStringToEditControlW (
|
|
HWND hwndDlg,
|
|
LPCWSTR pwsz,
|
|
WNDPROC wndproc,
|
|
UINT uID)
|
|
{
|
|
HWND hControl;
|
|
//
|
|
// Get the control and set the text on it, make sure the background is right
|
|
//
|
|
|
|
hControl = GetDlgItem(hwndDlg, uID);
|
|
SetRicheditIMFOption(GetDlgItem(hwndDlg, uID));
|
|
SetRicheditTextW(hwndDlg, uID, L"");
|
|
SetRicheditTextW(hwndDlg, uID, pwsz);
|
|
|
|
SendMessage(
|
|
hControl,
|
|
EM_SETBKGNDCOLOR,
|
|
0,
|
|
(LPARAM)GetSysColor(COLOR_3DFACE)
|
|
);
|
|
|
|
//
|
|
// Update for the link look
|
|
//
|
|
|
|
CHARFORMAT cf;
|
|
|
|
memset(&cf, 0, sizeof(CHARFORMAT));
|
|
cf.cbSize = sizeof(CHARFORMAT);
|
|
cf.dwMask = CFM_COLOR | CFM_UNDERLINE | CFM_LINK;
|
|
cf.crTextColor = RGB(0, 0, 255);
|
|
cf.dwEffects |= CFE_UNDERLINE | CFE_LINK;
|
|
|
|
SendMessage(hControl, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
|
|
|
|
|
|
//subclass the window proc so we can handle the link specially
|
|
LONG_PTR PrevWndProc = GetWindowLongPtr(hControl, GWLP_WNDPROC);
|
|
SetWindowLongPtr(hControl, GWLP_USERDATA, (LONG_PTR)PrevWndProc);
|
|
SetWindowLongPtr(hControl, GWLP_WNDPROC, (LONG_PTR)wndproc);
|
|
}
|
|
|
|
|
|
|