📄 mtlcom.h
字号:
#ifndef __MTLCOM_H__
#define __MTLCOM_H__
#pragma once
#ifndef __MTLBASE_H__
#error mtlcom.h requires mtlbase.h to be included first
#endif
#ifndef _SHLOBJ_H_
#error mtlcom.h requires shlobj.h to be included first
#endif
////////////////////////////////////////////////////////////////////////////
// MTL Version 0.10
// Copyright (C) 2001 MB<mb2@geocities.co.jp>
// All rights unreserved.
//
// This file is a part of Mb Template Library.
// The code and information is *NOT* provided "as-is" without
// warranty of any kind, either expressed or implied.
//
// MtlCom.h: Last updated: February 12, 2001
////////////////////////////////////////////////////////////////////////////
#define HANDLE_MENU_MESSAGE_CONTEXTMENU(x) \
if(uMsg == WM_INITMENUPOPUP || uMsg == WM_DRAWITEM || uMsg == WM_MEASUREITEM) \
{ \
if (x != NULL) { \
bHandled = TRUE; \
lResult = x->HandleMenuMsg(uMsg, wParam, lParam); \
} \
else { \
bHandled = FALSE; \
} \
if(bHandled) \
return TRUE; \
}
namespace MTL
{
inline void MtlCheckError(SCODE sc)
{
if (FAILED(sc)) {
if (sc == E_OUTOFMEMORY)
ATLTRACE2(atlTraceCOM, 0, "MtlCheckError Error : OOM\n");
else
ATLTRACE2(atlTraceCOM, 0, "MtlCheckError Error : MISC\n");
}
}
// cf. "ATL Internals"
inline HRESULT WINAPI _This(void* pv, REFIID iid, void** ppvObject, DWORD) {
ATLASSERT(iid == IID_NULL);
*ppvObject = pv;
return S_OK;
}
// Helper for creating default FORMATETC from cfFormat
LPFORMATETC _MtlFillFormatEtc(
LPFORMATETC lpFormatEtc, CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtcFill)
{
ATLASSERT(lpFormatEtcFill != NULL);
if (lpFormatEtc == NULL && cfFormat != 0)
{
lpFormatEtc = lpFormatEtcFill;
lpFormatEtc->cfFormat = cfFormat;
lpFormatEtc->ptd = NULL;
lpFormatEtc->dwAspect = DVASPECT_CONTENT;
lpFormatEtc->lindex = -1;
lpFormatEtc->tymed = (DWORD) -1;
}
return lpFormatEtc;
}
bool MtlIsDataAvailable(IDataObject* pDataObject, CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc = NULL)
{
ATLASSERT(pDataObject != NULL);
// fill in FORMATETC struct
FORMATETC formatEtc;
lpFormatEtc = _MtlFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
// attempt to get the data
return pDataObject->QueryGetData(lpFormatEtc) == S_OK;
}
bool MtlGetDropFileName(IDataObject* pDataObject, CSimpleArray<CString>& arrFileNames)
{
if (!MtlIsDataAvailable(pDataObject, CF_HDROP))
return false;
FORMATETC formatetc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stgmedium;
HRESULT hr = pDataObject->GetData(&formatetc, &stgmedium);
if (FAILED(hr) || stgmedium.hGlobal == NULL) {
return false;
}
HDROP hDropInfo = (HDROP)stgmedium.hGlobal;
UINT nFiles = ::DragQueryFile(hDropInfo, (UINT)-1, NULL, 0);
for (UINT iFile = 0; iFile < nFiles; iFile++) {
TCHAR szFileName[_MAX_PATH];
::DragQueryFile(hDropInfo, iFile, szFileName, _MAX_PATH);
arrFileNames.Add(CString(szFileName));
}
::DragFinish(hDropInfo);// required?
::ReleaseStgMedium(&stgmedium);
if (arrFileNames.GetSize() > 0)
return true;
else
return false;
}
// Implementation
bool MtlGetHGlobalText(IDataObject* pDataObject, CString& strText, CLIPFORMAT cfFormat = CF_TEXT)
{
bool bResult = false;
if (!MtlIsDataAvailable(pDataObject, cfFormat))
return false;
FORMATETC formatetc = { cfFormat, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stgmedium;
HRESULT hr = pDataObject->GetData(&formatetc, &stgmedium);
if (SUCCEEDED(hr)) {
if (stgmedium.hGlobal != NULL) {
HGLOBAL hText = stgmedium.hGlobal;
strText = reinterpret_cast<LPSTR>(::GlobalLock(hText));
::GlobalUnlock(hText);
bResult = true;
}
::ReleaseStgMedium(&stgmedium);
}
return bResult;
}
// Thanks to www.nakka.com
// Even IE creates a shortcut file for every link, what the hell is OLE.
template <class _InputStringIter>
HDROP MtlCreateDropFile(_InputStringIter __first, _InputStringIter __last)
{
if (__first == __last)
return NULL;
//filename\0...\0filename\0...\0filename\0\0
int nLen = 0;
_InputStringIter it;
for (it = __first; it != __last; ++it) {
nLen += ::lstrlen(*it);
nLen += 1; // for '\0' separator
}
nLen += 1; // for the last '\0'
HDROP hDrop = (HDROP)::GlobalAlloc(GHND, sizeof(DROPFILES) + nLen*sizeof(TCHAR));
if (hDrop == NULL)
return NULL;
LPDROPFILES lpDropFiles;
lpDropFiles = (LPDROPFILES)::GlobalLock(hDrop);
lpDropFiles->pFiles = sizeof(DROPFILES);
lpDropFiles->pt.x = 0;
lpDropFiles->pt.y = 0;
lpDropFiles->fNC = FALSE;
#ifdef _UNICODE
lpDropFiles->fWide = TRUE;
#else
lpDropFiles->fWide = FALSE;
#endif
TCHAR* psz = (TCHAR*)(lpDropFiles + 1);
for (it = __first; it != __last; ++it) {
::lstrcpy(psz, (*it));
psz += ::lstrlen(*it) + 1;// skip a '\0' separator
}
::GlobalUnlock(hDrop);
return hDrop;
}
HDROP MtlCreateDropFile(CSimpleArray<CString>& arrFiles)
{
if (arrFiles.GetSize() == 0)
return NULL;
//filename\0...\0filename\0...\0filename\0\0
int nLen = 0;
int i;
for (i = 0; i < arrFiles.GetSize(); ++i) {
nLen += arrFiles[i].GetLength();
nLen += 1; // for '\0' separator
}
nLen += 1; // for the last '\0'
HDROP hDrop = (HDROP)::GlobalAlloc(GHND, sizeof(DROPFILES) + nLen*sizeof(TCHAR));
if (hDrop == NULL)
return NULL;
LPDROPFILES lpDropFiles;
lpDropFiles = (LPDROPFILES)::GlobalLock(hDrop);
lpDropFiles->pFiles = sizeof(DROPFILES);
lpDropFiles->pt.x = 0;
lpDropFiles->pt.y = 0;
lpDropFiles->fNC = FALSE;
#ifdef _UNICODE
lpDropFiles->fWide = TRUE;
#else
lpDropFiles->fWide = FALSE;
#endif
TCHAR* psz = (TCHAR*)(lpDropFiles + 1);
for (i = 0; i < arrFiles.GetSize(); ++i) {
::lstrcpy(psz, arrFiles[i]);
psz += arrFiles[i].GetLength() + 1;// skip a '\0' separator
}
::GlobalUnlock(hDrop);
return hDrop;
}
/////////////////////////////////////////////////////////////////////////////
// CSafeArray class
typedef const SAFEARRAY* LPCSAFEARRAY;
typedef const VARIANT* LPCVARIANT;
/////////////////////////////////////////////////////////////////////////////
// Helper for initializing CComSafeArray
static bool _MtlCompareSafeArrays(SAFEARRAY* parray1, SAFEARRAY* parray2)
{
bool bCompare = false;
// If one is NULL they must both be NULL to compare
if (parray1 == NULL || parray2 == NULL)
{
return parray1 == parray2;
}
// Dimension must match and if 0, then arrays compare
DWORD dwDim1 = ::SafeArrayGetDim(parray1);
DWORD dwDim2 = ::SafeArrayGetDim(parray2);
if (dwDim1 != dwDim2)
return false;
else if (dwDim1 == 0)
return true;
// Element size must match
DWORD dwSize1 = ::SafeArrayGetElemsize(parray1);
DWORD dwSize2 = ::SafeArrayGetElemsize(parray2);
if (dwSize1 != dwSize2)
return false;
long* pLBound1 = NULL;
long* pLBound2 = NULL;
long* pUBound1 = NULL;
long* pUBound2 = NULL;
void* pData1 = NULL;
void* pData2 = NULL;
// Bounds must match
ATLTRY(pLBound1 = new long[dwDim1]);
ATLTRY(pLBound2 = new long[dwDim2]);
ATLTRY(pUBound1 = new long[dwDim1]);
ATLTRY(pUBound2 = new long[dwDim2]);
size_t nTotalElements = 1;
// Get and compare bounds
for (DWORD dwIndex = 0; dwIndex < dwDim1; dwIndex++)
{
MtlCheckError(::SafeArrayGetLBound(
parray1, dwIndex+1, &pLBound1[dwIndex]));
MtlCheckError(::SafeArrayGetLBound(
parray2, dwIndex+1, &pLBound2[dwIndex]));
MtlCheckError(::SafeArrayGetUBound(
parray1, dwIndex+1, &pUBound1[dwIndex]));
MtlCheckError(::SafeArrayGetUBound(
parray2, dwIndex+1, &pUBound2[dwIndex]));
// Check the magnitude of each bound
if (pUBound1[dwIndex] - pLBound1[dwIndex] !=
pUBound2[dwIndex] - pLBound2[dwIndex])
{
delete[] pLBound1;
delete[] pLBound2;
delete[] pUBound1;
delete[] pUBound2;
return false;
}
// Increment the element count
nTotalElements *= pUBound1[dwIndex] - pLBound1[dwIndex] + 1;
}
// Access the data
MtlCheckError(::SafeArrayAccessData(parray1, &pData1));
MtlCheckError(::SafeArrayAccessData(parray2, &pData2));
// Calculate the number of bytes of data and compare
size_t nSize = nTotalElements * dwSize1;
int nOffset = memcmp(pData1, pData2, nSize);
bCompare = (nOffset == 0);
// Release the array locks
MtlCheckError(::SafeArrayUnaccessData(parray1));
MtlCheckError(::SafeArrayUnaccessData(parray2));
// Clean up bounds arrays
delete[] pLBound1;
delete[] pLBound2;
delete[] pUBound1;
delete[] pUBound2;
return bCompare;
}
/////////////////////////////////////////////////////////////////////////////
// CComSafeArray class
class CComSafeArray : public tagVARIANT
{
public:
// Data members
// Cache info to make element access (operator []) faster
DWORD m_dwElementSize;
DWORD m_dwDims;
//Constructors
CComSafeArray()
{
_SafeArrayInit(this);
vt = VT_EMPTY;
}
~CComSafeArray()
{
Clear();
}
CComSafeArray(const SAFEARRAY& saSrc, VARTYPE vtSrc)
{
_SafeArrayInit(this);
vt = (VARTYPE)(vtSrc | VT_ARRAY);
MtlCheckError(::SafeArrayCopy((LPSAFEARRAY)&saSrc, &parray));
m_dwDims = GetDim();
m_dwElementSize = GetElemSize();
}
CComSafeArray(LPCSAFEARRAY pSrc, VARTYPE vtSrc)
{
_SafeArrayInit(this);
vt = (VARTYPE)(vtSrc | VT_ARRAY);
MtlCheckError(::SafeArrayCopy((LPSAFEARRAY)pSrc, &parray));
m_dwDims = GetDim();
m_dwElementSize = GetElemSize();
}
CComSafeArray(const CComSafeArray& saSrc)
{
_SafeArrayInit(this);
*this = saSrc;
m_dwDims = GetDim();
m_dwElementSize = GetElemSize();
}
CComSafeArray(const VARIANT& varSrc)
{
_SafeArrayInit(this);
*this = varSrc;
m_dwDims = GetDim();
m_dwElementSize = GetElemSize();
}
CComSafeArray(LPCVARIANT pSrc)
{
_SafeArrayInit(this);
*this = pSrc;
m_dwDims = GetDim();
m_dwElementSize = GetElemSize();
}
void _SafeArrayInit(CComSafeArray* psa)
{
::memset(psa, 0, sizeof(*psa));
}
void Clear()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -