1602 lines
41 KiB
C++
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
|