442 lines
15 KiB
C++
442 lines
15 KiB
C++
/*
|
|
* CHNGSRC.CPP
|
|
*
|
|
* Implements the OleUIChangeSource function which invokes the complete
|
|
* Change Source dialog.
|
|
*
|
|
* Copyright (c)1992 Microsoft Corporation, All Right Reserved
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
#include "common.h"
|
|
#include "utility.h"
|
|
#include "strsafe.h"
|
|
|
|
OLEDBGDATA
|
|
|
|
// Internally used structure
|
|
typedef struct tagCHANGESOURCE
|
|
{
|
|
// Keep this item first as the Standard* functions depend on it here.
|
|
LPOLEUICHANGESOURCE lpOCS; //Original structure passed.
|
|
UINT nIDD; // IDD of dialog (used for help info)
|
|
|
|
/*
|
|
* What we store extra in this structure besides the original caller's
|
|
* pointer are those fields that we need to modify during the life of
|
|
* the dialog but that we don't want to change in the original structure
|
|
* until the user presses OK.
|
|
*/
|
|
|
|
} CHANGESOURCE, *PCHANGESOURCE, FAR* LPCHANGESOURCE;
|
|
|
|
// Internal function prototypes
|
|
// CHNGSRC.CPP
|
|
|
|
UINT_PTR CALLBACK ChangeSourceHookProc(HWND, UINT, WPARAM, LPARAM);
|
|
BOOL FChangeSourceInit(HWND hDlg, WPARAM, LPARAM);
|
|
STDAPI_(BOOL) IsValidInterface(void FAR* ppv);
|
|
|
|
/*
|
|
* OleUIChangeSource
|
|
*
|
|
* Purpose:
|
|
* Invokes the standard OLE Change Source dialog box allowing the user
|
|
* to change the source of a link. The link source is not actually
|
|
* changed by this dialog. It is up to the caller to actually change
|
|
* the link source itself.
|
|
*
|
|
* Parameters:
|
|
* lpCS LPOLEUIChangeSource pointing to the in-out structure
|
|
* for this dialog.
|
|
*
|
|
* Return Value:
|
|
* UINT One of the following codes, indicating success or error:
|
|
* OLEUI_SUCCESS Success
|
|
* OLEUI_ERR_STRUCTSIZE The dwStructSize value is wrong
|
|
*/
|
|
STDAPI_(UINT) OleUIChangeSource(LPOLEUICHANGESOURCE lpCS)
|
|
{
|
|
HGLOBAL hMemDlg = NULL;
|
|
UINT uRet = UStandardValidation((LPOLEUISTANDARD)lpCS,
|
|
sizeof(OLEUICHANGESOURCE), &hMemDlg);
|
|
|
|
if (OLEUI_SUCCESS != uRet)
|
|
return uRet;
|
|
|
|
|
|
HCURSOR hCurSave = NULL;
|
|
|
|
// validate contents of lpCS
|
|
if (lpCS->lpOleUILinkContainer == NULL)
|
|
{
|
|
uRet = OLEUI_CSERR_LINKCNTRNULL;
|
|
goto Error;
|
|
}
|
|
if (!IsValidInterface(lpCS->lpOleUILinkContainer))
|
|
{
|
|
uRet = OLEUI_CSERR_LINKCNTRINVALID;
|
|
goto Error;
|
|
}
|
|
|
|
// lpszFrom and lpszTo must be NULL (they are out only)
|
|
if (lpCS->lpszFrom != NULL)
|
|
{
|
|
uRet = OLEUI_CSERR_FROMNOTNULL;
|
|
goto Error;
|
|
}
|
|
if (lpCS->lpszTo != NULL)
|
|
{
|
|
uRet = OLEUI_CSERR_TONOTNULL;
|
|
goto Error;
|
|
}
|
|
|
|
// lpszDisplayName must be valid or NULL
|
|
if (lpCS->lpszDisplayName != NULL &&
|
|
IsBadStringPtr(lpCS->lpszDisplayName, (UINT)-1))
|
|
{
|
|
uRet = OLEUI_CSERR_SOURCEINVALID;
|
|
goto Error;
|
|
}
|
|
|
|
hCurSave = HourGlassOn();
|
|
|
|
// attempt to retrieve link source if not provided
|
|
if (lpCS->lpszDisplayName == NULL)
|
|
{
|
|
if (NOERROR != lpCS->lpOleUILinkContainer->GetLinkSource(
|
|
lpCS->dwLink, &lpCS->lpszDisplayName, &lpCS->nFileLength,
|
|
NULL, NULL, NULL, NULL))
|
|
{
|
|
uRet = OLEUI_CSERR_SOURCEINVALID;
|
|
goto Error;
|
|
}
|
|
}
|
|
|
|
// verify that nFileLength is valid
|
|
UINT cchDisplayName = lstrlen(lpCS->lpszDisplayName);
|
|
if (cchDisplayName < lpCS->nFileLength)
|
|
{
|
|
uRet = OLEUI_CSERR_SOURCEINVALID;
|
|
goto Error;
|
|
}
|
|
|
|
// allocate file buffer and split directory and file name
|
|
UINT nFileLength; nFileLength = lpCS->nFileLength;
|
|
UINT nFileBuf; nFileBuf = max(nFileLength+1, MAX_PATH);
|
|
LPTSTR lpszFileBuf;
|
|
|
|
if (cchDisplayName > nFileBuf -1)
|
|
{
|
|
uRet = OLEUI_CSERR_SOURCEINVALID;
|
|
goto Error;
|
|
}
|
|
|
|
LPTSTR lpszDirBuf; lpszDirBuf = (LPTSTR)OleStdMalloc(nFileBuf * sizeof(TCHAR));
|
|
if (lpszDirBuf == NULL)
|
|
{
|
|
uRet = OLEUI_ERR_OLEMEMALLOC;
|
|
goto Error;
|
|
}
|
|
lstrcpyn(lpszDirBuf, lpCS->lpszDisplayName, nFileLength+1);
|
|
|
|
UINT nFileLen; nFileLen = GetFileName(lpszDirBuf, NULL, 0);
|
|
|
|
lpszFileBuf = (LPTSTR)OleStdMalloc(nFileBuf * sizeof(TCHAR));
|
|
if (lpszFileBuf == NULL)
|
|
{
|
|
uRet = OLEUI_ERR_OLEMEMALLOC;
|
|
goto ErrorFreeDirBuf;
|
|
}
|
|
memmove(lpszFileBuf, lpszDirBuf+nFileLength-nFileLen+1,
|
|
(nFileLen+1)*sizeof(TCHAR));
|
|
lpszDirBuf[nFileLength-(nFileLen - 1)] = 0;
|
|
|
|
// start filling the OPENFILENAME struct
|
|
OPENFILENAME ofn; memset(&ofn, 0, sizeof(ofn));
|
|
ofn.lpstrFile = lpszFileBuf;
|
|
ofn.nMaxFile = nFileBuf;
|
|
ofn.lpstrInitialDir = lpszDirBuf;
|
|
|
|
// load filter strings
|
|
TCHAR szFilters[MAX_PATH];
|
|
if (!LoadString(_g_hOleStdResInst, IDS_FILTERS, szFilters, MAX_PATH))
|
|
szFilters[0] = 0;
|
|
else
|
|
ReplaceCharWithNull(szFilters, szFilters[lstrlen(szFilters)-1]);
|
|
ofn.lpstrFilter = szFilters;
|
|
ofn.nFilterIndex = 1;
|
|
|
|
TCHAR szTitle[MAX_PATH];
|
|
|
|
// set the caption
|
|
if (NULL!=lpCS->lpszCaption)
|
|
ofn.lpstrTitle = lpCS->lpszCaption;
|
|
else
|
|
{
|
|
LoadString(_g_hOleStdResInst, IDS_CHANGESOURCE, szTitle, MAX_PATH);
|
|
ofn.lpstrTitle = szTitle;
|
|
}
|
|
|
|
// fill in rest of OPENFILENAME struct
|
|
ofn.hwndOwner = lpCS->hWndOwner;
|
|
ofn.lStructSize = sizeof(ofn);
|
|
ofn.Flags = OFN_HIDEREADONLY | OFN_ENABLEHOOK;
|
|
if (bWin4 && ((NULL == lpCS->hInstance && NULL == lpCS->hResource)
|
|
|| 0 != (lpCS->dwFlags & CSF_EXPLORER)))
|
|
ofn.Flags |= OFN_EXPLORER;
|
|
if (lpCS->dwFlags & CSF_SHOWHELP)
|
|
ofn.Flags |= OFN_SHOWHELP;
|
|
ofn.lCustData = (LPARAM)lpCS;
|
|
ofn.lpfnHook = ChangeSourceHookProc;
|
|
ofn.lCustData = (LPARAM)lpCS;
|
|
lpCS->lpOFN = &ofn; // needed sometimes in hook proc
|
|
|
|
// allow hooking of the dialog resource
|
|
if (lpCS->hResource != NULL)
|
|
{
|
|
ofn.hInstance = (HINSTANCE)lpCS->hResource;
|
|
ofn.lpTemplateName = (LPCTSTR)lpCS->hResource;
|
|
ofn.Flags |= OFN_ENABLETEMPLATEHANDLE;
|
|
}
|
|
else
|
|
{
|
|
if (lpCS->hInstance == NULL)
|
|
{
|
|
ofn.hInstance = _g_hOleStdResInst;
|
|
ofn.lpTemplateName = bWin4 ?
|
|
MAKEINTRESOURCE(IDD_CHANGESOURCE4) : MAKEINTRESOURCE(IDD_CHANGESOURCE);
|
|
ofn.Flags |= OFN_ENABLETEMPLATE;
|
|
}
|
|
else
|
|
{
|
|
ofn.hInstance = lpCS->hInstance;
|
|
ofn.lpTemplateName = lpCS->lpszTemplate;
|
|
ofn.Flags |= OFN_ENABLETEMPLATE;
|
|
}
|
|
}
|
|
|
|
if (lpCS->hWndOwner != NULL)
|
|
{
|
|
// allow hooking of the OFN struct
|
|
SendMessage(lpCS->hWndOwner, uMsgBrowseOFN, ID_BROWSE_CHANGESOURCE, (LPARAM)&ofn);
|
|
}
|
|
|
|
// call up the dialog
|
|
BOOL bResult;
|
|
|
|
bResult = StandardGetOpenFileName(&ofn);
|
|
|
|
// cleanup
|
|
OleStdFree(lpszDirBuf);
|
|
OleStdFree(lpszFileBuf);
|
|
|
|
HourGlassOff(hCurSave);
|
|
|
|
// map return value to OLEUI_ standard returns
|
|
return bResult ? OLEUI_OK : OLEUI_CANCEL;
|
|
|
|
// handle most error returns here
|
|
ErrorFreeDirBuf:
|
|
OleStdFree(lpszDirBuf);
|
|
|
|
Error:
|
|
if (hCurSave != NULL)
|
|
HourGlassOff(hCurSave);
|
|
return uRet;
|
|
}
|
|
|
|
/*
|
|
* ChangeSourceHookProc
|
|
*
|
|
* Purpose:
|
|
* Implements the OLE Change Source dialog as invoked through the
|
|
* OleUIChangeSource function. This is a standard COMMDLG hook function
|
|
* as opposed to a dialog proc.
|
|
*
|
|
* Parameters:
|
|
* Standard
|
|
*
|
|
* Return Value:
|
|
* Standard
|
|
*/
|
|
UINT_PTR CALLBACK ChangeSourceHookProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
// Declare Win16/Win32 compatible WM_COMMAND parameters.
|
|
COMMANDPARAMS(wID, wCode, hWndMsg);
|
|
|
|
// This will fail under WM_INITDIALOG, where we allocate it.
|
|
UINT uHook = 0;
|
|
LPCHANGESOURCE lpCS = (LPCHANGESOURCE)LpvStandardEntry(hDlg, iMsg, wParam, lParam, &uHook);
|
|
|
|
LPOLEUICHANGESOURCE lpOCS = NULL;
|
|
if (lpCS != NULL)
|
|
lpOCS = lpCS->lpOCS;
|
|
|
|
// If the hook processed the message, we're done.
|
|
if (0 != uHook)
|
|
return uHook;
|
|
|
|
// Process help message
|
|
if ((iMsg == uMsgHelp) && NULL != lpOCS)
|
|
{
|
|
PostMessage(lpOCS->hWndOwner, uMsgHelp,
|
|
(WPARAM)hDlg, MAKELPARAM(IDD_CHANGESOURCE, 0));
|
|
}
|
|
|
|
// Process the temination message
|
|
if (iMsg == uMsgEndDialog)
|
|
{
|
|
// Free any specific allocations before calling StandardCleanup
|
|
StandardCleanup((PVOID)lpCS, hDlg);
|
|
EndDialog(hDlg, wParam);
|
|
return TRUE;
|
|
}
|
|
|
|
// handle validation of the file name (when user hits OK)
|
|
if ((iMsg == uMsgFileOKString) && (lpOCS != NULL))
|
|
{
|
|
// always use fully qualified name
|
|
LPOPENFILENAME lpOFN = lpOCS->lpOFN;
|
|
LPCTSTR lpsz = lpOFN->lpstrFile;
|
|
LPTSTR lpszFile;
|
|
TCHAR szPath[MAX_PATH];
|
|
if (!GetFullPathName(lpsz, MAX_PATH, szPath, &lpszFile))
|
|
lstrcpyn(szPath, lpsz, MAX_PATH);
|
|
UINT nLenFile = lstrlen(szPath);
|
|
TCHAR szItemName[MAX_PATH];
|
|
GetDlgItemText(hDlg, edt2, szItemName, MAX_PATH);
|
|
|
|
// combine them into szDisplayName (which is now large enough)
|
|
TCHAR szDisplayName[MAX_PATH+MAX_PATH];
|
|
StringCchCopy(szDisplayName, sizeof(szDisplayName)/sizeof(szDisplayName[0]), szPath);
|
|
if (szItemName[0] != '\0')
|
|
{
|
|
StringCchCat(szDisplayName, sizeof(szDisplayName)/sizeof(szDisplayName[0]), TEXT("\\"));
|
|
StringCchCat(szDisplayName, sizeof(szDisplayName)/sizeof(szDisplayName[0]), szItemName);
|
|
}
|
|
|
|
if (!(lpOCS->dwFlags & CSF_ONLYGETSOURCE))
|
|
{
|
|
// verify the source by calling into the link container
|
|
LPOLEUILINKCONTAINER lpOleUILinkCntr = lpOCS->lpOleUILinkContainer;
|
|
ULONG chEaten;
|
|
if (lpOleUILinkCntr->SetLinkSource(lpOCS->dwLink, szDisplayName, nLenFile,
|
|
&chEaten, TRUE) != NOERROR)
|
|
{
|
|
// link not verified ok
|
|
lpOCS->dwFlags &= ~CSF_VALIDSOURCE;
|
|
UINT uRet = PopupMessage(hDlg, IDS_CHANGESOURCE, IDS_INVALIDSOURCE,
|
|
MB_ICONQUESTION | MB_YESNO);
|
|
if (uRet == IDYES)
|
|
{
|
|
SetWindowLong(hDlg, DWLP_MSGRESULT, 1);
|
|
return 1; // do not close dialog
|
|
}
|
|
|
|
// user doesn't care if the link is valid or not
|
|
lpOleUILinkCntr->SetLinkSource(lpOCS->dwLink, szDisplayName, nLenFile,
|
|
&chEaten, FALSE);
|
|
}
|
|
else
|
|
{
|
|
// link was verified ok
|
|
lpOCS->dwFlags |= CSF_VALIDSOURCE;
|
|
}
|
|
}
|
|
|
|
// calculate lpszFrom and lpszTo for batch changes to links
|
|
DiffPrefix(lpOCS->lpszDisplayName, szDisplayName, &lpOCS->lpszFrom, &lpOCS->lpszTo);
|
|
|
|
// only keep them if the file name portion is the only part that changed
|
|
if (lstrcmpi(lpOCS->lpszTo, lpOCS->lpszFrom) == 0 ||
|
|
(UINT)lstrlen(lpOCS->lpszFrom) > lpOCS->nFileLength)
|
|
{
|
|
OleStdFree(lpOCS->lpszFrom);
|
|
lpOCS->lpszFrom = NULL;
|
|
|
|
OleStdFree(lpOCS->lpszTo);
|
|
lpOCS->lpszTo = NULL;
|
|
}
|
|
|
|
// store new source in lpOCS->lpszDisplayName
|
|
OleStdFree(lpOCS->lpszDisplayName);
|
|
lpOCS->lpszDisplayName = OleStdCopyString(szDisplayName);
|
|
lpOCS->nFileLength = nLenFile;
|
|
|
|
return 0;
|
|
}
|
|
|
|
switch (iMsg)
|
|
{
|
|
case WM_NOTIFY:
|
|
if (((NMHDR*)lParam)->code == CDN_HELP)
|
|
{
|
|
goto POSTHELP;
|
|
}
|
|
break;
|
|
case WM_COMMAND:
|
|
if (wID == pshHelp)
|
|
{
|
|
POSTHELP:
|
|
PostMessage(lpCS->lpOCS->hWndOwner, uMsgHelp,
|
|
(WPARAM)hDlg, MAKELPARAM(IDD_CHANGESOURCE, 0));
|
|
}
|
|
break;
|
|
case WM_INITDIALOG:
|
|
return FChangeSourceInit(hDlg, wParam, lParam);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* FChangeSourceInit
|
|
*
|
|
* Purpose:
|
|
* WM_INITIDIALOG handler for the Change Source dialog box.
|
|
*
|
|
* Parameters:
|
|
* hDlg HWND of the dialog
|
|
* wParam WPARAM of the message
|
|
* lParam LPARAM of the message
|
|
*
|
|
* Return Value:
|
|
* BOOL Value to return for WM_INITDIALOG.
|
|
*/
|
|
BOOL FChangeSourceInit(HWND hDlg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
// Copy the structure at lParam into our instance memory.
|
|
LPCHANGESOURCE lpCS = (LPCHANGESOURCE)LpvStandardInit(hDlg, sizeof(CHANGESOURCE), NULL);
|
|
|
|
// PvStandardInit send a termination to us already.
|
|
if (NULL == lpCS)
|
|
return FALSE;
|
|
|
|
LPOLEUICHANGESOURCE lpOCS=
|
|
(LPOLEUICHANGESOURCE)((LPOPENFILENAME)lParam)->lCustData;
|
|
lpCS->lpOCS = lpOCS;
|
|
lpCS->nIDD = IDD_CHANGESOURCE;
|
|
|
|
// Setup Item text box with item part of lpszDisplayName
|
|
LPTSTR lpszItemName = lpOCS->lpszDisplayName + lpOCS->nFileLength;
|
|
if (*lpszItemName != '\0')
|
|
SetDlgItemText(hDlg, edt2, lpszItemName+1);
|
|
SendDlgItemMessage(hDlg, edt2, EM_LIMITTEXT, MAX_PATH, 0L);
|
|
|
|
// Change the caption
|
|
if (NULL!=lpOCS->lpszCaption)
|
|
SetWindowText(hDlg, lpOCS->lpszCaption);
|
|
|
|
// Call the hook with lCustData in lParam
|
|
UStandardHook((PVOID)lpCS, hDlg, WM_INITDIALOG, wParam, lpOCS->lCustData);
|
|
#ifdef CHICO
|
|
TCHAR szTemp[MAX_PATH];
|
|
LoadString(_g_hOleStdResInst, IDS_CHNGSRCOKBUTTON , szTemp, MAX_PATH);
|
|
CommDlg_OpenSave_SetControlText(GetParent(hDlg), IDOK, szTemp);
|
|
#endif
|
|
return TRUE;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|