|
Blender
V2.59
|
00001 /* 00002 * $Id: GHOST_DropTargetWin32.cpp 38908 2011-08-02 04:28:05Z merwin $ 00003 * ***** BEGIN GPL LICENSE BLOCK ***** 00004 * 00005 * This program is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU General Public License 00007 * as published by the Free Software Foundation; either version 2 00008 * of the License, or (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License 00016 * along with this program; if not, write to the Free Software Foundation, 00017 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00018 * 00019 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00020 * All rights reserved. 00021 * 00022 * The Original Code is: all of this file. 00023 * 00024 * Contributor(s): none yet. 00025 * 00026 * ***** END GPL LICENSE BLOCK ***** 00027 */ 00028 00034 #include "GHOST_Debug.h" 00035 #include "GHOST_DropTargetWin32.h" 00036 #include <ShellApi.h> 00037 00038 #ifdef GHOST_DEBUG 00039 // utility 00040 void printLastError(void); 00041 #endif // GHOST_DEBUG 00042 00043 00044 GHOST_DropTargetWin32::GHOST_DropTargetWin32(GHOST_WindowWin32 * window, GHOST_SystemWin32 * system) 00045 : 00046 m_window(window), 00047 m_system(system) 00048 { 00049 m_cRef = 1; 00050 m_hWnd = window->getHWND(); 00051 m_draggedObjectType = GHOST_kDragnDropTypeUnknown; 00052 00053 // register our window as drop target 00054 ::RegisterDragDrop(m_hWnd, this); 00055 } 00056 00057 GHOST_DropTargetWin32::~GHOST_DropTargetWin32() 00058 { 00059 ::RevokeDragDrop(m_hWnd); 00060 } 00061 00062 00063 /* 00064 * IUnknown::QueryInterface 00065 */ 00066 HRESULT __stdcall GHOST_DropTargetWin32::QueryInterface (REFIID riid, void ** ppvObj) 00067 { 00068 00069 if (!ppvObj) 00070 return E_INVALIDARG; 00071 *ppvObj = NULL; 00072 00073 if(riid == IID_IUnknown || riid == IID_IDropTarget) 00074 { 00075 AddRef(); 00076 *ppvObj = (void*)this; 00077 return S_OK; 00078 } 00079 else 00080 { 00081 *ppvObj = 0; 00082 return E_NOINTERFACE; 00083 } 00084 } 00085 00086 00087 /* 00088 * IUnknown::AddRef 00089 */ 00090 00091 ULONG __stdcall GHOST_DropTargetWin32::AddRef(void) 00092 { 00093 return ::InterlockedIncrement(&m_cRef); 00094 } 00095 00096 /* 00097 * IUnknown::Release 00098 */ 00099 ULONG __stdcall GHOST_DropTargetWin32::Release(void) 00100 { 00101 ULONG refs = ::InterlockedDecrement(&m_cRef); 00102 00103 if(refs == 0) 00104 { 00105 delete this; 00106 return 0; 00107 } 00108 else 00109 { 00110 return refs; 00111 } 00112 } 00113 00114 /* 00115 * Implementation of IDropTarget::DragEnter 00116 */ 00117 HRESULT __stdcall GHOST_DropTargetWin32::DragEnter(IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect) 00118 { 00119 // we accept all drop by default 00120 m_window->setAcceptDragOperation(true); 00121 *pdwEffect = DROPEFFECT_NONE; 00122 00123 m_draggedObjectType = getGhostType(pDataObject); 00124 m_system->pushDragDropEvent(GHOST_kEventDraggingEntered, m_draggedObjectType, m_window, pt.x, pt.y, NULL); 00125 return S_OK; 00126 } 00127 00128 /* 00129 * Implementation of IDropTarget::DragOver 00130 */ 00131 HRESULT __stdcall GHOST_DropTargetWin32::DragOver(DWORD grfKeyState, POINTL pt, DWORD * pdwEffect) 00132 { 00133 if(m_window->canAcceptDragOperation()) 00134 { 00135 *pdwEffect = allowedDropEffect(*pdwEffect); 00136 } 00137 else 00138 { 00139 *pdwEffect = DROPEFFECT_NONE; 00140 //*pdwEffect = DROPEFFECT_COPY; // XXX Uncomment to test drop. Drop will not be called if pdwEffect == DROPEFFECT_NONE. 00141 } 00142 m_system->pushDragDropEvent(GHOST_kEventDraggingUpdated, m_draggedObjectType, m_window, pt.x, pt.y, NULL); 00143 return S_OK; 00144 } 00145 00146 /* 00147 * Implementation of IDropTarget::DragLeave 00148 */ 00149 HRESULT __stdcall GHOST_DropTargetWin32::DragLeave(void) 00150 { 00151 m_system->pushDragDropEvent(GHOST_kEventDraggingExited, m_draggedObjectType, m_window, 0, 0, NULL); 00152 m_draggedObjectType = GHOST_kDragnDropTypeUnknown; 00153 return S_OK; 00154 } 00155 00156 /* Implementation of IDropTarget::Drop 00157 * This function will not be called if pdwEffect is set to DROPEFFECT_NONE in 00158 * the implementation of IDropTarget::DragOver 00159 */ 00160 HRESULT __stdcall GHOST_DropTargetWin32::Drop(IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect) 00161 { 00162 void * data = getGhostData(pDataObject); 00163 if(m_window->canAcceptDragOperation()) 00164 { 00165 *pdwEffect = allowedDropEffect(*pdwEffect); 00166 00167 } 00168 else 00169 { 00170 *pdwEffect = DROPEFFECT_NONE; 00171 } 00172 if (data) 00173 m_system->pushDragDropEvent(GHOST_kEventDraggingDropDone, m_draggedObjectType, m_window, pt.x, pt.y, data ); 00174 00175 m_draggedObjectType = GHOST_kDragnDropTypeUnknown; 00176 return S_OK; 00177 } 00178 00179 /* 00180 * Helpers 00181 */ 00182 00183 DWORD GHOST_DropTargetWin32::allowedDropEffect(DWORD dwAllowed) 00184 { 00185 DWORD dwEffect = DROPEFFECT_NONE; 00186 if(dwAllowed & DROPEFFECT_COPY) 00187 dwEffect = DROPEFFECT_COPY; 00188 00189 return dwEffect; 00190 } 00191 00192 GHOST_TDragnDropTypes GHOST_DropTargetWin32::getGhostType(IDataObject * pDataObject) 00193 { 00194 /* Text 00195 * Note: Unicode text is aviable as CF_TEXT too, the system can do the 00196 * conversion, but we do the conversion ourself with WC_NO_BEST_FIT_CHARS. 00197 */ 00198 FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; 00199 if(pDataObject->QueryGetData(&fmtetc) == S_OK) 00200 { 00201 return GHOST_kDragnDropTypeString; 00202 } 00203 00204 // Filesnames 00205 fmtetc.cfFormat = CF_HDROP; 00206 if(pDataObject->QueryGetData(&fmtetc) == S_OK) 00207 { 00208 return GHOST_kDragnDropTypeFilenames; 00209 } 00210 00211 return GHOST_kDragnDropTypeUnknown; 00212 } 00213 00214 void * GHOST_DropTargetWin32::getGhostData(IDataObject * pDataObject) 00215 { 00216 GHOST_TDragnDropTypes type = getGhostType(pDataObject); 00217 switch(type) 00218 { 00219 case GHOST_kDragnDropTypeFilenames: 00220 return getDropDataAsFilenames(pDataObject); 00221 break; 00222 case GHOST_kDragnDropTypeString: 00223 return getDropDataAsString(pDataObject); 00224 break; 00225 case GHOST_kDragnDropTypeBitmap: 00226 //return getDropDataAsBitmap(pDataObject); 00227 break; 00228 default: 00229 #ifdef GHOST_DEBUG 00230 ::printf("\nGHOST_kDragnDropTypeUnknown"); 00231 #endif // GHOST_DEBUG 00232 return NULL; 00233 break; 00234 } 00235 return NULL; 00236 } 00237 00238 void * GHOST_DropTargetWin32::getDropDataAsFilenames(IDataObject * pDataObject) 00239 { 00240 UINT totfiles, nvalid=0; 00241 WCHAR fpath [MAX_PATH]; 00242 char * temp_path; 00243 GHOST_TStringArray *strArray = NULL; 00244 FORMATETC fmtetc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; 00245 STGMEDIUM stgmed; 00246 HDROP hdrop; 00247 00248 // Check if dataobject supplies the format we want. 00249 // Double checking here, first in getGhostType. 00250 if(pDataObject->QueryGetData(&fmtetc) == S_OK) 00251 { 00252 if(pDataObject->GetData(&fmtetc, &stgmed) == S_OK) 00253 { 00254 hdrop = (HDROP)::GlobalLock(stgmed.hGlobal); 00255 00256 totfiles = ::DragQueryFileW ( hdrop, -1, NULL, 0 ); 00257 if (!totfiles) 00258 { 00259 ::GlobalUnlock(stgmed.hGlobal); 00260 return NULL; 00261 } 00262 00263 strArray = (GHOST_TStringArray*) ::malloc(sizeof(GHOST_TStringArray)); 00264 strArray->count = 0; 00265 strArray->strings = (GHOST_TUns8**) ::malloc(totfiles*sizeof(GHOST_TUns8*)); 00266 00267 for ( UINT nfile = 0; nfile < totfiles; nfile++ ) 00268 { 00269 if ( ::DragQueryFileW ( hdrop, nfile, fpath, MAX_PATH ) > 0 ) 00270 { 00271 if ( !WideCharToANSI(fpath, temp_path) ) 00272 { 00273 continue; 00274 } 00275 // Just ignore paths that could not be converted verbatim. 00276 if (strpbrk(temp_path, "?")) 00277 { 00278 #ifdef GHOST_DEBUG 00279 ::printf("\ndiscarding path that contains illegal characters: %s", temp_path); 00280 #endif // GHOST_DEBUG 00281 ::free(temp_path); 00282 temp_path = NULL; 00283 continue; 00284 } 00285 strArray->strings[nvalid] = (GHOST_TUns8*) temp_path; 00286 strArray->count = nvalid+1; 00287 nvalid++; 00288 } 00289 } 00290 // Free up memory. 00291 ::GlobalUnlock(stgmed.hGlobal); 00292 ::ReleaseStgMedium(&stgmed); 00293 00294 return strArray; 00295 } 00296 } 00297 return NULL; 00298 } 00299 00300 void * GHOST_DropTargetWin32::getDropDataAsString(IDataObject * pDataObject) 00301 { 00302 char* tmp_string; 00303 FORMATETC fmtetc = { CF_UNICODETEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; 00304 STGMEDIUM stgmed; 00305 00306 // Try unicode first. 00307 // Check if dataobject supplies the format we want. 00308 if(pDataObject->QueryGetData(&fmtetc) == S_OK) 00309 { 00310 if(pDataObject->GetData(&fmtetc, &stgmed) == S_OK) 00311 { 00312 LPCWSTR wstr = (LPCWSTR)::GlobalLock(stgmed.hGlobal); 00313 if ( !WideCharToANSI(wstr, tmp_string) ) 00314 { 00315 ::GlobalUnlock(stgmed.hGlobal); 00316 return NULL; 00317 } 00318 // Free memory 00319 ::GlobalUnlock(stgmed.hGlobal); 00320 ::ReleaseStgMedium(&stgmed); 00321 #ifdef GHOST_DEBUG 00322 ::printf("\n<converted droped unicode string>\n%s\n</droped converted unicode string>\n",tmp_string); 00323 #endif // GHOST_DEBUG 00324 return tmp_string; 00325 } 00326 } 00327 00328 fmtetc.cfFormat = CF_TEXT; 00329 00330 if(pDataObject->QueryGetData(&fmtetc) == S_OK) 00331 { 00332 if(pDataObject->GetData(&fmtetc, &stgmed) == S_OK) 00333 { 00334 char * str = (char*)::GlobalLock(stgmed.hGlobal); 00335 00336 tmp_string = (char*)::malloc(::strlen(str)+1); 00337 if ( !tmp_string ) 00338 { 00339 ::GlobalUnlock(stgmed.hGlobal); 00340 return NULL; 00341 } 00342 00343 if ( !::strcpy(tmp_string, str) ) 00344 { 00345 ::free(tmp_string); 00346 ::GlobalUnlock(stgmed.hGlobal); 00347 return NULL; 00348 } 00349 // Free memory 00350 ::GlobalUnlock(stgmed.hGlobal); 00351 ::ReleaseStgMedium(&stgmed); 00352 00353 return tmp_string; 00354 } 00355 } 00356 00357 return NULL; 00358 } 00359 00360 int GHOST_DropTargetWin32::WideCharToANSI(LPCWSTR in, char * &out) 00361 { 00362 int size; 00363 out = NULL; //caller should free if != NULL 00364 00365 // Get the required size. 00366 size = ::WideCharToMultiByte(CP_ACP, //System Default Codepage 00367 0x00000400, // WC_NO_BEST_FIT_CHARS 00368 in, 00369 -1, //-1 null terminated, makes output null terminated too. 00370 NULL, 00371 0, 00372 NULL,NULL 00373 ); 00374 00375 if(!size) 00376 { 00377 #ifdef GHOST_DEBUG 00378 ::printLastError(); 00379 #endif // GHOST_DEBUG 00380 return 0; 00381 } 00382 00383 out = (char*)::malloc(size); 00384 if (!out) 00385 { 00386 ::printf("\nmalloc failed!!!"); 00387 return 0; 00388 } 00389 00390 size = ::WideCharToMultiByte(CP_ACP, 00391 0x00000400, 00392 in, 00393 -1, 00394 (LPSTR) out, 00395 size, 00396 NULL,NULL 00397 ); 00398 00399 if(!size) 00400 { 00401 #ifdef GHOST_DEBUG 00402 ::printLastError(); 00403 #endif //GHOST_DEBUG 00404 ::free(out); 00405 out = NULL; 00406 } 00407 return size; 00408 } 00409 00410 #ifdef GHOST_DEBUG 00411 void printLastError(void) 00412 { 00413 LPTSTR s; 00414 DWORD err; 00415 00416 err = GetLastError(); 00417 if(FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 00418 FORMAT_MESSAGE_FROM_SYSTEM, 00419 NULL, 00420 err, 00421 0, 00422 (LPTSTR)&s, 00423 0, 00424 NULL) 00425 ) 00426 { 00427 printf("\nLastError: (%d) %s\n", (int)err, s); 00428 LocalFree(s); 00429 } 00430 } 00431 #endif // GHOST_DEBUG 00432