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