昨天写《用程序来模拟文件拖放》的时候,程序刚刚运行通过,测试用例是向 WordPad 也即写字板里面扔一个文件。今天把程序改了改,向真实案例继续靠近,往 360 加固助手里扔 apk 包,不出意外地失败了。我就说嘛,老天爷怎么会如此轻易放过老夫。
不过这个情况并不棘手。因为截至目前,已经证明拖放的支持基础是很坚实的。为什么 360 加固助手不能像预期那样正确接收投喂,几乎可以百分百确定是格式枚举部分的支持没有完成而导致的。还好有前人在这块儿做出过泽惠吾等的努力,实现过一个开箱即用的格式枚举辅助类,略作修改后投入使用,再测试,就一马平川了。
涉及到对上一篇文章中代码的改动有两处,一是加上 #include "enumfmt.h"
,二是对 EnumFormatEtc
方法进行填充,在原有的一条返回语句前增加以下三行:
C++
1 2 3 |
FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; if(dwDirection == DATADIR_GET) return CEnumFormatEtc::Create(1, &fmt, ppEnumFormatEtc); |
此处附上 enumfmt.h
头文件的内容如下:
C++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
#include <windows.h> class CEnumFormatEtc : public IEnumFORMATETC { static HRESULT CreateEnumFormatEtc(UINT nNumFormats, FORMATETC *pFormatEtc, IEnumFORMATETC **ppEnumFormatEtc) { if(nNumFormats == 0 || pFormatEtc == 0 || ppEnumFormatEtc == 0) return E_INVALIDARG; *ppEnumFormatEtc = new CEnumFormatEtc(pFormatEtc, nNumFormats); return (*ppEnumFormatEtc) ? S_OK : E_OUTOFMEMORY; } // Helper function to perform a "deep" copy of a FORMATETC static void DeepCopyFormatEtc(FORMATETC *dest, FORMATETC *source) { // copy the source FORMATETC into dest *dest = *source; if(source->ptd) { // allocate memory for the DVTARGETDEVICE if necessary dest->ptd = (DVTARGETDEVICE*)CoTaskMemAlloc(sizeof(DVTARGETDEVICE)); // copy the contents of the source DVTARGETDEVICE into dest->ptd *(dest->ptd) = *(source->ptd); } } public: // "Drop-in" replacement for SHCreateStdEnumFmtEtc. Called by CDataObject::EnumFormatEtc static HRESULT Create(UINT nNumFormats, FORMATETC *pFormatEtc, IEnumFORMATETC **ppEnumFormatEtc) { return CreateEnumFormatEtc(nNumFormats, pFormatEtc, ppEnumFormatEtc); } public: // // IUnknown members // HRESULT __stdcall QueryInterface (REFIID iid, void ** ppvObject) { // check to see what interface has been requested if(iid == IID_IEnumFORMATETC || iid == IID_IUnknown) { AddRef(); *ppvObject = this; return S_OK; } *ppvObject = 0; return E_NOINTERFACE; } ULONG __stdcall AddRef (void) { // increment object reference count return InterlockedIncrement(&m_lRefCount); } ULONG __stdcall Release (void) { // decrement object reference count LONG count = InterlockedDecrement(&m_lRefCount); if(count == 0) { delete this; return 0; } return count; } // // IEnumFormatEtc members // // If the returned FORMATETC structure contains a non-null "ptd" member, then // the caller must free this using CoTaskMemFree (stated in the COM documentation) // HRESULT __stdcall Next (ULONG celt, FORMATETC * rgelt, ULONG * pceltFetched) { // validate arguments if(celt == 0 || rgelt == 0) return E_INVALIDARG; // copy FORMATETC structures into caller's buffer ULONG copied = 0; while(m_nIndex < m_nNumFormats && copied < celt) { DeepCopyFormatEtc(&rgelt[copied], &m_pFormatEtc[m_nIndex]); copied++; m_nIndex++; } // store result if(pceltFetched != 0) *pceltFetched = copied; // did we copy all that was requested? return (copied == celt) ? S_OK : S_FALSE; } HRESULT __stdcall Skip (ULONG celt) { m_nIndex += celt; return (m_nIndex <= m_nNumFormats) ? S_OK : S_FALSE; } HRESULT __stdcall Reset (void) { m_nIndex = 0; return S_OK; } HRESULT __stdcall Clone (IEnumFORMATETC ** ppEnumFormatEtc) { // make a duplicate enumerator HRESULT hResult = CreateEnumFormatEtc(m_nNumFormats, m_pFormatEtc, ppEnumFormatEtc); if(hResult == S_OK) { // manually set the index state ((CEnumFormatEtc *) *ppEnumFormatEtc)->m_nIndex = m_nIndex; } return hResult; } // // Construction / Destruction // CEnumFormatEtc(FORMATETC *pFormatEtc, int nNumFormats) { m_lRefCount = 1; m_nIndex = 0; m_nNumFormats = nNumFormats; m_pFormatEtc = new FORMATETC[nNumFormats]; // copy the FORMATETC structures for(int i = 0; i < nNumFormats; i++) { DeepCopyFormatEtc(&m_pFormatEtc[i], &pFormatEtc[i]); } } ~CEnumFormatEtc() { if(m_pFormatEtc) { for(ULONG i = 0; i < m_nNumFormats; i++) { if(m_pFormatEtc[i].ptd) CoTaskMemFree(m_pFormatEtc[i].ptd); } delete[] m_pFormatEtc; } } private: LONG m_lRefCount; // Reference count for this COM interface ULONG m_nIndex; // current enumerator index ULONG m_nNumFormats; // number of FORMATETC members FORMATETC * m_pFormatEtc; // array of FORMATETC objects }; |