Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1343 lines
33 KiB

/*
* dataobjm.cpp - IDataObject implementation for MSMosaic.
*/
/* Headers
**********/
#include "project.hpp"
#pragma hdrstop
#include <intshcut.h>
#include "blob.h"
#include "dataobjm.h"
#include "gendatao.hpp"
#include "history.h"
#include "htmlutil.h"
#include "mci.h"
#include "w_pal.h"
/* Types
********/
typedef HRESULT (*DATACONSTRUCTORPROC)(PIDataObject pido, PCMWIN pcmwin, int iElem);
typedef struct dataconstructor
{
// drop effects offered
DWORD dwAvailEffects;
// data constructor
DATACONSTRUCTORPROC dcp;
}
DATACONSTRUCTOR;
DECLARE_STANDARD_TYPES(DATACONSTRUCTOR);
typedef struct elemtypedataconstructor
{
// element type
UCHAR uchElemType;
// data constructor for element type
DATACONSTRUCTOR dc;
}
ELEMTYPEDATACONSTRUCTOR;
DECLARE_STANDARD_TYPES(ELEMTYPEDATACONSTRUCTOR);
/* Global Variables
*******************/
/* registered clipboard formats */
PUBLIC_DATA UINT g_cfURL = 0;
PUBLIC_DATA UINT g_cfFileGroupDescriptor = 0;
PUBLIC_DATA UINT g_cfFileContents = 0;
/* Module Constants
*******************/
#pragma data_seg(DATA_SEG_READ_ONLY)
// data format allocation parameters
PRIVATE_DATA CULONG s_culcInitialFormats = 0;
PRIVATE_DATA CULONG s_culcFormatAllocGranularity = 8;
#pragma data_seg()
/* Module Prototypes
********************/
PRIVATE_CODE HRESULT ImageDataConstructor(PIDataObject pido, PCMWIN pcmwin, int iElem);
/* Module Variables
*******************/
#pragma data_seg(DATA_SEG_READ_ONLY)
PRIVATE_DATA char s_szURLCF[] = "UniformResourceLocator";
PRIVATE_DATA char s_szFileDescriptorCF[] = CFSTR_FILEDESCRIPTOR;
PRIVATE_DATA char s_szFileContentsCF[] = CFSTR_FILECONTENTS;
#pragma data_seg()
PRIVATE_DATA ELEMTYPEDATACONSTRUCTOR s_rgetdc[] =
{
{ ELE_IMAGE, { DROPEFFECT_COPY, &ImageDataConstructor } },
{ ELE_FORMIMAGE, { DROPEFFECT_COPY, &ImageDataConstructor } }
};
/***************************** Private Functions *****************************/
#ifdef DEBUG
PRIVATE_CODE BOOL IsValidPCDATACONSTRUCTOR(PCDATACONSTRUCTOR pcdc)
{
return(IS_VALID_READ_PTR(pcdc, CDATACONSTRUCTOR) &&
FLAGS_ARE_VALID(pcdc->dwAvailEffects, ALL_DROPEFFECT_FLAGS) &&
IS_VALID_CODE_PTR(pcdc->dcp, DATACONSTRUCTORPROC));
}
PRIVATE_CODE BOOL IsValidPCELEMTYPEDATACONSTRUCTOR(
PCELEMTYPEDATACONSTRUCTOR pcetdc)
{
return(IS_VALID_READ_PTR(pcetdc, CELEMTYPEDATACONSTRUCTOR) &&
EVAL(IsValidElementType(pcetdc->uchElemType)) &&
IS_VALID_STRUCT_PTR(&(pcetdc->dc), CDATACONSTRUCTOR));
}
#endif
PRIVATE_CODE ULONG GetLengthOfStringList(PCSTR rgpcsz[], ULONG ulcStrings)
{
ULONG ulcbLen = 0;
ULONG ul;
ASSERT(IS_VALID_READ_BUFFER_PTR(rgpcsz, PCSTR, ulcStrings * sizeof(rgpcsz[0])));
for (ul = 0; ul < ulcStrings; ul++)
{
ASSERT(IS_VALID_STRING_PTR(rgpcsz[ul], CSTR));
// (+ 1) for null terminator.
ulcbLen += lstrlen(rgpcsz[ul]) + 1;
}
// Account for no strings.
if (! ulcStrings)
ulcbLen++;
// Double null terminate.
ulcbLen++;
return(ulcbLen);
}
PRIVATE_CODE HRESULT GetDataConstructorFromElementType(
CHAR uchElemType,
PCDATACONSTRUCTOR *ppcdc)
{
HRESULT hr = S_FALSE;
int i;
ASSERT(IsValidElementType(uchElemType));
ASSERT(IS_VALID_WRITE_PTR(ppcdc, PCDATACONSTRUCTOR));
*ppcdc = NULL;
for (i = 0; i < ARRAY_ELEMENTS(s_rgetdc); i++)
{
ASSERT(IS_VALID_STRUCT_PTR(&(s_rgetdc[i]), CELEMTYPEDATACONSTRUCTOR));
if (s_rgetdc[i].uchElemType == uchElemType)
{
*ppcdc = &(s_rgetdc[i].dc);
hr = S_OK;
break;
}
}
ASSERT((hr == S_OK &&
IS_VALID_STRUCT_PTR(*ppcdc, CDATACONSTRUCTOR)) ||
(hr == S_FALSE &&
! *ppcdc));
return(hr);
}
PRIVATE_CODE HRESULT CreateDataObject(PIDataObject *ppido)
{
HRESULT hr;
PGenDataObject pgendo;
ASSERT(IS_VALID_WRITE_PTR(ppido, PIDataObject));
pgendo = new(GenDataObject(s_culcInitialFormats,
s_culcFormatAllocGranularity));
if (pgendo)
{
hr = pgendo->Status();
if (hr == S_OK)
*ppido = pgendo;
else
{
ASSERT(FAILED(hr));
delete pgendo;
pgendo = NULL;
}
}
else
hr = E_OUTOFMEMORY;
ASSERT((hr == S_OK &&
IS_VALID_INTERFACE_PTR(*ppido, IDataObject)) ||
(FAILED(hr) &&
! *ppido));
return(hr);
}
PRIVATE_CODE HRESULT LinkDataObjectConstructor(PCMWIN pcmwin, int iElem,
PIDataObject *ppido)
{
HRESULT hr;
PCELEMENT pcelem;
PIUniformResourceLocator piurl;
ASSERT(IS_VALID_STRUCT_PTR(pcmwin, CMWIN));
ASSERT(IsValidElementIndex(pcmwin, iElem));
ASSERT(IS_VALID_WRITE_PTR(ppido, PIDataObject));
pcelem = &(pcmwin->w3doc->aElements[iElem]);
ASSERT(IS_FLAG_SET(pcelem->lFlags, ELEFLAG_ANCHOR));
hr = SHCoCreateInstance(NULL, &CLSID_InternetShortcut, NULL,
IID_IUniformResourceLocator, (PVOID *)&piurl);
if (hr == S_OK)
{
PSTR pszURL;
hr = GetURLFromHREF(pcmwin, iElem, &pszURL);
if (hr == S_OK)
{
hr = piurl->SetURL(pszURL, 0);
if (hr == S_OK)
{
PIShellLink pisl;
hr = piurl->QueryInterface(IID_IShellLink, (PVOID *)&pisl);
if (hr == S_OK)
{
PSTR pszName;
hr = GetElementText(pcmwin, iElem, &pszName);
// BUGBUG: (DavidDi 3/31/95) The element text may contain
// invalid file name characters. We need to strip them out
// before calling SetDescription().
if (hr == S_OK || hr == S_FALSE)
{
char rgchFileName[MAX_PATH_LEN];
TrimWhiteSpace(pszName);
if (GetNewShortcutFilename(
pszURL,
(pszName && *pszName) ? pszName : NULL,
rgchFileName,
NULL,
FOLDER_NONE,
(NEWSHORTCUT_FL_NO_HOST_PATH |
NEWSHORTCUT_FL_ALLOW_DUPLICATE_URL))
== S_OK)
{
ASSERT(IS_VALID_STRING_PTR(rgchFileName, STR));
hr = pisl->SetDescription(rgchFileName);
}
else
hr = S_OK;
if (hr == S_OK)
hr = piurl->QueryInterface(IID_IDataObject,
(PVOID *)ppido);
delete pszName;
pszName = NULL;
}
pisl->Release();
pisl = NULL;
}
}
else
{
// Translate URL-specific failure into generic failure.
if (hr == URL_E_INVALID_SYNTAX)
hr = E_FAIL;
}
delete pszURL;
}
piurl->Release();
piurl = NULL;
}
ASSERT((hr == S_OK &&
IS_VALID_INTERFACE_PTR(*ppido, IDataObject)) ||
(FAILED(hr) &&
! *ppido));
return(hr);
}
PRIVATE_CODE HRESULT SBLinkDataObjectConstructor( PCMWIN pcmwin,
PIDataObject *ppido)
{
HRESULT hr;
PIUniformResourceLocator piurl;
ASSERT(IS_VALID_STRUCT_PTR(pcmwin, CMWIN));
ASSERT(IS_VALID_WRITE_PTR(ppido, PIDataObject));
hr = SHCoCreateInstance(NULL, &CLSID_InternetShortcut, NULL,
IID_IUniformResourceLocator, (PVOID *)&piurl);
if (hr == S_OK)
{
PSTR pszURL;
if (pcmwin && pcmwin->w3doc && pcmwin->w3doc->szActualURL)
{
ASSERT(IS_VALID_STRING_PTR(pcmwin->w3doc->szActualURL, CSTR));
pszURL = pcmwin->w3doc->szActualURL;
hr = piurl->SetURL(pszURL, 0);
}
else
{
hr = E_FAIL;
}
if (hr == S_OK)
{
PIShellLink pisl;
hr = piurl->QueryInterface(IID_IShellLink, (PVOID *)&pisl);
if (hr == S_OK)
{
PSTR pszName;
char rgchFileName[MAX_PATH_LEN];
pszName = pcmwin->w3doc->title;
// BUGBUG: (DavidDi 3/31/95) The title text may contain
// invalid file name characters. We need to strip them out
// before calling SetDescription().
if (hr == S_OK && pszName && *pszName)
TrimWhiteSpace(pszName);
if (GetNewShortcutFilename(
pszURL,
(pszName && *pszName) ? pszName : NULL,
rgchFileName,
NULL,
FOLDER_NONE,
(NEWSHORTCUT_FL_NO_HOST_PATH |
NEWSHORTCUT_FL_ALLOW_DUPLICATE_URL))
== S_OK)
{
ASSERT(IS_VALID_STRING_PTR(rgchFileName, STR));
hr = pisl->SetDescription(rgchFileName);
}
else
hr = S_OK;
if (hr == S_OK)
hr = piurl->QueryInterface(IID_IDataObject,
(PVOID *)ppido);
pisl->Release();
pisl = NULL;
}
}
else
{
// Translate URL-specific failure into generic failure.
if (hr == URL_E_INVALID_SYNTAX)
hr = E_FAIL;
}
piurl->Release();
piurl = NULL;
}
ASSERT((hr == S_OK &&
IS_VALID_INTERFACE_PTR(*ppido, IDataObject)) ||
(FAILED(hr) &&
! *ppido));
return(hr);
}
PRIVATE_CODE HRESULT CreateClipboardDIB(PCMWIN pcmwin, int iElem,
PHGLOBAL phgDIB)
{
HRESULT hr;
PCELEMENT pcelem;
ASSERT(IS_VALID_STRUCT_PTR(pcmwin, CMWIN));
ASSERT(IsValidElementIndex(pcmwin, iElem));
ASSERT(IS_VALID_WRITE_PTR(phgDIB, HGLOBAL));
*phgDIB = NULL;
pcelem = &(pcmwin->w3doc->aElements[iElem]);
if (EVAL(pcelem->myImage->pbmi != NULL) &&
EVAL(pcelem->myImage->data != NULL))
{
PCBITMAPINFO pcbmiSrc = pcelem->myImage->pbmi;
DWORD dwcColorsUsed;
DWORD dwcbColors;
DWORD dwcbInfo;
DWORD dwcbImage;
DWORD dwcbTotal;
HGLOBAL hgDIB;
hr = E_OUTOFMEMORY;
// (/ 8) for bytes.
// (+ (8 - 1)) to round up.
dwcColorsUsed = pcbmiSrc->bmiHeader.biClrUsed;
if (! dwcColorsUsed)
{
if (pcbmiSrc->bmiHeader.biBitCount != 24)
dwcColorsUsed = (1 << pcbmiSrc->bmiHeader.biBitCount);
}
dwcbColors = dwcColorsUsed * sizeof(pcbmiSrc->bmiColors[0]);
dwcbInfo = sizeof(pcbmiSrc->bmiHeader) + dwcbColors;
dwcbImage = ((((pcbmiSrc->bmiHeader.biWidth *
pcbmiSrc->bmiHeader.biBitCount) + 31) & ~31) / 8)
* pcbmiSrc->bmiHeader.biHeight;
dwcbTotal = dwcbInfo + dwcbImage;
hgDIB = GlobalAlloc((GMEM_MOVEABLE | GMEM_SHARE), dwcbTotal);
if (hgDIB)
{
PBITMAPINFO pbmi;
pbmi = (PBITMAPINFO)GlobalLock(hgDIB);
if (pbmi)
{
pbmi->bmiHeader = pcbmiSrc->bmiHeader;
// 8-bit display?
if (wg.eColorMode == 8 )
{
int i;
PALETTEENTRY pal[256];
// Yes. Get colors from app palette.
EVAL(GetPaletteEntries(hPalGuitar, 0, ARRAY_ELEMENTS(pal), pal)
== ARRAY_ELEMENTS(pal));
// Translate palette PALETTEENTRYs to BITMAPINFO RGBQUADs.
if (dwcColorsUsed == 2)
{
pbmi->bmiColors[0].rgbRed = pal[BACKGROUND_COLOR_INDEX].peRed;
pbmi->bmiColors[0].rgbBlue = pal[BACKGROUND_COLOR_INDEX].peBlue;
pbmi->bmiColors[0].rgbGreen = pal[BACKGROUND_COLOR_INDEX].peGreen;
pbmi->bmiColors[0].rgbReserved = 0;
pbmi->bmiColors[1].rgbRed = pal[FOREGROUND_COLOR_INDEX].peRed;
pbmi->bmiColors[1].rgbBlue = pal[FOREGROUND_COLOR_INDEX].peBlue;
pbmi->bmiColors[1].rgbGreen = pal[FOREGROUND_COLOR_INDEX].peGreen;
pbmi->bmiColors[1].rgbReserved = 0;
}
else
{
for (i = 0; i < ARRAY_ELEMENTS(pal); i++)
{
pbmi->bmiColors[i].rgbRed = pal[i].peRed;
pbmi->bmiColors[i].rgbGreen = pal[i].peGreen;
pbmi->bmiColors[i].rgbBlue = pal[i].peBlue;
pbmi->bmiColors[i].rgbReserved = 0;
}
}
}
else
// No. Use source BITMAPINFO colors.
CopyMemory(pbmi->bmiColors, pcbmiSrc->bmiColors, dwcbColors);
CopyMemory((PBYTE)pbmi + dwcbInfo, pcelem->myImage->data,
dwcbImage);
GlobalUnlock(hgDIB);
pbmi = NULL;
*phgDIB = hgDIB;
hr = S_OK;
TRACE_OUT(("CreateClipboardDIB(): Created %lu byte DIB for clipboard.",
dwcbTotal));
}
else
{
GlobalFree(hgDIB);
hgDIB = NULL;
}
}
}
else
{
WARNING_OUT(("CreateClipboardDIB(): No image data."));
hr = S_FALSE;
}
ASSERT((hr == S_OK &&
IS_VALID_HANDLE(*phgDIB, GLOBAL)) ||
(hr != S_OK &&
EVAL(! *phgDIB)));
return(hr);
}
PRIVATE_CODE HRESULT ImageDataConstructor(PIDataObject pido, PCMWIN pcmwin,
int iElem)
{
HRESULT hr;
PCELEMENT pcelem;
HGLOBAL hgDropFiles = NULL;
HGLOBAL hgDIB = NULL;
ASSERT(IS_VALID_INTERFACE_PTR(pido, IDataObject));
ASSERT(IS_VALID_STRUCT_PTR(pcmwin, CMWIN));
ASSERT(IsValidElementIndex(pcmwin, iElem));
ASSERT(pcmwin->w3doc->aElements[iElem].type == ELE_IMAGE ||
pcmwin->w3doc->aElements[iElem].type == ELE_FORMIMAGE);
pcelem = &(pcmwin->w3doc->aElements[iElem]);
// need to make sure that a blob is loaded, otherwise
// we cannot download it.
#ifdef FEATURE_VRML
// if we're VRML then disable D&D
if ( pcelem->pVrml )
{
// this error seems strange, but just following
// the behavior for images that are not loaded.
return E_OUTOFMEMORY;
}
#endif
if (pcelem->myImage)
{
PCSTR pcszURL;
char szPath[MAX_PATH_LEN];
// Hand DROPFILES off to data object.
// We should have a valid URL either for an AVI or an image.
ASSERT((pcelem->pblob &&
IS_VALID_STRING_PTR(pcelem->pblob->szURL, STR) &&
EVAL(*(pcelem->pblob->szURL))) ||
(!pcelem->pblob &&
IS_VALID_STRING_PTR(pcelem->myImage->actualURL, STR) &&
EVAL(*(pcelem->myImage->actualURL))));
pcszURL = pcelem->pblob ? pcelem->pblob->szURL
: pcelem->myImage->actualURL;
hr = GetURLFileSystemPath(pcszURL, pcmwin->w3doc->szActualURL, szPath,
sizeof(szPath));
if (hr == S_OK)
{
PCSTR rgpcszPaths[1];
rgpcszPaths[0] = szPath;
hr = CreateHDrop(rgpcszPaths, ARRAY_ELEMENTS(rgpcszPaths),
&hgDropFiles);
if (hr == S_OK)
{
FORMATETC fmtetc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1,
TYMED_HGLOBAL };
STGMEDIUM stgmed;
stgmed.tymed = TYMED_HGLOBAL;
stgmed.hGlobal = hgDropFiles;
stgmed.pUnkForRelease = NULL;
// Give the HDROP to the data object.
hr = pido->SetData(&fmtetc, &stgmed, TRUE);
if (hr == S_OK)
{
// Don't free hgDropFiles on subsequent error now that
// hgDropFiles has been added to the data object.
// IDataObject::Release() will.
hgDropFiles = NULL;
TRACE_OUT(("ImageDataConstructor(): Added %s for %s.",
GetClipboardFormatNameString(fmtetc.cfFormat),
szPath));
hr = CreateClipboardDIB(pcmwin, iElem, &hgDIB);
if (hr == S_OK)
{
fmtetc.cfFormat = CF_DIB;
fmtetc.tymed = TYMED_HGLOBAL;
ASSERT(! fmtetc.ptd);
ASSERT(fmtetc.dwAspect == DVASPECT_CONTENT);
ASSERT(fmtetc.lindex == -1);
stgmed.tymed = TYMED_HGLOBAL;
stgmed.hGlobal = hgDIB;
// Give the DIB to the data object.
hr = pido->SetData(&fmtetc, &stgmed, TRUE);
if (hr == S_OK)
{
// Mark read-only source cache file read-write so
// destination file is also read-write.
EVAL(MakePathReadWrite(szPath));
TRACE_OUT(("ImageDataConstructor(): Added %s.",
GetClipboardFormatNameString(fmtetc.cfFormat)));
}
}
else
{
if (hr == S_FALSE)
hr = S_OK;
}
}
}
}
}
else
{
hr = S_FALSE;
WARNING_OUT(("ImageDataConstructor(): No image information for element %d.",
iElem));
}
if (hr != S_OK)
{
if (hgDropFiles)
{
GlobalFree(hgDropFiles);
hgDropFiles = NULL;
}
if (hgDIB)
{
GlobalFree(hgDIB);
hgDIB = NULL;
}
}
return(hr);
}
PRIVATE_CODE HRESULT TextSelectionDataObjectConstructor(PMWIN pmwin,
PIDataObject *ppido)
{
HRESULT hr;
PIDataObject pido;
ASSERT(IS_VALID_STRUCT_PTR(pmwin, CMWIN));
ASSERT(IS_VALID_WRITE_PTR(ppido, PIDataObject));
ASSERT(MWinHasSelection(pmwin));
*ppido = NULL;
hr = CreateDataObject(&pido);
if (hr == S_OK)
{
PCharStream pcs;
hr = E_OUTOFMEMORY;
pcs = W3Doc_GetSelectedText(pmwin);
if (pcs)
{
PSTR pszText;
HGLOBAL hgText;
pszText = CS_GetPool(pcs);
// (+ 1) for null terminator.
hgText = GlobalAlloc((GMEM_MOVEABLE | GMEM_SHARE),
lstrlen(pszText) + 1);
if (hgText)
{
PSTR pszCopy;
pszCopy = (PSTR)GlobalLock(hgText);
if (pszCopy)
{
FORMATETC fmtetc = { CF_TEXT, NULL, DVASPECT_CONTENT, -1,
TYMED_HGLOBAL };
STGMEDIUM stgmed;
lstrcpy(pszCopy, pszText);
GlobalUnlock(hgText);
pszCopy = NULL;
stgmed.tymed = TYMED_HGLOBAL;
stgmed.hGlobal = hgText;
stgmed.pUnkForRelease = NULL;
hr = pido->SetData(&fmtetc, &stgmed, TRUE);
if (hr == S_OK)
*ppido = pido;
}
if (hr != S_OK)
{
GlobalFree(hgText);
hgText = NULL;
}
}
CS_Destroy(pcs);
}
if (hr != S_OK)
{
pido->Release();
pido = NULL;
}
}
ASSERT((hr == S_OK &&
IS_VALID_INTERFACE_PTR(*ppido, IDataObject)) ||
(FAILED(hr) &&
! *ppido));
return(hr);
}
PRIVATE_CODE HRESULT AddDataToClipboard(PIDataObject pido, PFORMATETC pfmtetc)
{
HRESULT hr;
ASSERT(IS_VALID_INTERFACE_PTR(pido, IDataObject));
ASSERT(IS_VALID_STRUCT_PTR(pfmtetc, CFORMATETC));
switch (pfmtetc->tymed)
{
case TYMED_HGLOBAL:
case TYMED_GDI:
case TYMED_MFPICT:
case TYMED_ENHMF:
hr = S_OK;
break;
default:
hr = S_FALSE;
WARNING_OUT(("AddDataToClipboard(): Cannot add clipboard format %s data to the clipboard. Storage medium not handled by clipboard.",
GetClipboardFormatNameString(pfmtetc->cfFormat)));
break;
}
if (hr == S_OK)
{
STGMEDIUM stgmed;
// BUGBUG: (performance) (DavidDi 4/11/95) We copy the data out of pido
// here. There is no way through IDataObject to use the internal data.
// That would be more efficient since the data would not be duplicated,
// possibly twice including the CloneStgMedium() call below.
hr = pido->GetData(pfmtetc, &stgmed);
if (hr == S_OK)
{
STGMEDIUM stgmedClone;
PSTGMEDIUM pstgmedToUse;
// Clone storage medium if necessary.
pstgmedToUse = &stgmed;
if (stgmed.pUnkForRelease)
{
hr = CloneStgMedium(&stgmed, &stgmedClone);
if (hr == S_OK)
{
hr = MyReleaseStgMedium(&stgmed);
pstgmedToUse = &stgmedClone;
}
}
if (hr == S_OK)
{
HANDLE hcf;
// Retrieve appropriate clipboard data handle from storage medium.
switch (stgmed.tymed)
{
case TYMED_HGLOBAL:
hcf = pstgmedToUse->hGlobal;
break;
case TYMED_GDI:
hcf = pstgmedToUse->hBitmap;
break;
case TYMED_MFPICT:
hcf = pstgmedToUse->hMetaFilePict;
break;
case TYMED_ENHMF:
hcf = pstgmedToUse->hEnhMetaFile;
break;
default:
hr = S_FALSE;
ERROR_OUT(("AddDataToClipboard(): Returned medium %lu is different than requested medium %lu.",
pstgmedToUse->tymed,
pfmtetc->tymed));
break;
}
if (hr == S_OK)
{
if (SetClipboardData(pfmtetc->cfFormat, hcf))
TRACE_OUT(("AddDataToClipboard(): Added clipboard format %s to clipboard.",
GetClipboardFormatNameString(pfmtetc->cfFormat)));
else
hr = E_FAIL;
}
}
// Release storage medium on error.
if (hr != S_OK)
EVAL(MyReleaseStgMedium(pstgmedToUse) == S_OK);
}
}
return(hr);
}
/****************************** Public Functions *****************************/
PUBLIC_CODE BOOL RegisterClipboardFormats(void)
{
g_cfURL = RegisterClipboardFormat(s_szURLCF);
g_cfFileGroupDescriptor = RegisterClipboardFormat(s_szFileDescriptorCF);
g_cfFileContents = RegisterClipboardFormat(s_szFileContentsCF);
return(g_cfURL != NULL &&
g_cfFileGroupDescriptor != NULL &&
g_cfFileContents != NULL);
}
PUBLIC_CODE BOOL MakePathReadWrite(PCSTR pcszPath)
{
BOOL bResult;
DWORD dwOldAttributes;
ASSERT(IsValidPath(pcszPath));
dwOldAttributes = GetFileAttributes(pcszPath);
if (dwOldAttributes != -1)
{
if (IS_FLAG_SET(dwOldAttributes, FILE_ATTRIBUTE_READONLY))
{
CLEAR_FLAG(dwOldAttributes, FILE_ATTRIBUTE_READONLY);
// Win32 doesn't like paths with all attributes clear. Set
// FILE_ATTRIBUTE_NORMAL if resulting attributes would otherwise be 0.
bResult = SetFileAttributes(pcszPath, dwOldAttributes ? dwOldAttributes : FILE_ATTRIBUTE_NORMAL);
if (bResult)
TRACE_OUT(("MakePathReadWrite(): Path %s now read-write.",
pcszPath));
else
WARNING_OUT(("MakePathReadWrite(): Unable to make path %s read-write.",
pcszPath));
}
else
{
bResult = TRUE;
TRACE_OUT(("MakePathReadWrite(): Path %s already read-write.",
pcszPath));
}
}
else
{
bResult = FALSE;
TRACE_OUT(("MakePathReadWrite(): Path %s does not exist.",
pcszPath));
}
return(bResult);
}
PUBLIC_CODE HRESULT CreateHDrop(PCSTR rgpcszPaths[], ULONG ulcPaths,
PHGLOBAL phgDropFiles)
{
HRESULT hr = E_OUTOFMEMORY;
ULONG ulcbStringListLen;
HGLOBAL hgDropFiles;
ASSERT(IS_VALID_READ_BUFFER_PTR(rgpcszPaths, PCSTR, ulcPaths * sizeof(rgpcszPaths[0])));
ASSERT(IS_VALID_WRITE_PTR(phgDropFiles, HGLOBAL));
*phgDropFiles = NULL;
ulcbStringListLen = GetLengthOfStringList(rgpcszPaths, ulcPaths);
// (+ 1) again for null terminator.
hgDropFiles = GlobalAlloc((GMEM_MOVEABLE | GMEM_SHARE),
sizeof(DROPFILES) + ulcbStringListLen);
if (hgDropFiles)
{
PDROPFILES pdf;
pdf = (PDROPFILES)GlobalLock(hgDropFiles);
if (pdf)
{
PSTR pszDropPath;
ULONG ul;
ZeroMemory(pdf, sizeof(*pdf));
pdf->pFiles = sizeof(*pdf);
pszDropPath = (PSTR)((PBYTE)pdf + sizeof(*pdf));
for (ul = 0; ul < ulcPaths; ul++)
{
ASSERT(IS_VALID_STRING_PTR(rgpcszPaths[ul], CSTR));
lstrcpy(pszDropPath, rgpcszPaths[ul]);
TRACE_OUT(("CreateHDrop(): Added %s to HDROP.",
pszDropPath));
// (+ 1) for null terminator.
pszDropPath += lstrlen(pszDropPath) + 1;
}
// Double null terminate.
*pszDropPath = '\0';
GlobalUnlock(hgDropFiles);
pdf = NULL;
*phgDropFiles = hgDropFiles;
hr = S_OK;
}
}
ASSERT((hr == S_OK &&
IS_VALID_HANDLE(*phgDropFiles, GLOBAL)) ||
(hr == E_OUTOFMEMORY &&
! *phgDropFiles));
return(hr);
}
PUBLIC_CODE HRESULT CreateElementDataObject(PCMWIN pcmwin, int iElem,
PIDataObject *ppido,
PDWORD pdwAvailEffects)
{
HRESULT hr;
PCELEMENT pcelem;
PCDATACONSTRUCTOR pcdc;
ASSERT(IS_VALID_STRUCT_PTR(pcmwin, CMWIN));
ASSERT(IsValidElementIndex(pcmwin, iElem));
ASSERT(IS_VALID_WRITE_PTR(ppido, PIDataObject));
ASSERT(IS_VALID_WRITE_PTR(pdwAvailEffects, DWORD));
*ppido = NULL;
*pdwAvailEffects = 0;
pcelem = &(pcmwin->w3doc->aElements[iElem]);
// Create an element type data object from a generic data object.
hr = GetDataConstructorFromElementType(pcelem->type, &pcdc);
if (hr == S_OK)
{
PIDataObject pido;
TRACE_OUT(("CreateElementDataObject(): Trying to create an element type data object."));
hr = CreateDataObject(&pido);
if (hr == S_OK)
{
hr = (*(pcdc->dcp))(pido, pcmwin, iElem);
if (hr == S_OK)
{
*ppido = pido;
*pdwAvailEffects = pcdc->dwAvailEffects;
ASSERT(*pdwAvailEffects);
}
else
{
pido->Release();
pido = NULL;
}
}
}
else
ASSERT(hr == S_FALSE);
ASSERT((hr == S_OK &&
IS_VALID_INTERFACE_PTR(*ppido, IDataObject) &&
EVAL(*pdwAvailEffects)) ||
(hr != S_OK &&
EVAL(! *ppido) &&
EVAL(! *pdwAvailEffects)));
return(hr);
}
PUBLIC_CODE HRESULT CreateLinkDataObject(PCMWIN pcmwin, int iElem,
PIDataObject *ppido,
PDWORD pdwAvailEffects)
{
HRESULT hr;
PCELEMENT pcelem;
ASSERT(IS_VALID_STRUCT_PTR(pcmwin, CMWIN));
ASSERT(IsValidElementIndex(pcmwin, iElem));
ASSERT(IS_VALID_WRITE_PTR(ppido, PIDataObject));
ASSERT(IS_VALID_WRITE_PTR(pdwAvailEffects, DWORD));
*ppido = NULL;
*pdwAvailEffects = 0;
pcelem = &(pcmwin->w3doc->aElements[iElem]);
if (IS_FLAG_SET(pcelem->lFlags, ELEFLAG_ANCHOR))
{
// Create a link data object as an Internet Shortcut.
TRACE_OUT(("CreateElementDataObject(): Trying to create a link data object."));
hr = LinkDataObjectConstructor(pcmwin, iElem, ppido);
if (hr == S_OK)
*pdwAvailEffects = DROPEFFECT_LINK;
}
else
hr = S_FALSE;
ASSERT((hr == S_OK &&
IS_VALID_INTERFACE_PTR(*ppido, IDataObject) &&
EVAL(*pdwAvailEffects)) ||
(hr != S_OK &&
EVAL(! *ppido) &&
EVAL(! *pdwAvailEffects)));
return(hr);
}
PUBLIC_CODE HRESULT CreateSBLinkDataObject( PCMWIN pcmwin,
PIDataObject *ppido,
PDWORD pdwAvailEffects)
{
HRESULT hr;
ASSERT(IS_VALID_STRUCT_PTR(pcmwin, CMWIN));
ASSERT(IS_VALID_WRITE_PTR(ppido, PIDataObject));
ASSERT(IS_VALID_WRITE_PTR(pdwAvailEffects, DWORD));
*ppido = NULL;
*pdwAvailEffects = 0;
// Create a link data object as an Internet Shortcut.
TRACE_OUT(("CreateElementDataObject(): Trying to create a link data object."));
hr = SBLinkDataObjectConstructor(pcmwin, ppido);
if (hr == S_OK)
*pdwAvailEffects = DROPEFFECT_LINK;
ASSERT((hr == S_OK &&
IS_VALID_INTERFACE_PTR(*ppido, IDataObject) &&
EVAL(*pdwAvailEffects)) ||
(hr != S_OK &&
EVAL(! *ppido) &&
EVAL(! *pdwAvailEffects)));
return(hr);
}
PUBLIC_CODE HRESULT CreateSelectionDataObject(PMWIN pmwin, PIDataObject *ppido,
PDWORD pdwAvailEffects)
{
HRESULT hr;
ASSERT(IS_VALID_STRUCT_PTR(pmwin, CMWIN));
ASSERT(IS_VALID_WRITE_PTR(ppido, PIDataObject));
ASSERT(IS_VALID_WRITE_PTR(pdwAvailEffects, DWORD));
*ppido = NULL;
*pdwAvailEffects = 0;
if (MWinHasSelection(pmwin))
{
TRACE_OUT(("CreateSelectionDataObject(): Trying to create a selection data object."));
hr = TextSelectionDataObjectConstructor(pmwin, ppido);
if (hr == S_OK)
*pdwAvailEffects = DROPEFFECT_COPY;
}
else
hr = S_FALSE;
ASSERT((hr == S_OK &&
IS_VALID_INTERFACE_PTR(*ppido, IDataObject) &&
EVAL(*pdwAvailEffects)) ||
(hr != S_OK &&
EVAL(! *ppido) &&
EVAL(! *pdwAvailEffects)));
return(hr);
}
PUBLIC_CODE HRESULT SetClipboardDataFromDataObject(HWND hwndOwner,
PIDataObject pido)
{
HRESULT hr = E_FAIL;
ASSERT(IS_VALID_HANDLE(hwndOwner, WND));
ASSERT(IS_VALID_INTERFACE_PTR(pido, IDataObject));
if (OpenClipboard(hwndOwner))
{
TRACE_OUT(("SetClipboardDataFromDataObject(): Opened clipboard."));
if (EmptyClipboard())
{
PIEnumFORMATETC piefe;
TRACE_OUT(("SetClipboardDataFromDataObject(): Emptied clipboard."));
hr = pido->EnumFormatEtc(DATADIR_GET, &piefe);
if (hr == S_OK)
{
FORMATETC fmtetc;
TRACE_OUT(("SetClipboardDataFromDataObject(): Enumerating data object clipboard formats."));
while ((hr = piefe->Next(1, &fmtetc, NULL)) == S_OK)
{
hr = AddDataToClipboard(pido, &fmtetc);
if (FAILED(hr))
break;
}
TRACE_OUT(("SetClipboardDataFromDataObject(): Finished enumerating data object clipboard formats."));
if (hr == S_FALSE)
hr = S_OK;
piefe->Release();
}
// Remove any data added to the clipboard on error.
if (hr != S_OK)
{
if (EVAL(EmptyClipboard()))
TRACE_OUT(("SetClipboardDataFromDataObject(): Emptied clipboard on error."));
else
WARNING_OUT(("SetClipboardDataFromDataObject(): Unable to empty clipboard on error."));
}
}
if (EVAL(CloseClipboard()))
TRACE_OUT(("SetClipboardDataFromDataObject(): Closed clipboard."));
else
WARNING_OUT(("SetClipboardDataFromDataObject(): Unable to close clipboard."));
}
return(hr);
}
/*
** GetURLIcon()
**
** Retrieves an icon for a URL. Creates an Internet Shortcut, stuffs a URL in
** it, and then queries it for its icon.
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE BOOL GetURLIcon(PCSTR pcszURL, PHICON phicon)
{
BOOL bResult = FALSE;
PIUniformResourceLocator piurl;
ASSERT(IS_VALID_STRING_PTR(pcszURL, CSTR));
ASSERT(IS_VALID_WRITE_PTR(phicon, HICON));
// Create an InternetShortcut object. Get IUniformResourceLocator.
if (SHCoCreateInstance(NULL, &CLSID_InternetShortcut, NULL,
IID_IUniformResourceLocator, (PVOID *)&piurl) == S_OK)
{
// Set the InternetShortcut's URL.
if (piurl->SetURL(pcszURL, 0) == S_OK)
{
IExtractIcon *piei;
// Get IExtractIcon.
if (piurl->QueryInterface(IID_IExtractIcon, (PVOID *)&piei) == S_OK)
{
char szIconFile[MAX_PATH_LEN];
int niIcon;
UINT uOutFlags;
// Ask for the InternetShortcut's icon.
if (piei->GetIconLocation(0, szIconFile, sizeof(szIconFile),
&niIcon, &uOutFlags) == S_OK)
{
#ifdef DEBUG
HICON hiconLarge;
HICON hiconSmall;
// BUGBUG: We should really use IExtractIcon::Extract() here,
// perhaps recursively. Cheat, and assume that
// GetIconLocation() returned a file and icon index we can use
// directly.
ASSERT(piei->Extract(szIconFile, niIcon, &hiconLarge, &hiconSmall, 0) == S_FALSE);
#endif
// BUGBUG: This icon does not have the link arrow overlayed.
// The Shortcut and Internet Shortcut property sheets have the
// same bug.
*phicon = ExtractIcon(wg.hInstance, szIconFile,
niIcon);
bResult = (*phicon != NULL);
}
piei->Release();
piei= NULL;
}
}
piurl->Release();
piurl = NULL;
}
// Return NULL icon handle on failure.
if (! bResult)
*phicon = NULL;
ASSERT((bResult &&
IS_VALID_HANDLE(*phicon, ICON)) ||
(! bResult &&
! *phicon));
return(bResult);
}