#define STRICT #include #include #include /* * NOTE: These constants are duplicated in Win32TYMEDSelectionTest.java. * Be sure to keep them is sync. */ static const int CODE_OK = 0; static const int CODE_INVALID_TYMED_FAILURE = 1; static const int CODE_INVALID_DATA_FAILURE = 2; static const int CODE_OTHER_FAILURE = 3; static const char* TEST_TEXT = "TEST TEXT"; static const int X = 300; static const int Y = 300; static const int WIDTH = 100; static const int HEIGHT = 100; static const char szClassName[] = "test window"; class TestDropTarget : virtual public IDropTarget { public: TestDropTarget(); virtual ~TestDropTarget(); virtual HRESULT __stdcall QueryInterface(REFIID riid, void __RPC_FAR*__RPC_FAR *ppvObject); virtual ULONG __stdcall AddRef(void); virtual ULONG __stdcall Release(void); virtual HRESULT __stdcall DragEnter(IDataObject __RPC_FAR *pDataObject, DWORD grfKeyState, POINTL pt, DWORD __RPC_FAR *pdwEffect); virtual HRESULT __stdcall DragOver(DWORD grfKeyState, POINTL pt, DWORD __RPC_FAR *pdwEffect); virtual HRESULT __stdcall DragLeave(void); virtual HRESULT __stdcall Drop(IDataObject __RPC_FAR *pDataObject, DWORD grfKeyState, POINTL pt, DWORD __RPC_FAR *pdwEffect); virtual int CheckTransferTymed(IDataObject __RPC_FAR *pDataObj, DWORD tymed); virtual void DumpTestResult(DWORD tymed, int nTestResult); private: unsigned int m_refs; }; TestDropTarget::TestDropTarget() { m_refs = 0U; AddRef(); } TestDropTarget::~TestDropTarget() {} HRESULT __stdcall TestDropTarget::QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject) { if (riid == IID_IUnknown) { *ppvObject = (void __RPC_FAR *__RPC_FAR)(IUnknown*)this; AddRef(); return S_OK; } else if (riid == IID_IDropTarget) { *ppvObject = (void __RPC_FAR *__RPC_FAR)(IDropTarget*)this; AddRef(); return S_OK; } else { *ppvObject = (void __RPC_FAR *__RPC_FAR)NULL; return E_NOINTERFACE; } } ULONG __stdcall TestDropTarget::AddRef() { return (ULONG)++m_refs; } ULONG __stdcall TestDropTarget::Release() { int refs; if ((refs = --m_refs) == 0) delete this; return (ULONG)refs; } HRESULT __stdcall TestDropTarget::DragEnter(IDataObject __RPC_FAR *pDataObj, DWORD grfKeyState, POINTL pt, DWORD __RPC_FAR *pdwEffect) { *pdwEffect = DROPEFFECT_COPY; return S_OK; } HRESULT __stdcall TestDropTarget::DragOver(DWORD grfKeyState, POINTL pt, DWORD __RPC_FAR *pdwEffect) { *pdwEffect = DROPEFFECT_COPY; return S_OK; } HRESULT __stdcall TestDropTarget::DragLeave() { return S_OK; } HRESULT __stdcall TestDropTarget::Drop(IDataObject __RPC_FAR *pDataObj, DWORD grfKeyState, POINTL pt, DWORD __RPC_FAR *pdwEffect) { int nExitCode = CODE_OTHER_FAILURE; HRESULT res = S_OK; *pdwEffect = DROPEFFECT_NONE; nExitCode = CheckTransferTymed(pDataObj, TYMED_HGLOBAL); if (nExitCode == CODE_OK) { nExitCode = CheckTransferTymed(pDataObj, TYMED_ISTREAM); } if (nExitCode == CODE_OK) { nExitCode = CheckTransferTymed(pDataObj, TYMED_ENHMF); } if (nExitCode == CODE_OK) { *pdwEffect = DROPEFFECT_COPY; } ::PostQuitMessage(nExitCode); return res; } int TestDropTarget::CheckTransferTymed(IDataObject __RPC_FAR *pDataObj, DWORD tymed) { int nExitCode = CODE_OTHER_FAILURE; FORMATETC format; switch (tymed) { case TYMED_HGLOBAL: case TYMED_ISTREAM: format.cfFormat = CF_TEXT; break; case TYMED_ENHMF: format.cfFormat = CF_ENHMETAFILE; break; } format.ptd = NULL; format.lindex = -1; format.dwAspect = DVASPECT_CONTENT; format.tymed = tymed; STGMEDIUM stgmedium; HRESULT res = pDataObj->GetData(&format, &stgmedium); if (res == S_OK) { if (stgmedium.tymed == tymed) { nExitCode = CODE_INVALID_DATA_FAILURE; switch (tymed) { case TYMED_HGLOBAL: { DWORD size = ::GlobalSize(stgmedium.hGlobal); if (size != 0) { LPVOID data = ::GlobalLock(stgmedium.hGlobal); if (strcmp((const char*)data, TEST_TEXT) == 0) { nExitCode = CODE_OK; } } break; } case TYMED_ISTREAM: { IStream* pstm = stgmedium.pstm; if (pstm != NULL) { STATSTG statstg; if (pstm->Stat(&statstg, STATFLAG_NONAME) == S_OK) { if (statstg.cbSize.LowPart >= strlen(TEST_TEXT) && statstg.cbSize.HighPart == 0) { ULONG size = (ULONG)statstg.cbSize.QuadPart; ULONG act = 0; LPVOID buf = calloc(1, size); if (buf != NULL) { if (pstm->Read((void*)buf,size,&act) == S_OK && strcmp((const char*)buf, TEST_TEXT) == 0) { nExitCode = CODE_OK; } free(buf); } } } } break; } case TYMED_ENHMF: { HENHMETAFILE hemf = stgmedium.hEnhMetaFile; UINT size = ::GetEnhMetaFileHeader(hemf, 0, NULL); BOOL headerValid = FALSE; if (size != 0) { LPENHMETAHEADER lpemh = (LPENHMETAHEADER)calloc(1, size); if (lpemh != NULL) { if (::GetEnhMetaFileHeader(hemf, size, lpemh) == size) { headerValid = TRUE; } free(lpemh); } } if (headerValid == TRUE) { UINT size = ::GetEnhMetaFileBits(hemf, 0, NULL); if (size != 0) { LPBYTE lpbits = (LPBYTE)calloc(1, size); if (lpbits != NULL) { if (::GetEnhMetaFileBits(hemf, size, lpbits) == size) { nExitCode = CODE_OK; } free(lpbits); } } } break; } } } else { nExitCode = CODE_INVALID_TYMED_FAILURE; } } DumpTestResult(tymed, nExitCode); ::ReleaseStgMedium(&stgmedium); return nExitCode; } void TestDropTarget::DumpTestResult(DWORD tymed, int nTestResult) { switch (tymed) { case TYMED_HGLOBAL: fprintf(stderr,"Test transfer for TYMED_HGLOBAL: "); break; case TYMED_ISTREAM: fprintf(stderr,"Test transfer for TYMED_ISTREAM: "); break; case TYMED_ENHMF: fprintf(stderr,"Test transfer for TYMED_ENHMF: "); break; default: fprintf(stderr,"Test transfer for unknown TYMED %d: ", tymed); break; } switch (nTestResult) { case CODE_OK: fprintf(stderr,"PASSED"); break; case CODE_INVALID_TYMED_FAILURE: fprintf(stderr,"FAILED: invalid TYMED detected"); break; case CODE_INVALID_DATA_FAILURE: fprintf(stderr,"FAILED: invalid transfer data detected"); break; case CODE_OTHER_FAILURE: fprintf(stderr,"FAILED: other failure detected"); break; default: fprintf(stderr,"FAILED: unknown test result %d", nTestResult); break; } fprintf(stderr,"\n"); } LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam ) { switch (iMessage) { case WM_DESTROY: ::RevokeDragDrop(hWnd); ::OleUninitialize(); ::PostQuitMessage(0); break; default: return ::DefWindowProc( hWnd, iMessage, wParam, lParam ); } return 0; } int main(int argc, char* argv[]) { HMODULE hInstance = ::GetModuleHandle(NULL); WNDCLASS wndclass; wndclass.style = CS_OWNDC; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = NULL; wndclass.hCursor = NULL; wndclass.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szClassName; if (::RegisterClass(&wndclass) == 0) { exit( FALSE ); } HWND hMainWnd = ::CreateWindowEx(WS_EX_CLIENTEDGE, szClassName, szClassName, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, X, Y, WIDTH, HEIGHT, NULL, NULL, hInstance, NULL); if (hMainWnd == NULL) { exit(FALSE); } ::ShowWindow(hMainWnd, SW_SHOWNORMAL); ::UpdateWindow(hMainWnd); ::OleInitialize(NULL); HRESULT res = ::RegisterDragDrop(hMainWnd, new TestDropTarget()); MSG msg; while (::GetMessage(&msg, NULL, 0, 0)) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); } ::OleUninitialize(); ::UnregisterClass(szClassName, hInstance); return msg.wParam; }