1 #define  STRICT
   2 #include <stdio.h>
   3 #include <windows.h>
   4 #include <ole2.h>
   5 
   6 /*
   7  * NOTE: These constants are duplicated in Win32TYMEDSelectionTest.java.
   8  * Be sure to keep them is sync.
   9  */
  10 static const int CODE_OK = 0;
  11 static const int CODE_INVALID_TYMED_FAILURE = 1;
  12 static const int CODE_INVALID_DATA_FAILURE = 2;
  13 static const int CODE_OTHER_FAILURE = 3;
  14 static const char* TEST_TEXT = "TEST TEXT";
  15 static const int X = 300;
  16 static const int Y = 300;
  17 static const int WIDTH = 100;
  18 static const int HEIGHT = 100;
  19 
  20 static const char szClassName[] = "test window";
  21 
  22 class TestDropTarget : virtual public IDropTarget {
  23   public:
  24     TestDropTarget();
  25     virtual ~TestDropTarget();
  26 
  27     virtual HRESULT __stdcall QueryInterface(REFIID riid,
  28                                         void __RPC_FAR*__RPC_FAR *ppvObject);
  29     virtual ULONG   __stdcall AddRef(void);
  30     virtual ULONG   __stdcall Release(void);
  31     virtual HRESULT __stdcall DragEnter(IDataObject __RPC_FAR *pDataObject,
  32                                         DWORD grfKeyState, POINTL pt,
  33                                         DWORD __RPC_FAR *pdwEffect);
  34     virtual HRESULT __stdcall DragOver(DWORD grfKeyState, POINTL pt,
  35                                        DWORD __RPC_FAR *pdwEffect);
  36     virtual HRESULT __stdcall DragLeave(void);
  37     virtual HRESULT __stdcall Drop(IDataObject __RPC_FAR *pDataObject,
  38                                    DWORD grfKeyState, POINTL pt,
  39                                    DWORD __RPC_FAR *pdwEffect);
  40     virtual int CheckTransferTymed(IDataObject __RPC_FAR *pDataObj,
  41                                    DWORD tymed);
  42     virtual void DumpTestResult(DWORD tymed, int nTestResult);
  43   private:
  44     unsigned int m_refs;
  45 };
  46 
  47 TestDropTarget::TestDropTarget() {
  48     m_refs          = 0U;
  49     AddRef();
  50 }
  51 
  52 TestDropTarget::~TestDropTarget() {}
  53 
  54 HRESULT __stdcall
  55 TestDropTarget::QueryInterface(REFIID riid,
  56                                void __RPC_FAR *__RPC_FAR *ppvObject) {
  57     if (riid == IID_IUnknown) {
  58         *ppvObject = (void __RPC_FAR *__RPC_FAR)(IUnknown*)this;
  59         AddRef();
  60         return S_OK;
  61     } else if (riid == IID_IDropTarget) {
  62         *ppvObject = (void __RPC_FAR *__RPC_FAR)(IDropTarget*)this;
  63         AddRef();
  64         return S_OK;
  65     } else {
  66         *ppvObject = (void __RPC_FAR *__RPC_FAR)NULL;
  67         return E_NOINTERFACE;
  68     }
  69 }
  70 
  71 ULONG __stdcall
  72 TestDropTarget::AddRef() {
  73     return (ULONG)++m_refs;
  74 }
  75 
  76 ULONG __stdcall
  77 TestDropTarget::Release() {
  78     int refs;
  79     if ((refs = --m_refs) == 0) delete this;
  80     return (ULONG)refs;
  81 }
  82 
  83 HRESULT __stdcall
  84 TestDropTarget::DragEnter(IDataObject __RPC_FAR *pDataObj, DWORD grfKeyState,
  85                           POINTL pt, DWORD __RPC_FAR *pdwEffect) {
  86     *pdwEffect = DROPEFFECT_COPY;
  87     return S_OK;
  88 }
  89 
  90 HRESULT __stdcall
  91 TestDropTarget::DragOver(DWORD grfKeyState, POINTL pt,
  92                          DWORD __RPC_FAR *pdwEffect) {
  93     *pdwEffect = DROPEFFECT_COPY;
  94     return S_OK;
  95 }
  96 
  97 HRESULT __stdcall
  98 TestDropTarget::DragLeave() {
  99         return S_OK;
 100 }
 101 
 102 HRESULT __stdcall
 103 TestDropTarget::Drop(IDataObject __RPC_FAR *pDataObj, DWORD grfKeyState,
 104                      POINTL pt, DWORD __RPC_FAR *pdwEffect) {
 105     int nExitCode = CODE_OTHER_FAILURE;
 106     HRESULT res = S_OK;
 107 
 108     *pdwEffect = DROPEFFECT_NONE;
 109 
 110     nExitCode = CheckTransferTymed(pDataObj, TYMED_HGLOBAL);
 111     if (nExitCode == CODE_OK) {
 112         nExitCode = CheckTransferTymed(pDataObj, TYMED_ISTREAM);
 113     }
 114     if (nExitCode == CODE_OK) {
 115         nExitCode = CheckTransferTymed(pDataObj, TYMED_ENHMF);
 116     }
 117 
 118     if (nExitCode == CODE_OK) {
 119         *pdwEffect = DROPEFFECT_COPY;
 120     }
 121     ::PostQuitMessage(nExitCode);
 122     return res;
 123 }
 124 
 125 int
 126 TestDropTarget::CheckTransferTymed(IDataObject __RPC_FAR *pDataObj,
 127                                    DWORD tymed) {
 128     int nExitCode = CODE_OTHER_FAILURE;
 129     FORMATETC format;
 130 
 131     switch (tymed) {
 132     case TYMED_HGLOBAL:
 133     case TYMED_ISTREAM:
 134         format.cfFormat = CF_TEXT;
 135         break;
 136     case TYMED_ENHMF:
 137         format.cfFormat = CF_ENHMETAFILE;
 138         break;
 139     }
 140     format.ptd = NULL;
 141     format.lindex = -1;
 142     format.dwAspect = DVASPECT_CONTENT;
 143     format.tymed = tymed;
 144 
 145     STGMEDIUM stgmedium;
 146 
 147     HRESULT res = pDataObj->GetData(&format, &stgmedium);
 148     if (res == S_OK) {
 149         if (stgmedium.tymed == tymed) {
 150             nExitCode = CODE_INVALID_DATA_FAILURE;
 151 
 152             switch (tymed) {
 153             case TYMED_HGLOBAL: {
 154                 DWORD size = ::GlobalSize(stgmedium.hGlobal);
 155                 if (size != 0) {
 156                     LPVOID data = ::GlobalLock(stgmedium.hGlobal);
 157                     if (strcmp((const char*)data, TEST_TEXT) == 0) {
 158                         nExitCode = CODE_OK;
 159                     }
 160                 }
 161                 break;
 162             }
 163             case TYMED_ISTREAM: {
 164                 IStream* pstm = stgmedium.pstm;
 165                 if (pstm != NULL) {
 166                     STATSTG statstg;
 167                     if (pstm->Stat(&statstg, STATFLAG_NONAME) == S_OK) {
 168                         if (statstg.cbSize.LowPart >= strlen(TEST_TEXT) &&
 169                             statstg.cbSize.HighPart == 0) {
 170                             ULONG size = (ULONG)statstg.cbSize.QuadPart;
 171                             ULONG act = 0;
 172                             LPVOID buf = calloc(1, size);
 173                             if (buf != NULL) {
 174                                 if (pstm->Read((void*)buf,size,&act) == S_OK &&
 175                                     strcmp((const char*)buf, TEST_TEXT) == 0) {
 176 
 177                                     nExitCode = CODE_OK;
 178                                 }
 179                                 free(buf);
 180                             }
 181                         }
 182                     }
 183                 }
 184                 break;
 185             }
 186             case TYMED_ENHMF: {
 187                 HENHMETAFILE hemf = stgmedium.hEnhMetaFile;
 188                 UINT size = ::GetEnhMetaFileHeader(hemf, 0, NULL);
 189                 BOOL headerValid = FALSE;
 190                 if (size != 0) {
 191                     LPENHMETAHEADER lpemh = (LPENHMETAHEADER)calloc(1, size);
 192                     if (lpemh != NULL) {
 193                         if (::GetEnhMetaFileHeader(hemf, size, lpemh) == size) {
 194                             headerValid = TRUE;
 195                         }
 196                         free(lpemh);
 197                     }
 198                 }
 199                 if (headerValid == TRUE) {
 200                     UINT size = ::GetEnhMetaFileBits(hemf, 0, NULL);
 201                     if (size != 0) {
 202                         LPBYTE lpbits = (LPBYTE)calloc(1, size);
 203                         if (lpbits != NULL) {
 204                             if (::GetEnhMetaFileBits(hemf, size, lpbits) == size) {
 205                                 nExitCode = CODE_OK;
 206                             }
 207                             free(lpbits);
 208                         }
 209                     }
 210                 }
 211                 break;
 212             }
 213             }
 214         } else {
 215             nExitCode = CODE_INVALID_TYMED_FAILURE;
 216         }
 217     }
 218 
 219     DumpTestResult(tymed, nExitCode);
 220     ::ReleaseStgMedium(&stgmedium);
 221     return nExitCode;
 222 }
 223 
 224 void
 225 TestDropTarget::DumpTestResult(DWORD tymed, int nTestResult) {
 226     switch (tymed) {
 227     case TYMED_HGLOBAL:
 228         fprintf(stderr,"Test transfer for TYMED_HGLOBAL: ");
 229         break;
 230     case TYMED_ISTREAM:
 231         fprintf(stderr,"Test transfer for TYMED_ISTREAM: ");
 232         break;
 233     case TYMED_ENHMF:
 234         fprintf(stderr,"Test transfer for TYMED_ENHMF: ");
 235         break;
 236     default:
 237         fprintf(stderr,"Test transfer for unknown TYMED %d: ", tymed);
 238         break;
 239     }
 240 
 241     switch (nTestResult) {
 242     case CODE_OK:
 243         fprintf(stderr,"PASSED");
 244         break;
 245     case CODE_INVALID_TYMED_FAILURE:
 246         fprintf(stderr,"FAILED: invalid TYMED detected");
 247         break;
 248     case CODE_INVALID_DATA_FAILURE:
 249         fprintf(stderr,"FAILED: invalid transfer data detected");
 250         break;
 251     case CODE_OTHER_FAILURE:
 252         fprintf(stderr,"FAILED: other failure detected");
 253         break;
 254     default:
 255         fprintf(stderr,"FAILED: unknown test result %d", nTestResult);
 256         break;
 257     }
 258 
 259     fprintf(stderr,"\n");
 260 }
 261 
 262 LRESULT CALLBACK
 263 WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam ) {
 264     switch (iMessage) {
 265     case WM_DESTROY:
 266         ::RevokeDragDrop(hWnd);
 267         ::OleUninitialize();
 268         ::PostQuitMessage(0);
 269         break;
 270     default:
 271         return ::DefWindowProc( hWnd, iMessage, wParam, lParam );
 272     }
 273     return 0;
 274 }
 275 
 276 int
 277 main(int argc, char* argv[]) {
 278 
 279     HMODULE hInstance = ::GetModuleHandle(NULL);
 280     WNDCLASS wndclass;
 281     wndclass.style         = CS_OWNDC;
 282     wndclass.lpfnWndProc   = WndProc;
 283     wndclass.cbClsExtra    = 0;
 284     wndclass.cbWndExtra    = 0;
 285     wndclass.hInstance     = hInstance;
 286     wndclass.hIcon         = NULL;
 287     wndclass.hCursor       = NULL;
 288     wndclass.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH);
 289     wndclass.lpszMenuName  = NULL;
 290     wndclass.lpszClassName = szClassName;
 291     if (::RegisterClass(&wndclass) == 0) {
 292         exit( FALSE );
 293     }
 294     HWND hMainWnd = ::CreateWindowEx(WS_EX_CLIENTEDGE, szClassName, szClassName,
 295                                      WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
 296                                      X, Y, WIDTH, HEIGHT,
 297                                      NULL, NULL, hInstance, NULL);
 298     if (hMainWnd == NULL) {
 299         exit(FALSE);
 300     }
 301     ::ShowWindow(hMainWnd, SW_SHOWNORMAL);
 302     ::UpdateWindow(hMainWnd);
 303     ::OleInitialize(NULL);
 304     HRESULT res = ::RegisterDragDrop(hMainWnd, new TestDropTarget());
 305     MSG msg;
 306 
 307     while (::GetMessage(&msg, NULL, 0, 0)) {
 308         ::TranslateMessage(&msg);
 309         ::DispatchMessage(&msg);
 310     }
 311 
 312     ::OleUninitialize();
 313     ::UnregisterClass(szClassName, hInstance);
 314     return msg.wParam;
 315 }