windows-nt/Source/XPSP1/NT/shell/ext/url/persist.cpp
2020-09-26 16:20:57 +08:00

1602 lines
41 KiB
C++

/*
* persist.cpp - IPersist, IPersistFile, and IPersistStream implementations for
* URL class.
*/
/* Headers
**********/
#include "project.hpp"
#pragma hdrstop
#include "resource.h"
#include <mluisupp.h>
/* Global Constants
*******************/
#pragma data_seg(DATA_SEG_READ_ONLY)
extern const UINT g_ucMaxURLLen = 1024;
extern const char g_cszURLPrefix[] = "url:";
extern const UINT g_ucbURLPrefixLen = sizeof(g_cszURLPrefix) - 1;
extern const char g_cszURLExt[] = ".url";
extern const char g_cszURLDefaultFileNamePrompt[] = "*.url";
extern const char g_cszCRLF[] = "\r\n";
#pragma data_seg()
/* Module Constants
*******************/
#pragma data_seg(DATA_SEG_READ_ONLY)
// case-insensitive
PRIVATE_DATA const char s_cszInternetShortcutSection[] = "InternetShortcut";
PRIVATE_DATA const char s_cszURLKey[] = "URL";
PRIVATE_DATA const char s_cszIconFileKey[] = "IconFile";
PRIVATE_DATA const char s_cszIconIndexKey[] = "IconIndex";
PRIVATE_DATA const char s_cszHotkeyKey[] = "Hotkey";
PRIVATE_DATA const char s_cszWorkingDirectoryKey[] = "WorkingDirectory";
PRIVATE_DATA const char s_cszShowCmdKey[] = "ShowCommand";
PRIVATE_DATA const UINT s_ucMaxIconIndexLen = 1 + 10 + 1; // -2147483647
PRIVATE_DATA const UINT s_ucMaxHotkeyLen = s_ucMaxIconIndexLen;
PRIVATE_DATA const UINT s_ucMaxShowCmdLen = s_ucMaxIconIndexLen;
#pragma data_seg()
/***************************** Private Functions *****************************/
PRIVATE_CODE BOOL DeletePrivateProfileString(PCSTR pcszSection, PCSTR pcszKey,
PCSTR pcszFile)
{
ASSERT(IS_VALID_STRING_PTR(pcszSection, CSTR));
ASSERT(IS_VALID_STRING_PTR(pcszKey, CSTR));
ASSERT(IS_VALID_STRING_PTR(pcszFile, CSTR));
return(WritePrivateProfileString(pcszSection, pcszKey, NULL, pcszFile));
}
#define SHDeleteIniString(pcszSection, pcszKey, pcszFile) \
SHSetIniString(pcszSection, pcszKey, NULL, pcszFile)
PRIVATE_CODE HRESULT MassageURL(PSTR pszURL)
{
HRESULT hr = E_FAIL;
ASSERT(IS_VALID_STRING_PTR(pszURL, STR));
TrimWhiteSpace(pszURL);
PSTR pszBase = pszURL;
PSTR psz;
// Skip over any "url:" prefix.
if (! lstrnicmp(pszBase, g_cszURLPrefix, g_ucbURLPrefixLen))
pszBase += g_ucbURLPrefixLen;
lstrcpy(pszURL, pszBase);
hr = S_OK;
TRACE_OUT(("MassageURL(): Massaged URL to %s.",
pszURL));
ASSERT(FAILED(hr) ||
IS_VALID_STRING_PTR(pszURL, STR));
return(hr);
}
PRIVATE_CODE HRESULT ReadURLFromFile(PCSTR pcszFile, PSTR *ppszURL)
{
HRESULT hr;
PSTR pszNewURL;
ASSERT(IS_VALID_STRING_PTR(pcszFile, CSTR));
ASSERT(IS_VALID_WRITE_PTR(ppszURL, PSTR));
*ppszURL = NULL;
pszNewURL = new(char[g_ucMaxURLLen]);
if (pszNewURL)
{
DWORD dwcValueLen;
dwcValueLen = SHGetIniString(s_cszInternetShortcutSection,
s_cszURLKey,
pszNewURL, g_ucMaxURLLen, pcszFile);
if (dwcValueLen > 0)
{
hr = MassageURL(pszNewURL);
if (hr == S_OK)
{
PSTR pszShorterURL;
// (+ 1) for null terminator.
if (ReallocateMemory(pszNewURL, lstrlen(pszNewURL) + 1,
(PVOID *)&pszShorterURL))
{
*ppszURL = pszShorterURL;
hr = S_OK;
}
else
hr = E_OUTOFMEMORY;
}
}
else
{
hr = S_FALSE;
WARNING_OUT(("ReadURLFromFile: No URL found in file %s.",
pcszFile));
}
}
else
hr = E_OUTOFMEMORY;
if (FAILED(hr) ||
hr == S_FALSE)
{
if (pszNewURL)
{
delete pszNewURL;
pszNewURL = NULL;
}
}
ASSERT((hr == S_OK &&
IS_VALID_STRING_PTR(*ppszURL, STR)) ||
(hr != S_OK &&
! *ppszURL));
return(hr);
}
PRIVATE_CODE HRESULT WriteURLToFile(PCSTR pcszFile, PCSTR pcszURL)
{
HRESULT hr;
ASSERT(IS_VALID_STRING_PTR(pcszFile, CSTR));
ASSERT(! pcszURL ||
IS_VALID_STRING_PTR(pcszURL, CSTR));
if (AnyMeat(pcszURL))
{
int ncbLen;
ASSERT(IS_VALID_STRING_PTR(pcszFile, CSTR));
ASSERT(IS_VALID_STRING_PTR(pcszURL, PSTR));
hr = (SHSetIniString(s_cszInternetShortcutSection, s_cszURLKey, pcszURL, pcszFile))
? S_OK
: E_FAIL;
}
else
hr = (SHDeleteIniString(s_cszInternetShortcutSection, s_cszURLKey, pcszFile))
? S_OK
: E_FAIL;
return(hr);
}
PRIVATE_CODE HRESULT ReadIconLocationFromFile(PCSTR pcszFile,
PSTR *ppszIconFile, PINT pniIcon)
{
HRESULT hr;
char rgchNewIconFile[MAX_PATH_LEN];
DWORD dwcValueLen;
ASSERT(IS_VALID_STRING_PTR(pcszFile, CSTR));
ASSERT(IS_VALID_WRITE_PTR(ppszIconFile, PSTR));
ASSERT(IS_VALID_WRITE_PTR(pniIcon, INT));
*ppszIconFile = NULL;
*pniIcon = 0;
dwcValueLen = SHGetIniString(s_cszInternetShortcutSection,
s_cszIconFileKey,
rgchNewIconFile,
sizeof(rgchNewIconFile), pcszFile);
if (dwcValueLen > 0)
{
char rgchNewIconIndex[s_ucMaxIconIndexLen];
dwcValueLen = GetPrivateProfileString(s_cszInternetShortcutSection,
s_cszIconIndexKey,
EMPTY_STRING, rgchNewIconIndex,
sizeof(rgchNewIconIndex),
pcszFile);
if (dwcValueLen > 0)
{
int niIcon;
if (StrToIntEx(rgchNewIconIndex, 0, &niIcon))
{
// (+ 1) for null terminator.
*ppszIconFile = new(char[lstrlen(rgchNewIconFile) + 1]);
if (*ppszIconFile)
{
lstrcpy(*ppszIconFile, rgchNewIconFile);
*pniIcon = niIcon;
hr = S_OK;
}
else
hr = E_OUTOFMEMORY;
}
else
{
hr = S_FALSE;
WARNING_OUT(("ReadIconLocationFromFile(): Bad icon index \"%s\" found in file %s.",
rgchNewIconIndex,
pcszFile));
}
}
else
{
hr = S_FALSE;
WARNING_OUT(("ReadIconLocationFromFile(): No icon index found in file %s.",
pcszFile));
}
}
else
{
hr = S_FALSE;
TRACE_OUT(("ReadIconLocationFromFile(): No icon file found in file %s.",
pcszFile));
}
ASSERT(IsValidIconIndex(hr, *ppszIconFile, MAX_PATH_LEN, *pniIcon));
return(hr);
}
PRIVATE_CODE HRESULT WriteIconLocationToFile(PCSTR pcszFile,
PCSTR pcszIconFile,
int niIcon)
{
HRESULT hr;
ASSERT(IS_VALID_STRING_PTR(pcszFile, CSTR));
ASSERT(! pcszIconFile ||
IS_VALID_STRING_PTR(pcszIconFile, CSTR));
ASSERT(IsValidIconIndex((pcszIconFile ? S_OK : S_FALSE), pcszIconFile, MAX_PATH_LEN, niIcon));
if (AnyMeat(pcszIconFile))
{
char rgchIconIndexRHS[s_ucMaxIconIndexLen];
int ncLen;
ncLen = wsprintf(rgchIconIndexRHS, "%d", niIcon);
ASSERT(ncLen > 0);
ASSERT(ncLen < sizeof(rgchIconIndexRHS));
ASSERT(ncLen == lstrlen(rgchIconIndexRHS));
hr = (SHSetIniString(s_cszInternetShortcutSection,
s_cszIconFileKey, pcszIconFile,
pcszFile) &&
WritePrivateProfileString(s_cszInternetShortcutSection,
s_cszIconIndexKey, rgchIconIndexRHS,
pcszFile))
? S_OK
: E_FAIL;
}
else
hr = (SHDeleteIniString(s_cszInternetShortcutSection,
s_cszIconFileKey, pcszFile) &&
DeletePrivateProfileString(s_cszInternetShortcutSection,
s_cszIconIndexKey, pcszFile))
? S_OK
: E_FAIL;
return(hr);
}
PRIVATE_CODE HRESULT ReadHotkeyFromFile(PCSTR pcszFile, PWORD pwHotkey)
{
HRESULT hr = S_FALSE;
char rgchHotkey[s_ucMaxHotkeyLen];
DWORD dwcValueLen;
ASSERT(IS_VALID_STRING_PTR(pcszFile, CSTR));
ASSERT(IS_VALID_WRITE_PTR(pwHotkey, WORD));
*pwHotkey = 0;
dwcValueLen = GetPrivateProfileString(s_cszInternetShortcutSection,
s_cszHotkeyKey, EMPTY_STRING,
rgchHotkey, sizeof(rgchHotkey),
pcszFile);
if (dwcValueLen > 0)
{
UINT uHotkey;
if (StrToIntEx(rgchHotkey, 0, (int *)&uHotkey))
{
*pwHotkey = (WORD)uHotkey;
hr = S_OK;
}
else
WARNING_OUT(("ReadHotkeyFromFile(): Bad hotkey \"%s\" found in file %s.",
rgchHotkey,
pcszFile));
}
else
WARNING_OUT(("ReadHotkeyFromFile(): No hotkey found in file %s.",
pcszFile));
ASSERT((hr == S_OK &&
IsValidHotkey(*pwHotkey)) ||
(hr == S_FALSE &&
! *pwHotkey));
return(hr);
}
PRIVATE_CODE HRESULT WriteHotkeyToFile(PCSTR pcszFile, WORD wHotkey)
{
HRESULT hr;
ASSERT(IS_VALID_STRING_PTR(pcszFile, CSTR));
ASSERT(! wHotkey ||
IsValidHotkey(wHotkey));
if (wHotkey)
{
char rgchHotkeyRHS[s_ucMaxHotkeyLen];
int ncLen;
ncLen = wsprintf(rgchHotkeyRHS, "%u", (UINT)wHotkey);
ASSERT(ncLen > 0);
ASSERT(ncLen < sizeof(rgchHotkeyRHS));
ASSERT(ncLen == lstrlen(rgchHotkeyRHS));
hr = WritePrivateProfileString(s_cszInternetShortcutSection,
s_cszHotkeyKey, rgchHotkeyRHS,
pcszFile)
? S_OK
: E_FAIL;
}
else
hr = DeletePrivateProfileString(s_cszInternetShortcutSection,
s_cszHotkeyKey, pcszFile)
? S_OK
: E_FAIL;
return(hr);
}
PRIVATE_CODE HRESULT ReadWorkingDirectoryFromFile(PCSTR pcszFile,
PSTR *ppszWorkingDirectory)
{
HRESULT hr;
char rgchDirValue[MAX_PATH_LEN];
DWORD dwcValueLen;
ASSERT(IS_VALID_STRING_PTR(pcszFile, CSTR));
ASSERT(IS_VALID_WRITE_PTR(ppszWorkingDirectory, PSTR));
*ppszWorkingDirectory = NULL;
dwcValueLen = SHGetIniString(s_cszInternetShortcutSection,
s_cszWorkingDirectoryKey,
rgchDirValue,
sizeof(rgchDirValue), pcszFile);
if (dwcValueLen > 0)
{
char rgchFullPath[MAX_PATH_LEN];
PSTR pszFileName;
if (GetFullPathName(rgchDirValue, sizeof(rgchFullPath), rgchFullPath,
&pszFileName) > 0)
{
// (+ 1) for null terminator.
*ppszWorkingDirectory = new(char[lstrlen(rgchFullPath) + 1]);
if (*ppszWorkingDirectory)
{
lstrcpy(*ppszWorkingDirectory, rgchFullPath);
hr = S_OK;
}
else
hr = E_OUTOFMEMORY;
}
else
hr = E_FAIL;
}
else
{
hr = S_FALSE;
TRACE_OUT(("ReadWorkingDirectoryFromFile: No working directory found in file %s.",
pcszFile));
}
ASSERT(IsValidPathResult(hr, *ppszWorkingDirectory, MAX_PATH_LEN));
return(hr);
}
PRIVATE_CODE HRESULT WriteWorkingDirectoryToFile(PCSTR pcszFile,
PCSTR pcszWorkingDirectory)
{
HRESULT hr;
ASSERT(IS_VALID_STRING_PTR(pcszFile, CSTR));
ASSERT(! pcszWorkingDirectory ||
IS_VALID_STRING_PTR(pcszWorkingDirectory, CSTR));
if (AnyMeat(pcszWorkingDirectory))
hr = (SHSetIniString(s_cszInternetShortcutSection,
s_cszWorkingDirectoryKey,
pcszWorkingDirectory, pcszFile))
? S_OK
: E_FAIL;
else
hr = (SHDeleteIniString(s_cszInternetShortcutSection,
s_cszWorkingDirectoryKey, pcszFile))
? S_OK
: E_FAIL;
return(hr);
}
PRIVATE_CODE HRESULT ReadShowCmdFromFile(PCSTR pcszFile, PINT pnShowCmd)
{
HRESULT hr;
char rgchNewShowCmd[s_ucMaxShowCmdLen];
DWORD dwcValueLen;
ASSERT(IS_VALID_STRING_PTR(pcszFile, CSTR));
ASSERT(IS_VALID_WRITE_PTR(pnShowCmd, INT));
*pnShowCmd = g_nDefaultShowCmd;
dwcValueLen = GetPrivateProfileString(s_cszInternetShortcutSection,
s_cszShowCmdKey, EMPTY_STRING,
rgchNewShowCmd,
sizeof(rgchNewShowCmd), pcszFile);
if (dwcValueLen > 0)
{
int nShowCmd;
if (StrToIntEx(rgchNewShowCmd, 0, &nShowCmd))
{
*pnShowCmd = nShowCmd;
hr = S_OK;
}
else
{
hr = S_FALSE;
WARNING_OUT(("ReadShowCmdFromFile: Invalid show command \"%s\" found in file %s.",
rgchNewShowCmd,
pcszFile));
}
}
else
{
hr = S_FALSE;
TRACE_OUT(("ReadShowCmdFromFile: No show command found in file %s.",
pcszFile));
}
ASSERT((hr == S_OK &&
EVAL(IsValidShowCmd(*pnShowCmd))) ||
(hr == S_FALSE &&
EVAL(*pnShowCmd == g_nDefaultShowCmd)));
return(hr);
}
PRIVATE_CODE HRESULT WriteShowCmdToFile(PCSTR pcszFile, int nShowCmd)
{
HRESULT hr;
ASSERT(IS_VALID_STRING_PTR(pcszFile, CSTR));
ASSERT(IsValidShowCmd(nShowCmd));
if (nShowCmd != g_nDefaultShowCmd)
{
char rgchShowCmdRHS[s_ucMaxShowCmdLen];
int ncLen;
ncLen = wsprintf(rgchShowCmdRHS, "%d", nShowCmd);
ASSERT(ncLen > 0);
ASSERT(ncLen < sizeof(rgchShowCmdRHS));
ASSERT(ncLen == lstrlen(rgchShowCmdRHS));
hr = (WritePrivateProfileString(s_cszInternetShortcutSection,
s_cszShowCmdKey, rgchShowCmdRHS,
pcszFile))
? S_OK
: E_FAIL;
}
else
hr = (DeletePrivateProfileString(s_cszInternetShortcutSection,
s_cszShowCmdKey, pcszFile))
? S_OK
: E_FAIL;
return(hr);
}
/****************************** Public Functions *****************************/
PUBLIC_CODE HRESULT UnicodeToANSI(LPCOLESTR pcwszUnicode, PSTR *ppszANSI)
{
HRESULT hr;
int ncbLen;
// FEATURE: Need OLESTR validation function to validate pcwszUnicode here.
ASSERT(IS_VALID_WRITE_PTR(ppszANSI, PSTR));
*ppszANSI = NULL;
// Get length of translated string.
ncbLen = WideCharToMultiByte(CP_ACP, 0, pcwszUnicode, -1, NULL, 0, NULL,
NULL);
if (ncbLen > 0)
{
PSTR pszNewANSI;
// (+ 1) for null terminator.
pszNewANSI = new(char[ncbLen]);
if (pszNewANSI)
{
// Translate string.
if (WideCharToMultiByte(CP_ACP, 0, pcwszUnicode, -1, pszNewANSI,
ncbLen, NULL, NULL) > 0)
{
*ppszANSI = pszNewANSI;
hr = S_OK;
}
else
{
delete pszNewANSI;
pszNewANSI = NULL;
hr = E_UNEXPECTED;
WARNING_OUT(("UnicodeToANSI(): Failed to translate Unicode string to ANSI."));
}
}
else
hr = E_OUTOFMEMORY;
}
else
{
hr = E_UNEXPECTED;
WARNING_OUT(("UnicodeToANSI(): Failed to get length of translated ANSI string."));
}
ASSERT(FAILED(hr) ||
IS_VALID_STRING_PTR(*ppszANSI, STR));
return(hr);
}
PUBLIC_CODE HRESULT ANSIToUnicode(PCSTR pcszANSI, LPOLESTR *ppwszUnicode)
{
HRESULT hr;
int ncbWideLen;
ASSERT(IS_VALID_STRING_PTR(pcszANSI, CSTR));
ASSERT(IS_VALID_WRITE_PTR(ppwszUnicode, LPOLESTR));
*ppwszUnicode = NULL;
// Get length of translated string.
ncbWideLen = MultiByteToWideChar(CP_ACP, 0, pcszANSI, -1, NULL, 0);
if (ncbWideLen > 0)
{
PWSTR pwszNewUnicode;
// (+ 1) for null terminator.
pwszNewUnicode = new(WCHAR[ncbWideLen]);
if (pwszNewUnicode)
{
// Translate string.
if (MultiByteToWideChar(CP_ACP, 0, pcszANSI, -1, pwszNewUnicode,
ncbWideLen) > 0)
{
*ppwszUnicode = pwszNewUnicode;
hr = S_OK;
}
else
{
delete pwszNewUnicode;
pwszNewUnicode = NULL;
hr = E_UNEXPECTED;
WARNING_OUT(("ANSIToUnicode(): Failed to translate ANSI path string to Unicode."));
}
}
else
hr = E_OUTOFMEMORY;
}
else
{
hr = E_UNEXPECTED;
WARNING_OUT(("ANSIToUnicode(): Failed to get length of translated Unicode string."));
}
// FEATURE: Need OLESTR validation function to validate *ppwszUnicode here.
return(hr);
}
/********************************** Methods **********************************/
HRESULT STDMETHODCALLTYPE InternetShortcut::SaveToFile(PCSTR pcszFile,
BOOL bRemember)
{
HRESULT hr;
PSTR pszURL;
DebugEntry(InternetShortcut::SaveToFile);
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
ASSERT(IS_VALID_STRING_PTR(pcszFile, CSTR));
hr = GetURL(&pszURL);
if (SUCCEEDED(hr))
{
hr = WriteURLToFile(pcszFile, pszURL);
if (pszURL)
{
SHFree(pszURL);
pszURL = NULL;
}
if (hr == S_OK)
{
char rgchBuf[MAX_PATH_LEN];
int niIcon;
hr = GetIconLocation(rgchBuf, sizeof(rgchBuf), &niIcon);
if (SUCCEEDED(hr))
{
hr = WriteIconLocationToFile(pcszFile, rgchBuf, niIcon);
if (hr == S_OK)
{
WORD wHotkey;
hr = GetHotkey(&wHotkey);
if (SUCCEEDED(hr))
{
hr = WriteHotkeyToFile(pcszFile, wHotkey);
if (hr == S_OK)
{
hr = GetWorkingDirectory(rgchBuf, sizeof(rgchBuf));
if (SUCCEEDED(hr))
{
hr = WriteWorkingDirectoryToFile(pcszFile, rgchBuf);
if (hr == S_OK)
{
int nShowCmd;
GetShowCmd(&nShowCmd);
hr = WriteShowCmdToFile(pcszFile, nShowCmd);
if (hr == S_OK)
{
/* Remember file if requested. */
if (bRemember)
{
PSTR pszFileCopy;
if (StringCopy(pcszFile, &pszFileCopy))
{
if (m_pszFile)
delete m_pszFile;
m_pszFile = pszFileCopy;
TRACE_OUT(("InternetShortcut::SaveToFile(): Remembering file %s, as requested.",
m_pszFile));
}
else
hr = E_OUTOFMEMORY;
}
if (hr == S_OK)
{
Dirty(FALSE);
SHChangeNotify(SHCNE_UPDATEITEM,
(SHCNF_PATH | SHCNF_FLUSH), pcszFile,
NULL);
#ifdef DEBUG
TRACE_OUT(("InternetShortcut::SaveToFile(): Internet Shortcut saved to file %s:",
pcszFile));
Dump();
#endif
}
}
}
}
}
}
}
}
}
}
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
DebugExitHRESULT(InternetShortcut::SaveToFile, hr);
return(hr);
}
HRESULT STDMETHODCALLTYPE InternetShortcut::LoadFromFile(PCSTR pcszFile,
BOOL bRemember)
{
HRESULT hr;
PSTR pszURL;
DebugEntry(InternetShortcut::LoadFromFile);
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
ASSERT(IS_VALID_STRING_PTR(pcszFile, CSTR));
hr = ReadURLFromFile(pcszFile, &pszURL);
if (SUCCEEDED(hr))
{
hr = SetURL(pszURL, (IURL_SETURL_FL_GUESS_PROTOCOL |
IURL_SETURL_FL_USE_DEFAULT_PROTOCOL));
if (pszURL)
{
delete pszURL;
pszURL = NULL;
}
if (hr == S_OK)
{
PSTR pszIconFile;
int niIcon;
hr = ReadIconLocationFromFile(pcszFile, &pszIconFile, &niIcon);
if (SUCCEEDED(hr))
{
hr = SetIconLocation(pszIconFile, niIcon);
if (pszIconFile)
{
delete pszIconFile;
pszIconFile = NULL;
}
if (hr == S_OK)
{
WORD wHotkey;
hr = ReadHotkeyFromFile(pcszFile, &wHotkey);
if (SUCCEEDED(hr))
{
hr = SetHotkey(wHotkey);
if (hr == S_OK)
{
PSTR pszWorkingDirectory;
hr = ReadWorkingDirectoryFromFile(pcszFile,
&pszWorkingDirectory);
if (SUCCEEDED(hr))
{
hr = SetWorkingDirectory(pszWorkingDirectory);
if (pszWorkingDirectory)
{
delete pszWorkingDirectory;
pszWorkingDirectory = NULL;
}
if (hr == S_OK)
{
int nShowCmd;
hr = ReadShowCmdFromFile(pcszFile, &nShowCmd);
if (SUCCEEDED(hr))
{
/* Remember file if requested. */
if (bRemember)
{
PSTR pszFileCopy;
if (StringCopy(pcszFile, &pszFileCopy))
{
if (m_pszFile)
delete m_pszFile;
m_pszFile = pszFileCopy;
TRACE_OUT(("InternetShortcut::LoadFromFile(): Remembering file %s, as requested.",
m_pszFile));
}
else
hr = E_OUTOFMEMORY;
}
if (SUCCEEDED(hr))
{
SetShowCmd(nShowCmd);
Dirty(FALSE);
hr = S_OK;
#ifdef DEBUG
TRACE_OUT(("InternetShortcut::LoadFromFile(): Internet Shortcut loaded from file %s:",
pcszFile));
Dump();
#endif
}
}
}
}
}
}
}
}
}
}
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
DebugExitHRESULT(InternetShortcut::LoadFromFile, hr);
return(hr);
}
HRESULT STDMETHODCALLTYPE InternetShortcut::GetCurFile(PSTR pszFile,
UINT ucbLen)
{
HRESULT hr;
DebugEntry(InternetShortcut::GetCurFile);
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszFile, STR, ucbLen));
if (m_pszFile)
{
lstrcpyn(pszFile, m_pszFile, ucbLen);
TRACE_OUT(("InternetShortcut::GetCurFile(): Current file name is %s.",
pszFile));
hr = S_OK;
}
else
hr = S_FALSE;
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
ASSERT(IS_VALID_STRING_PTR(pszFile, STR) &&
EVAL((UINT)lstrlen(pszFile) < ucbLen));
ASSERT(hr == S_OK ||
hr == S_FALSE);
DebugExitHRESULT(InternetShortcut::GetCurFile, hr);
return(hr);
}
HRESULT STDMETHODCALLTYPE InternetShortcut::Dirty(BOOL bDirty)
{
HRESULT hr;
DebugEntry(InternetShortcut::Dirty);
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
if (bDirty)
{
if (IS_FLAG_CLEAR(m_dwFlags, INTSHCUT_FL_DIRTY)) {
TRACE_OUT(("InternetShortcut::Dirty(): Now dirty."));
}
SET_FLAG(m_dwFlags, INTSHCUT_FL_DIRTY);
}
else
{
if (IS_FLAG_SET(m_dwFlags, INTSHCUT_FL_DIRTY)) {
TRACE_OUT(("InternetShortcut::Dirty(): Now clean."));
}
CLEAR_FLAG(m_dwFlags, INTSHCUT_FL_DIRTY);
}
hr = S_OK;
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
ASSERT(hr == S_OK);
DebugExitVOID(InternetShortcut::Dirty);
return(hr);
}
HRESULT STDMETHODCALLTYPE InternetShortcut::GetClassID(PCLSID pclsid)
{
HRESULT hr;
DebugEntry(InternetShortcut::GetClassID);
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
ASSERT(IS_VALID_STRUCT_PTR(pclsid, CCLSID));
*pclsid = CLSID_InternetShortcut;
hr = S_OK;
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
ASSERT(FAILED(hr) ||
IS_VALID_STRUCT_PTR(pclsid, CCLSID));
DebugExitHRESULT(InternetShortcut::GetClassID, hr);
return(hr);
}
HRESULT STDMETHODCALLTYPE InternetShortcut::IsDirty(void)
{
HRESULT hr;
DebugEntry(InternetShortcut::IsDirty);
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
if (IS_FLAG_SET(m_dwFlags, INTSHCUT_FL_DIRTY))
hr = S_OK;
else
hr = S_FALSE;
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
DebugExitHRESULT(InternetShortcut::IsDirty, hr);
return(hr);
}
HRESULT STDMETHODCALLTYPE InternetShortcut::Save(LPCOLESTR pcwszFile,
BOOL bRemember)
{
HRESULT hr;
PSTR pszFile;
DebugEntry(InternetShortcut::Save);
// bRemember may be any value.
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
// FEATURE: Need OLESTR validation function to validate pcwszFile here.
if (pcwszFile)
{
hr = UnicodeToANSI(pcwszFile, &pszFile);
if (hr == S_OK)
{
hr = SaveToFile(pszFile, bRemember);
delete pszFile;
pszFile = NULL;
}
}
else if (m_pszFile)
// Ignore bRemember.
hr = SaveToFile(m_pszFile, FALSE);
else
hr = E_FAIL;
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
DebugExitHRESULT(InternetShortcut::Save, hr);
return(hr);
}
#pragma warning(disable:4100) /* "unreferenced formal parameter" warning */
HRESULT STDMETHODCALLTYPE InternetShortcut::SaveCompleted(LPCOLESTR pcwszFile)
{
HRESULT hr;
DebugEntry(InternetShortcut::SaveCompleted);
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
// FEATURE: Need OLESTR validation function to validate pcwszFile here.
hr = S_OK;
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
DebugExitHRESULT(InternetShortcut::SaveCompleted, hr);
return(hr);
}
HRESULT STDMETHODCALLTYPE InternetShortcut::Load(LPCOLESTR pcwszFile,
DWORD dwMode)
{
HRESULT hr;
PSTR pszFile;
DebugEntry(InternetShortcut::Load);
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
// FEATURE: Need OLESTR validation function to validate pcwszFile here.
// FEATURE: Validate dwMode here.
// FEAUTRE: Implement dwMode flag support.
hr = UnicodeToANSI(pcwszFile, &pszFile);
if (hr == S_OK)
{
hr = LoadFromFile(pszFile, TRUE);
delete pszFile;
pszFile = NULL;
}
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
DebugExitHRESULT(InternetShortcut::Load, hr);
return(hr);
}
#pragma warning(default:4100) /* "unreferenced formal parameter" warning */
HRESULT STDMETHODCALLTYPE InternetShortcut::GetCurFile(LPOLESTR *ppwszFile)
{
HRESULT hr;
LPOLESTR pwszTempFile;
DebugEntry(InternetShortcut::GetCurFile);
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
ASSERT(IS_VALID_WRITE_PTR(ppwszFile, LPOLESTR));
if (m_pszFile)
{
hr = ANSIToUnicode(m_pszFile, &pwszTempFile);
if (hr == S_OK) {
TRACE_OUT(("InternetShortcut::GetCurFile(): Current file name is %s.",
m_pszFile));
}
}
else
{
hr = ANSIToUnicode(g_cszURLDefaultFileNamePrompt, &pwszTempFile);
if (hr == S_OK)
{
hr = S_FALSE;
TRACE_OUT(("InternetShortcut::GetCurFile(): No current file name. Returning default file name prompt %s.",
g_cszURLDefaultFileNamePrompt));
}
}
if (SUCCEEDED(hr))
{
// We should really call OleGetMalloc() to get the process IMalloc here.
// Use SHAlloc() here instead to avoid loading ole32.dll.
// SHAlloc() / SHFree() turn in to IMalloc::Alloc() and IMalloc::Free()
// once ole32.dll is loaded.
// N.b., lstrlenW() returns the length of the given string in characters,
// not bytes.
// (+ 1) for null terminator.
*ppwszFile = (LPOLESTR)SHAlloc((lstrlenW(pwszTempFile) + 1) *
sizeof(*pwszTempFile));
if (*ppwszFile)
lstrcpyW(*ppwszFile, pwszTempFile);
else
hr = E_OUTOFMEMORY;
delete pwszTempFile;
pwszTempFile = NULL;
}
// FEATURE: Need OLESTR validation function to validate *ppwszFile here.
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
DebugExitHRESULT(InternetShortcut::GetCurFile, hr);
return(hr);
}
#pragma warning(disable:4100) /* "unreferenced formal parameter" warning */
HRESULT STDMETHODCALLTYPE InternetShortcut::Load(PIStream pistr)
{
HRESULT hr;
DebugEntry(InternetShortcut::Load);
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
ASSERT(IS_VALID_INTERFACE_PTR(pistr, IStream));
hr = E_NOTIMPL;
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
DebugExitHRESULT(InternetShortcut::Load, hr);
return(hr);
}
HRESULT STDMETHODCALLTYPE InternetShortcut::Save(PIStream pistr,
BOOL bClearDirty)
{
HRESULT hr;
DebugEntry(InternetShortcut::Save);
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
ASSERT(IS_VALID_INTERFACE_PTR(pistr, IStream));
// APPCOMPAT: Yes, this is an awful hack, but that's what we get when
// no one implements a needed interface and we need to get a product
// shipped. (Actually, the hack isn't that bad, as it's what happens in
// TransferFileContents, except we're writing to a stream and not memory).
const static TCHAR s_cszNewLine[] = TEXT("\r\n");
const static TCHAR s_cszPrefix[] = TEXT("[InternetShortcut]\r\nURL=");
LPTSTR pszBuf;
DWORD cb;
pszBuf = (LPTSTR)LocalAlloc(LPTR, lstrlen(m_pszURL) + lstrlen(s_cszPrefix) + lstrlen(s_cszNewLine) + 1);
if (pszBuf)
{
wsprintf(pszBuf, TEXT("%s%s%s"), s_cszPrefix, m_pszURL ? m_pszURL : TEXT("") , s_cszNewLine);
hr = pistr->Write(pszBuf, lstrlen(pszBuf), &cb);
LocalFree(pszBuf);
}
else
{
hr = E_OUTOFMEMORY;
}
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
DebugExitHRESULT(InternetShortcut::Save, hr);
return(hr);
}
HRESULT STDMETHODCALLTYPE InternetShortcut::GetSizeMax(PULARGE_INTEGER pcbSize)
{
HRESULT hr;
DebugEntry(InternetShortcut::GetSizeMax);
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
ASSERT(IS_VALID_WRITE_PTR(pcbSize, ULARGE_INTEGER));
hr = E_NOTIMPL;
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
DebugExitHRESULT(InternetShortcut::GetSizeMax, hr);
return(hr);
}
#pragma warning(default:4100) /* "unreferenced formal parameter" warning */
DWORD STDMETHODCALLTYPE InternetShortcut::GetFileContentsSize(void)
{
DWORD dwcbLen;
DebugEntry(InternetShortcut::GetFileContentsSize);
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
// Section length.
// (- 1) for each null terminator.
HRESULT hr = CreateURLFileContents(m_pszURL, NULL);
// REARCHITECT: (DavidDi 3/29/95) We need to save more than just the URL string
// here, i.e., icon file and index, working directory, and show command.
dwcbLen = SUCCEEDED(hr) ? hr : 0;
dwcbLen++; // + 1 for final null terminator
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
DebugExitDWORD(InternetShortcut::GetFileContentsSize, dwcbLen);
return(dwcbLen);
}
HRESULT STDMETHODCALLTYPE InternetShortcut::TransferUniformResourceLocator(
PFORMATETC pfmtetc,
PSTGMEDIUM pstgmed)
{
HRESULT hr;
DebugEntry(InternetShortcut::TransferUniformResourceLocator);
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
ASSERT(IS_VALID_STRUCT_PTR(pfmtetc, CFORMATETC));
ASSERT(IS_VALID_WRITE_PTR(pstgmed, STGMEDIUM));
ASSERT(pfmtetc->dwAspect == DVASPECT_CONTENT);
ASSERT(pfmtetc->lindex == -1);
ZeroMemory(pstgmed, sizeof(*pstgmed));
if (IS_FLAG_SET(pfmtetc->tymed, TYMED_HGLOBAL))
{
if (m_pszURL)
{
HGLOBAL hgURL;
hr = E_OUTOFMEMORY;
// (+ 1) for null terminator.
hgURL = GlobalAlloc(0, lstrlen(m_pszURL) + 1);
if (hgURL)
{
PSTR pszURL;
pszURL = (PSTR)GlobalLock(hgURL);
if (EVAL(pszURL))
{
lstrcpy(pszURL, m_pszURL);
pstgmed->tymed = TYMED_HGLOBAL;
pstgmed->hGlobal = hgURL;
ASSERT(! pstgmed->pUnkForRelease);
hr = S_OK;
GlobalUnlock(hgURL);
pszURL = NULL;
}
if (hr != S_OK)
{
GlobalFree(hgURL);
hgURL = NULL;
}
}
}
else
hr = DV_E_FORMATETC;
}
else
hr = DV_E_TYMED;
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
ASSERT((hr == S_OK &&
IS_VALID_STRUCT_PTR(pstgmed, CSTGMEDIUM)) ||
(FAILED(hr) &&
(EVAL(pstgmed->tymed == TYMED_NULL) &&
EVAL(! pstgmed->hGlobal) &&
EVAL(! pstgmed->pUnkForRelease))));
DebugExitHRESULT(InternetShortcut::TransferUniformResourceLocator, hr);
return(hr);
}
HRESULT STDMETHODCALLTYPE InternetShortcut::TransferText(PFORMATETC pfmtetc,
PSTGMEDIUM pstgmed)
{
HRESULT hr;
DebugEntry(InternetShortcut::TransferText);
// Assume InternetShortcut::TransferUniformResourceLocator() will perform
// input and output validation.
hr = TransferUniformResourceLocator(pfmtetc, pstgmed);
DebugExitHRESULT(InternetShortcut::TransferText, hr);
return(hr);
}
HRESULT STDMETHODCALLTYPE InternetShortcut::TransferFileGroupDescriptor(
PFORMATETC pfmtetc,
PSTGMEDIUM pstgmed)
{
HRESULT hr;
DebugEntry(InternetShortcut::TransferFileGroupDescriptor);
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
ASSERT(IS_VALID_STRUCT_PTR(pfmtetc, CFORMATETC));
ASSERT(IS_VALID_WRITE_PTR(pstgmed, STGMEDIUM));
ASSERT(pfmtetc->dwAspect == DVASPECT_CONTENT);
ASSERT(pfmtetc->lindex == -1);
pstgmed->tymed = TYMED_NULL;
pstgmed->hGlobal = NULL;
pstgmed->pUnkForRelease = NULL;
if (IS_FLAG_SET(pfmtetc->tymed, TYMED_HGLOBAL))
{
HGLOBAL hgFileGroupDesc;
hr = E_OUTOFMEMORY;
hgFileGroupDesc = GlobalAlloc(GMEM_ZEROINIT,
sizeof(FILEGROUPDESCRIPTOR));
if (hgFileGroupDesc)
{
PFILEGROUPDESCRIPTOR pfgd;
pfgd = (PFILEGROUPDESCRIPTOR)GlobalLock(hgFileGroupDesc);
if (EVAL(pfgd))
{
PFILEDESCRIPTOR pfd = &(pfgd->fgd[0]);
// Do we already have a file name to use?
if (m_pszFile)
{
lstrcpyn(pfd->cFileName, ExtractFileName(m_pszFile),
SIZECHARS(pfd->cFileName));
hr = S_OK;
}
else
{
if (EVAL(MLLoadStringA(
IDS_NEW_INTERNET_SHORTCUT, pfd->cFileName,
sizeof(pfd->cFileName))))
hr = S_OK;
}
if (hr == S_OK)
{
pfd->dwFlags = (FD_FILESIZE |
FD_LINKUI);
pfd->nFileSizeHigh = 0;
pfd->nFileSizeLow = GetFileContentsSize();
pfgd->cItems = 1;
pstgmed->tymed = TYMED_HGLOBAL;
pstgmed->hGlobal = hgFileGroupDesc;
ASSERT(! pstgmed->pUnkForRelease);
}
GlobalUnlock(hgFileGroupDesc);
pfgd = NULL;
}
if (hr != S_OK)
{
GlobalFree(hgFileGroupDesc);
hgFileGroupDesc = NULL;
}
}
}
else
hr = DV_E_TYMED;
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
ASSERT((hr == S_OK &&
IS_VALID_STRUCT_PTR(pstgmed, CSTGMEDIUM)) ||
(FAILED(hr) &&
(EVAL(pstgmed->tymed == TYMED_NULL) &&
EVAL(! pstgmed->hGlobal) &&
EVAL(! pstgmed->pUnkForRelease))));
DebugExitHRESULT(InternetShortcut::TransferFileGroupDescriptor, hr);
return(hr);
}
HRESULT STDMETHODCALLTYPE InternetShortcut::TransferFileContents(
PFORMATETC pfmtetc,
PSTGMEDIUM pstgmed)
{
HRESULT hr;
DebugEntry(InternetShortcut::TransferFileContents);
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
ASSERT(IS_VALID_STRUCT_PTR(pfmtetc, CFORMATETC));
ASSERT(IS_VALID_WRITE_PTR(pstgmed, STGMEDIUM));
ASSERT(pfmtetc->dwAspect == DVASPECT_CONTENT);
ASSERT(! pfmtetc->lindex);
pstgmed->tymed = TYMED_NULL;
pstgmed->hGlobal = NULL;
pstgmed->pUnkForRelease = NULL;
if (IS_FLAG_SET(pfmtetc->tymed, TYMED_HGLOBAL))
{
HGLOBAL hgFileContents;
hr = CreateURLFileContents(m_pszURL, (LPSTR *)&hgFileContents);
if (SUCCEEDED(hr))
{
// Note some apps don't pay attention to the nFileSizeLow
// field; fortunately, CreateURLFileContents adds a final
// null terminator to prevent trailing garbage.
pstgmed->tymed = TYMED_HGLOBAL;
pstgmed->hGlobal = hgFileContents;
ASSERT(! pstgmed->pUnkForRelease);
hr = S_OK;
}
else
hr = E_OUTOFMEMORY;
}
else
hr = DV_E_TYMED;
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
ASSERT((hr == S_OK &&
IS_VALID_STRUCT_PTR(pstgmed, CSTGMEDIUM)) ||
(FAILED(hr) &&
(EVAL(pstgmed->tymed == TYMED_NULL) &&
EVAL(! pstgmed->hGlobal) &&
EVAL(! pstgmed->pUnkForRelease))));
DebugExitHRESULT(InternetShortcut::TransferFileContents, hr);
return(hr);
}
#ifdef DEBUG
void STDMETHODCALLTYPE InternetShortcut::Dump(void)
{
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
PLAIN_TRACE_OUT(("%sm_dwFlags = %#08lx",
INDENT_STRING,
m_dwFlags));
PLAIN_TRACE_OUT(("%sm_pszFile = \"%s\"",
INDENT_STRING,
CHECK_STRING(m_pszFile)));
PLAIN_TRACE_OUT(("%sm_pszURL = \"%s\"",
INDENT_STRING,
CHECK_STRING(m_pszURL)));
PLAIN_TRACE_OUT(("%sm_pszIconFile = \"%s\"",
INDENT_STRING,
CHECK_STRING(m_pszIconFile)));
PLAIN_TRACE_OUT(("%sm_niIcon = %d",
INDENT_STRING,
m_niIcon));
PLAIN_TRACE_OUT(("%sm_wHotkey = %#04x",
INDENT_STRING,
(UINT)m_wHotkey));
PLAIN_TRACE_OUT(("%sm_pszWorkingDirectory = \"%s\"",
INDENT_STRING,
CHECK_STRING(m_pszWorkingDirectory)));
PLAIN_TRACE_OUT(("%sm_nShowCmd = %d",
INDENT_STRING,
m_nShowCmd));
return;
}
#endif