Blender V2.61 - r43446

GHOST_DropTargetWin32.cpp

Go to the documentation of this file.
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