// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1998 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.

#include "stdafx.h"

#ifdef AFX_OLE2_SEG
#pragma code_seg(AFX_OLE2_SEG)
#endif

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define new DEBUG_NEW

UINT CALLBACK
AfxOleHookProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

////////////////////////////////////////////////////////////////////////////
// EditProperties dialog wrapper

COlePropertiesDialog::COlePropertiesDialog(
	COleClientItem* pItem, UINT nScaleMin, UINT nScaleMax, CWnd* pParentWnd)
	: COleDialog(pParentWnd), m_xLinkInfo(NULL)
{
	ASSERT_VALID(pItem);

	memset(&m_op, 0, sizeof(m_op)); // initialize structure to 0/NULL

	// fill in common part
	m_op.cbStruct = sizeof(m_op);
	m_op.dwFlags = 0;
	if (AfxHelpEnabled())
		m_op.dwFlags |= OPF_SHOWHELP;
	m_nIDHelp = AFX_IDD_OBJECTPROPERTIES;

	// specific to this dialog
	memset(&m_gp, 0, sizeof(m_gp));
	m_gp.cbStruct = sizeof(m_gp);
	m_gp.lpfnHook = AfxOleHookProc;
	m_gp.dwFlags = 0;

	memset(&m_vp, 0, sizeof(m_vp));
	m_vp.cbStruct = sizeof(m_vp);
	m_vp.lpfnHook = AfxOleHookProc;
	m_vp.dwFlags = 0;
	m_vp.nScaleMin = nScaleMin;
	m_vp.nScaleMax = nScaleMax;

	memset(&m_lp, 0, sizeof(m_lp));
	m_lp.cbStruct = sizeof(m_lp);
	m_lp.lpfnHook = AfxOleHookProc;
	m_lp.dwFlags = 0;

	m_op.lpObjInfo = &m_xOleUIObjInfo;
	m_op.lpLinkInfo = &m_xLinkInfo;
	m_op.dwLink = (DWORD)pItem;
	m_op.dwObject = (DWORD)pItem;
	m_op.lpGP = &m_gp; m_op.lpVP = &m_vp;
	if (pItem->GetType() == OT_LINK)
	{
		m_op.dwFlags |= OPF_OBJECTISLINK;
		m_op.lpLP = &m_lp;
	}
	memset(&m_psh, 0, sizeof(m_psh));
	m_psh.dwSize = sizeof(PROPSHEETHEADER);
	m_op.lpPS = &m_psh;
}

int COlePropertiesDialog::DoModal()
{
	ASSERT_VALID(this);
	ASSERT(m_gp.lpfnHook != NULL);  // can still be a user hook
	ASSERT(m_vp.lpfnHook != NULL);  // can still be a user hook
	ASSERT(m_lp.lpfnHook != NULL);  // can still be a user hook

	// disable scale if OnApplyScale not implemented
	if (!OnApplyScale(NULL, -1, FALSE))
		m_op.lpVP->dwFlags |= VPF_DISABLESCALE;

	// invoke the dialog
	m_op.lpPS->hwndParent = PreModal();
	int iResult = MapResult(::OleUIObjectProperties(&m_op));
	PostModal();
	return iResult;
}

BOOL COlePropertiesDialog::OnInitDialog()
{
	BOOL bResult = COleDialog::OnInitDialog();

	// automatic centering doesn't work for this dialog
	if (!(GetStyle() & WS_CHILD))
		CenterWindow();

	return bResult;
}

STDMETHODIMP_(ULONG) COlePropertiesDialog::XOleUIObjInfo::AddRef()
{
	return 0;
}

STDMETHODIMP_(ULONG) COlePropertiesDialog::XOleUIObjInfo::Release()
{
	return 0;
}

STDMETHODIMP COlePropertiesDialog::XOleUIObjInfo::QueryInterface(
	REFIID, LPVOID*)
{
	return E_NOTIMPL;
}

STDMETHODIMP COlePropertiesDialog::XOleUIObjInfo::GetObjectInfo(
	DWORD dwObject, DWORD* lpdwObjSize, LPTSTR* lplpszLabel,
	LPTSTR* lplpszType, LPTSTR* lplpszShortType, LPTSTR* lplpszLocation)
{
	COleClientItem* pItem = (COleClientItem*)dwObject;
	ASSERT_VALID(pItem);
	BOOL bIsLink = (pItem->GetType() == OT_LINK);

	if (lpdwObjSize != NULL)
	{
		ASSERT(pItem->m_lpStorage != NULL);

		// try ILockBytes first, then IStorage
		STATSTG statStg;
		if ((pItem->m_lpLockBytes == NULL ||
			pItem->m_lpLockBytes->Stat(&statStg, STATFLAG_NONAME) != S_OK) &&
			pItem->m_lpStorage->Stat(&statStg, STATFLAG_NONAME) != S_OK)
		{
			*lpdwObjSize = 0xFFFFFFFF;
		}
		else
		{
			ASSERT(statStg.pwcsName == NULL);
			if (statStg.cbSize.HighPart > 0)
				*lpdwObjSize = 0xFFFFFFFE;
			else if (statStg.cbSize.LowPart == 0)
				*lpdwObjSize = 0xFFFFFFFF;
			else
				*lpdwObjSize = statStg.cbSize.LowPart;
		}
	}

	if (lplpszLabel != NULL)
	{
		TCHAR szFormatLink[128];
		AfxLoadString(AFX_IDS_PASTELINKEDTYPE, szFormatLink, _countof(szFormatLink));
		TCHAR szFormatObj[] = _T("%s");
		LPTSTR lpszFormat = bIsLink ? szFormatLink : szFormatObj;
		CString strType;
		pItem->GetUserType(USERCLASSTYPE_FULL, strType);
		CString strResult;
		strResult.Format(lpszFormat, (LPCTSTR)strType);
		*lplpszLabel = AfxAllocTaskString(strResult);
	}

	if (lplpszType != NULL)
	{
		LPOLESTR lpOleStr;
		pItem->m_lpObject->GetUserType(USERCLASSTYPE_FULL, &lpOleStr);
		*lplpszType = TASKSTRINGOLE2T(lpOleStr);
	}

	if (lplpszShortType != NULL)
	{
		LPOLESTR lpOleStr;
		pItem->m_lpObject->GetUserType(USERCLASSTYPE_SHORT, &lpOleStr);
		*lplpszShortType = TASKSTRINGOLE2T(lpOleStr);
	}

	if (lplpszLocation != NULL)
	{
		if (bIsLink)
		{
			LPOLELINK lpOleLink = NULL;
			pItem->m_lpObject->QueryInterface(IID_IOleLink, (LPVOID*)&lpOleLink);
			ASSERT(lpOleLink != NULL);
			LPOLESTR lpOleStr;
			lpOleLink->GetSourceDisplayName(&lpOleStr);
			*lplpszLocation = TASKSTRINGOLE2T(lpOleStr);
			lpOleLink->Release();
		}
		else
		{
			CDocument* pDoc = (CDocument*)pItem->GetDocument();
			CString strLocation = pDoc->GetPathName();
			if (strLocation.IsEmpty())
				strLocation = pDoc->GetTitle();
			*lplpszLocation = AfxAllocTaskString(strLocation);
		}
	}

	return S_OK;
}

STDMETHODIMP COlePropertiesDialog::XOleUIObjInfo::GetConvertInfo(
	DWORD dwObject, CLSID* lpClassID, WORD* lpwFormat,
	CLSID*, LPCLSID*, UINT*)
{
	COleClientItem* pItem = (COleClientItem*)dwObject;
	ASSERT_VALID(pItem);

	if (lpClassID != NULL)
	{
		if (pItem->GetType() == OT_LINK ||
			S_OK != ReadClassStg(pItem->m_lpStorage, lpClassID))
		{
			pItem->GetClassID(lpClassID);
		}
	}
	if (lpwFormat != NULL)
	{
		*lpwFormat = 0;
		CLIPFORMAT cf;
		if (ReadFmtUserTypeStg(pItem->m_lpStorage, &cf, NULL) == S_OK)
			*lpwFormat = (WORD)cf;
	}

	// Note: leave rest at default

	return S_OK;
}

STDMETHODIMP COlePropertiesDialog::XOleUIObjInfo::ConvertObject(
	DWORD dwObject, REFCLSID clsidNew)
{
	COleClientItem* pItem = (COleClientItem*)dwObject;
	ASSERT_VALID(pItem);

	if (!pItem->ConvertTo(clsidNew))
	{
		AfxMessageBox(AFX_IDP_FAILED_TO_CONVERT,
			MB_OK | MB_ICONEXCLAMATION);
		return E_FAIL;
	}
	return S_OK;
}

STDMETHODIMP COlePropertiesDialog::XOleUIObjInfo::GetViewInfo(
	DWORD dwObject, HGLOBAL* phMetaPict, DWORD* pdvAspect, int* pnCurrentScale)
{
	COleClientItem* pItem = (COleClientItem*)dwObject;
	ASSERT_VALID(pItem);

	if (phMetaPict != NULL)
		*phMetaPict = pItem->GetIconicMetafile();

	if (pdvAspect != NULL)
		*pdvAspect = pItem->GetDrawAspect();

	if (pnCurrentScale != NULL)
		*pnCurrentScale = 100;  // 100% (arbitrary for now)

	return S_OK;
}

STDMETHODIMP COlePropertiesDialog::XOleUIObjInfo::SetViewInfo(
	DWORD dwObject, HGLOBAL hMetaPict, DWORD dvAspect,
	int nCurrentScale, BOOL bRelativeToOrig)
{
	METHOD_PROLOGUE_EX_(COlePropertiesDialog, OleUIObjInfo)
	COleClientItem* pItem = (COleClientItem*)dwObject;
	ASSERT_VALID(pItem);

	// handle aspect changes
	if (dvAspect != -1)
	{
		pItem->OnChange(OLE_CHANGED_ASPECT, dvAspect);
		pItem->SetDrawAspect((DVASPECT)dvAspect);

		// force scale to 100% when changing aspects
		if (dvAspect == DVASPECT_ICON)
		{
			nCurrentScale = 100;
			bRelativeToOrig = TRUE;
		}
		else if (nCurrentScale == -1)
		{
			nCurrentScale = 100;
			bRelativeToOrig = FALSE;
		}
	}

	// handle icon representation changes
	if (hMetaPict != NULL)
	{
		pItem->SetIconicMetafile(hMetaPict);
		if (pItem->GetDrawAspect() == DVASPECT_ICON)
			pItem->OnChange(OLE_CHANGED, (DWORD)DVASPECT_ICON);
	}

	// handle scale changes
	if (nCurrentScale != -1)
	{
		pThis->OnApplyScale(pItem, nCurrentScale, bRelativeToOrig);
	}

	return S_OK;
}

BOOL COlePropertiesDialog::OnApplyScale(COleClientItem*, int, BOOL)
{
	// Note: no default implementation. Must override or scaling
	//  controls will be disabled during the DoModal call.

	return FALSE;
}

/////////////////////////////////////////////////////////////////////////////
// COlePropertiesDialog diagnostics

#ifdef _DEBUG

void COlePropertiesDialog::Dump(CDumpContext& dc) const
{
	COleDialog::Dump(dc);
}

void COlePropertiesDialog::AssertValid() const
{
	COleDialog::AssertValid();
	ASSERT(m_op.cbStruct == sizeof(m_op));
	ASSERT(m_gp.cbStruct == sizeof(m_gp));
	ASSERT(m_vp.cbStruct == sizeof(m_vp));
	ASSERT(m_lp.cbStruct == sizeof(m_lp));
}

#endif

////////////////////////////////////////////////////////////////////////////
// ChangeSource dialog wrapper

COleChangeSourceDialog::COleChangeSourceDialog(COleClientItem* pItem,
	CWnd* pParentWnd) : COleDialog(pParentWnd), m_xLinkInfo(NULL)
{
	ASSERT_VALID(pItem);

	memset(&m_cs, 0, sizeof(m_cs)); // initialize structure to 0/NULL

	// fill in common part
	m_cs.cbStruct = sizeof(m_cs);
	m_cs.dwFlags = 0;
	if (AfxHelpEnabled())
		m_cs.dwFlags |= CSF_SHOWHELP;
	m_cs.lpfnHook = AfxOleHookProc;
	m_nIDHelp = AFX_IDD_CHANGESOURCE;

	// specific to this dialog
	m_cs.lpOleUILinkContainer = &m_xLinkInfo;
	m_cs.dwLink = (DWORD)pItem;
}

int COleChangeSourceDialog::DoModal()
{
	ASSERT_VALID(this);
	ASSERT(m_cs.lpfnHook != NULL);  // can still be a user hook

	m_cs.hWndOwner = PreModal();
	int iResult = MapResult(::OleUIChangeSource(&m_cs));
	PostModal();
	return iResult;
}

void COleChangeSourceDialog::PreInitDialog()
{
	// automatic centering doesn't work for this dialog
	if (!(GetStyle() & WS_CHILD))
		CenterWindow();
}

COleChangeSourceDialog::~COleChangeSourceDialog()
{
	CoTaskMemFree(m_cs.lpszTo);
	CoTaskMemFree(m_cs.lpszFrom);
	CoTaskMemFree(m_cs.lpszDisplayName);
}

/////////////////////////////////////////////////////////////////////////////
// COleChangeSourceDialog diagnostics

#ifdef _DEBUG

void COleChangeSourceDialog::Dump(CDumpContext& dc) const
{
	COleDialog::Dump(dc);

	dc << "m_cs.cbStruct = " << m_cs.cbStruct;
	dc << "\nm_cs.dwFlags = " << (LPVOID)m_cs.dwFlags;
	dc << "\nm_cs.hWndOwner = " << (UINT)m_cs.hWndOwner;
	dc << "\nm_cs.lpszCaption = " << m_cs.lpszCaption;
	dc << "\nm_cs.lCustData = " << (LPVOID)m_cs.lCustData;
	dc << "\nm_cs.hInstance = " << (UINT)m_cs.hInstance;
	dc << "\nm_cs.lpszTemplate = " << (LPVOID)m_cs.lpszTemplate;
	dc << "\nm_cs.hResource = " << (UINT)m_cs.hResource;
	if (m_cs.lpfnHook == AfxOleHookProc)
		dc << "\nhook function set to standard MFC hook function";
	else
		dc << "\nhook function set to non-standard hook function";

	dc << "\n";
}

void COleChangeSourceDialog::AssertValid() const
{
	COleDialog::AssertValid();
	ASSERT(m_cs.cbStruct == sizeof(m_cs));
	ASSERT(m_cs.lpfnHook != NULL);
}

#endif

#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif

IMPLEMENT_DYNAMIC(COlePropertiesDialog, COleDialog)
IMPLEMENT_DYNAMIC(COleChangeSourceDialog, COleDialog)

/////////////////////////////////////////////////////////////////////////////
