|
fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation) ![]() |
00001 // 00002 // "$Id: fl_dnd_win32.cxx 8028 2010-12-14 19:46:55Z AlbrechtS $" 00003 // 00004 // Drag & Drop code for the Fast Light Tool Kit (FLTK). 00005 // 00006 // Copyright 1998-2010 by Bill Spitzak and others. 00007 // 00008 // This library is free software; you can redistribute it and/or 00009 // modify it under the terms of the GNU Library General Public 00010 // License as published by the Free Software Foundation; either 00011 // version 2 of the License, or (at your option) any later version. 00012 // 00013 // This library is distributed in the hope that it will be useful, 00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 // Library General Public License for more details. 00017 // 00018 // You should have received a copy of the GNU Library General Public 00019 // License along with this library; if not, write to the Free Software 00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00021 // USA. 00022 // 00023 // Please report all bugs and problems on the following page: 00024 // 00025 // http://www.fltk.org/str.php 00026 00027 // This file contains win32-specific code for fltk which is always linked 00028 // in. Search other files for "WIN32" or filenames ending in _win32.cxx 00029 // for other system-specific code. 00030 00031 #include <FL/Fl.H> 00032 #include <FL/x.H> 00033 #include <FL/Fl_Window.H> 00034 #include <FL/fl_utf8.h> 00035 #include "flstring.h" 00036 #include <stdio.h> 00037 #include <stdlib.h> 00038 #include <sys/types.h> 00039 #include <objidl.h> 00040 #include <time.h> 00041 #if defined(__CYGWIN__) 00042 #include <sys/time.h> 00043 #include <unistd.h> 00044 #endif 00045 00046 extern char *fl_selection_buffer[2]; 00047 extern int fl_selection_length[2]; 00048 extern int fl_selection_buffer_length[2]; 00049 extern char fl_i_own_selection[2]; 00050 extern char *fl_locale2utf8(const char *s, UINT codepage = 0); 00051 extern unsigned int fl_codepage; 00052 00053 Fl_Window *fl_dnd_target_window = 0; 00054 00055 #include <ole2.h> 00056 #include <shellapi.h> 00057 #include <shlobj.h> 00058 00059 00063 class FLDropTarget : public IDropTarget 00064 { 00065 DWORD m_cRefCount; 00066 DWORD lastEffect; 00067 int px, py; 00068 public: 00069 FLDropTarget() : m_cRefCount(0) { } // initialize 00070 HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, LPVOID *ppvObject ) { 00071 if (IID_IUnknown==riid || IID_IDropTarget==riid) 00072 { 00073 *ppvObject=this; 00074 ((LPUNKNOWN)*ppvObject)->AddRef(); 00075 return S_OK; 00076 } 00077 *ppvObject = NULL; 00078 return E_NOINTERFACE; 00079 } 00080 ULONG STDMETHODCALLTYPE AddRef() { return ++m_cRefCount; } 00081 ULONG STDMETHODCALLTYPE Release() { 00082 long nTemp; 00083 nTemp = --m_cRefCount; 00084 if(nTemp==0) 00085 delete this; 00086 return nTemp; 00087 } 00088 HRESULT STDMETHODCALLTYPE DragEnter( IDataObject *pDataObj, DWORD /*grfKeyState*/, POINTL pt, DWORD *pdwEffect) { 00089 if( !pDataObj ) return E_INVALIDARG; 00090 // set e_modifiers here from grfKeyState, set e_x and e_root_x 00091 // check if FLTK handles this drag and return if it can't (i.e. BMP drag without filename) 00092 POINT ppt; 00093 Fl::e_x_root = ppt.x = pt.x; 00094 Fl::e_y_root = ppt.y = pt.y; 00095 HWND hWnd = WindowFromPoint( ppt ); 00096 Fl_Window *target = fl_find( hWnd ); 00097 if (target) { 00098 Fl::e_x = Fl::e_x_root-target->x(); 00099 Fl::e_y = Fl::e_y_root-target->y(); 00100 } 00101 fl_dnd_target_window = target; 00102 px = pt.x; py = pt.y; 00103 if (fillCurrentDragData(pDataObj)) { 00104 // FLTK has no mechanism yet for the different drop effects, so we allow move and copy 00105 if ( target && Fl::handle( FL_DND_ENTER, target ) ) 00106 *pdwEffect = DROPEFFECT_MOVE|DROPEFFECT_COPY; //|DROPEFFECT_LINK; 00107 else 00108 *pdwEffect = DROPEFFECT_NONE; 00109 } else { 00110 *pdwEffect = DROPEFFECT_NONE; 00111 } 00112 lastEffect = *pdwEffect; 00113 return S_OK; 00114 } 00115 HRESULT STDMETHODCALLTYPE DragOver( DWORD /*grfKeyState*/, POINTL pt, DWORD *pdwEffect) { 00116 if ( px==pt.x && py==pt.y ) 00117 { 00118 *pdwEffect = lastEffect; 00119 return S_OK; 00120 } 00121 if ( !fl_dnd_target_window ) 00122 { 00123 *pdwEffect = lastEffect = DROPEFFECT_NONE; 00124 return S_OK; 00125 } 00126 // set e_modifiers here from grfKeyState, set e_x and e_root_x 00127 Fl::e_x_root = pt.x; 00128 Fl::e_y_root = pt.y; 00129 if (fl_dnd_target_window) { 00130 Fl::e_x = Fl::e_x_root-fl_dnd_target_window->x(); 00131 Fl::e_y = Fl::e_y_root-fl_dnd_target_window->y(); 00132 } 00133 if (fillCurrentDragData(0)) { 00134 // Fl_Group will change DND_DRAG into DND_ENTER and DND_LEAVE if needed 00135 if ( Fl::handle( FL_DND_DRAG, fl_dnd_target_window ) ) 00136 *pdwEffect = DROPEFFECT_MOVE|DROPEFFECT_COPY; //|DROPEFFECT_LINK; 00137 else 00138 *pdwEffect = DROPEFFECT_NONE; 00139 } else { 00140 *pdwEffect = DROPEFFECT_NONE; 00141 } 00142 px = pt.x; py = pt.y; 00143 lastEffect = *pdwEffect; 00144 return S_OK; 00145 } 00146 HRESULT STDMETHODCALLTYPE DragLeave() { 00147 if ( fl_dnd_target_window && fillCurrentDragData(0)) 00148 { 00149 Fl::handle( FL_DND_LEAVE, fl_dnd_target_window ); 00150 fl_dnd_target_window = 0; 00151 clearCurrentDragData(); 00152 } 00153 return S_OK; 00154 } 00155 HRESULT STDMETHODCALLTYPE Drop( IDataObject *data, DWORD /*grfKeyState*/, POINTL pt, DWORD* /*pdwEffect*/) { 00156 if ( !fl_dnd_target_window ) 00157 return S_OK; 00158 Fl_Window *target = fl_dnd_target_window; 00159 fl_dnd_target_window = 0; 00160 Fl::e_x_root = pt.x; 00161 Fl::e_y_root = pt.y; 00162 if (target) { 00163 Fl::e_x = Fl::e_x_root-target->x(); 00164 Fl::e_y = Fl::e_y_root-target->y(); 00165 } 00166 // tell FLTK that the user released an object on this widget 00167 if ( !Fl::handle( FL_DND_RELEASE, target ) ) 00168 return S_OK; 00169 00170 Fl_Widget *w = target; 00171 while (w->parent()) w = w->window(); 00172 HWND hwnd = fl_xid( (Fl_Window*)w ); 00173 if (fillCurrentDragData(data)) { 00174 int old_event = Fl::e_number; 00175 char *a, *b; 00176 a = b = currDragData; 00177 while (*a) { // strip the CRLF pairs 00178 if (*a == '\r' && a[1] == '\n') a++; 00179 else *b++ = *a++; 00180 } 00181 *b = 0; 00182 Fl::e_text = currDragData; 00183 Fl::e_length = b - currDragData; 00184 Fl::belowmouse()->handle(Fl::e_number = FL_PASTE); // e_text will be invalid after this call 00185 Fl::e_number = old_event; 00186 SetForegroundWindow( hwnd ); 00187 clearCurrentDragData(); 00188 return S_OK; 00189 } 00190 return S_OK; 00191 } 00192 private: 00193 00194 static IDataObject *currDragRef; 00195 static char *currDragData; 00196 static int currDragSize; 00197 static char currDragResult; 00198 00199 static void clearCurrentDragData() { 00200 currDragRef = 0; 00201 if (currDragData) free(currDragData); 00202 currDragData = 0; 00203 currDragSize = 0; 00204 currDragResult = 0; 00205 } 00206 static char fillCurrentDragData(IDataObject *data) { 00207 // shortcut through this whole procedure if there is no fresh data 00208 if (!data) 00209 return currDragResult; 00210 // shortcut through this whole procedure if this is still the same drag event 00211 // (* this is safe, because 'currDragRef' is cleared on Leave and Drop events) 00212 if (data==currDragRef) 00213 return currDragResult; 00214 00215 // clear currDrag* for a new drag event 00216 clearCurrentDragData(); 00217 00218 currDragRef = data; 00219 // fill currDrag* with UTF-8 data, if available 00220 FORMATETC fmt = { 0 }; 00221 STGMEDIUM medium = { 0 }; 00222 fmt.tymed = TYMED_HGLOBAL; 00223 fmt.dwAspect = DVASPECT_CONTENT; 00224 fmt.lindex = -1; 00225 fmt.cfFormat = CF_UNICODETEXT; 00226 // if it is UNICODE text, return a UTF-8-converted copy of it 00227 if ( data->GetData( &fmt, &medium )==S_OK ) 00228 { 00229 void *stuff = GlobalLock( medium.hGlobal ); 00230 unsigned srclen = 0; 00231 const wchar_t *wstuff = (const wchar_t *)stuff; 00232 while (*wstuff++) srclen++; 00233 wstuff = (const wchar_t *)stuff; 00234 unsigned utf8len = fl_utf8fromwc(NULL, 0, wstuff, srclen); 00235 currDragSize = utf8len; 00236 currDragData = (char*)malloc(utf8len + 1); 00237 fl_utf8fromwc(currDragData, currDragSize+1, wstuff, srclen+1); // include null-byte 00238 GlobalUnlock( medium.hGlobal ); 00239 ReleaseStgMedium( &medium ); 00240 currDragResult = 1; 00241 return currDragResult; 00242 } 00243 fmt.cfFormat = CF_TEXT; 00244 // if it is CP1252 text, return a UTF-8-converted copy of it 00245 if ( data->GetData( &fmt, &medium )==S_OK ) 00246 { 00247 int len; 00248 char *p, *q, *last; 00249 unsigned u; 00250 void *stuff = GlobalLock( medium.hGlobal ); 00251 currDragData = (char*)malloc(3 * strlen((char*)stuff) + 10); 00252 p = (char*)stuff; 00253 last = p + strlen(p); 00254 q = currDragData; 00255 while (p < last) { 00256 u = fl_utf8decode(p, last, &len); 00257 p += len; 00258 len = fl_utf8encode(u, q); 00259 q += len; 00260 } 00261 *q = 0; 00262 currDragSize = q - currDragData; 00263 currDragData = (char*)realloc(currDragData, currDragSize + 1); 00264 GlobalUnlock( medium.hGlobal ); 00265 ReleaseStgMedium( &medium ); 00266 currDragResult = 1; 00267 return currDragResult; 00268 } 00269 // else fill currDrag* with filenames, if possible 00270 memset(&fmt, 0, sizeof(fmt)); 00271 fmt.tymed = TYMED_HGLOBAL; 00272 fmt.dwAspect = DVASPECT_CONTENT; 00273 fmt.lindex = -1; 00274 fmt.cfFormat = CF_HDROP; 00275 // if it is a pathname list, send an FL_PASTE with a \n separated list of filepaths 00276 if ( data->GetData( &fmt, &medium )==S_OK ) 00277 { 00278 HDROP hdrop = (HDROP)medium.hGlobal; 00279 int i, n, nn = 0, nf = DragQueryFileW( hdrop, (UINT)-1, 0, 0 ); 00280 for ( i=0; i<nf; i++ ) nn += DragQueryFileW( hdrop, i, 0, 0 ); 00281 nn += nf; 00282 xchar *dst = (xchar *)malloc(nn * sizeof(xchar)); 00283 xchar *bu = dst; 00284 for ( i=0; i<nf; i++ ) { 00285 n = DragQueryFileW( hdrop, i, (WCHAR*)dst, nn ); 00286 dst += n; 00287 if ( i<nf-1 ) { 00288 *dst++ = L'\n'; 00289 } 00290 } 00291 *dst=0; 00292 00293 currDragData = (char*) malloc(nn * 5 + 1); 00294 // Fl::e_length = fl_unicode2utf(bu, nn, Fl::e_text); 00295 currDragSize = fl_utf8fromwc(currDragData, (nn*5+1), bu, nn); 00296 currDragData[currDragSize] = 0; 00297 free(bu); 00298 00299 // Fl::belowmouse()->handle(FL_DROP); 00300 // free( Fl::e_text ); 00301 ReleaseStgMedium( &medium ); 00302 currDragResult = 1; 00303 return currDragResult; 00304 } 00305 currDragResult = 0; 00306 return currDragResult; 00307 } 00308 } flDropTarget; 00309 00310 IDropTarget *flIDropTarget = &flDropTarget; 00311 00312 IDataObject *FLDropTarget::currDragRef = 0; 00313 char *FLDropTarget::currDragData = 0; 00314 int FLDropTarget::currDragSize = 0; 00315 char FLDropTarget::currDragResult = 0; 00316 00320 class FLDropSource : public IDropSource 00321 { 00322 DWORD m_cRefCount; 00323 public: 00324 FLDropSource() { m_cRefCount = 0; } 00325 HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, LPVOID *ppvObject ) { 00326 if (IID_IUnknown==riid || IID_IDropSource==riid) 00327 { 00328 *ppvObject=this; 00329 ((LPUNKNOWN)*ppvObject)->AddRef(); 00330 return S_OK; 00331 } 00332 *ppvObject = NULL; 00333 return E_NOINTERFACE; 00334 } 00335 ULONG STDMETHODCALLTYPE AddRef() { return ++m_cRefCount; } 00336 ULONG STDMETHODCALLTYPE Release() { 00337 long nTemp; 00338 nTemp = --m_cRefCount; 00339 if(nTemp==0) 00340 delete this; 00341 return nTemp; 00342 } 00343 STDMETHODIMP GiveFeedback( ulong ) { return DRAGDROP_S_USEDEFAULTCURSORS; } 00344 STDMETHODIMP QueryContinueDrag( BOOL esc, DWORD keyState ) { 00345 if ( esc ) 00346 return DRAGDROP_S_CANCEL; 00347 if ( !(keyState & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON)) ) 00348 return DRAGDROP_S_DROP; 00349 return S_OK; 00350 } 00351 }; 00352 class FLEnum : public IEnumFORMATETC 00353 { 00354 public: 00355 int n; 00356 LONG m_lRefCount; 00357 00358 ULONG __stdcall AddRef(void) { 00359 return InterlockedIncrement(&m_lRefCount); 00360 } 00361 00362 ULONG __stdcall Release(void) { 00363 LONG count = InterlockedDecrement(&m_lRefCount); 00364 if(count == 0) { 00365 delete this; 00366 return 0; 00367 } else { 00368 return count; 00369 } 00370 } 00371 00372 00373 HRESULT __stdcall QueryInterface(REFIID iid, void **ppvObject) { 00374 if(iid == IID_IEnumFORMATETC || iid == IID_IUnknown) { 00375 AddRef(); 00376 *ppvObject = this; 00377 return S_OK; 00378 } else { 00379 *ppvObject = 0; 00380 return E_NOINTERFACE; 00381 } 00382 } 00383 00384 HRESULT __stdcall Next(ULONG celt, FORMATETC * rgelt, ULONG *pceltFetched) { 00385 if (n > 0) return S_FALSE; 00386 for (ULONG i = 0; i < celt; i++) { 00387 n++; 00388 rgelt->cfFormat = CF_HDROP; 00389 rgelt->dwAspect = DVASPECT_CONTENT; 00390 rgelt->lindex = -1; 00391 rgelt->ptd = NULL; 00392 rgelt->tymed = TYMED_HGLOBAL; 00393 } 00394 if (pceltFetched) *pceltFetched = celt; 00395 return S_OK; 00396 } 00397 00398 HRESULT __stdcall Skip(ULONG celt) { 00399 n += celt; 00400 return (n == 0) ? S_OK : S_FALSE; 00401 } 00402 00403 HRESULT __stdcall Reset(void) { 00404 n = 0; 00405 return S_OK; 00406 } 00407 00408 HRESULT __stdcall Clone(IEnumFORMATETC **ppenum){ 00409 *ppenum = new FLEnum(); 00410 return S_OK; 00411 } 00412 00413 FLEnum(void) { 00414 m_lRefCount = 1; 00415 n = 0; 00416 } 00417 00418 virtual ~FLEnum(void) { 00419 n = 0; 00420 } 00421 }; 00422 00423 00429 class FLDataObject : public IDataObject 00430 { 00431 DWORD m_cRefCount; 00432 FLEnum *m_EnumF; 00433 public: 00434 FLDataObject() { m_cRefCount = 1; }// m_EnumF = new FLEnum();} 00435 HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, LPVOID *ppvObject ) { 00436 if (IID_IUnknown==riid || IID_IDataObject==riid) 00437 { 00438 *ppvObject=this; 00439 ((LPUNKNOWN)*ppvObject)->AddRef(); 00440 return S_OK; 00441 } 00442 *ppvObject = NULL; 00443 return E_NOINTERFACE; 00444 } 00445 ULONG STDMETHODCALLTYPE AddRef() { return ++m_cRefCount; } 00446 ULONG STDMETHODCALLTYPE Release() { 00447 long nTemp; 00448 nTemp = --m_cRefCount; 00449 if(nTemp==0) 00450 delete this; 00451 return nTemp; 00452 } 00453 // GetData currently allows UNICODE text through Global Memory only 00454 HRESULT STDMETHODCALLTYPE GetData( FORMATETC *pformatetcIn, STGMEDIUM *pmedium ) { 00455 if ((pformatetcIn->dwAspect & DVASPECT_CONTENT) && 00456 (pformatetcIn->tymed & TYMED_HGLOBAL) && 00457 (pformatetcIn->cfFormat == CF_UNICODETEXT)) 00458 { 00459 int utf16_len = fl_utf8toUtf16(fl_selection_buffer[0], fl_selection_length[0], 0, 0); 00460 HGLOBAL gh = GlobalAlloc( GHND, utf16_len * 2 + 2 ); 00461 char *pMem = (char*)GlobalLock( gh ); 00462 fl_utf8toUtf16(fl_selection_buffer[0], fl_selection_length[0], (unsigned short*)pMem, utf16_len + 1); 00463 // HGLOBAL gh = GlobalAlloc( GHND| GMEM_SHARE, 00464 // (fl_selection_length[0]+4) * sizeof(short) 00465 // + sizeof(DROPFILES)); 00466 // unsigned char *pMem = (unsigned char*)GlobalLock( gh ); 00467 // if (!pMem) { 00468 // GlobalFree(gh); 00469 // return DV_E_FORMATETC; 00470 // } 00471 // DROPFILES *df =(DROPFILES*) pMem; 00472 // int l; 00473 // df->pFiles = sizeof(DROPFILES); 00474 // df->pt.x = 0; 00475 // df->pt.y = 0; 00476 // df->fNC = FALSE; 00477 // for (int i = 0; i < fl_selection_length[0]; i++) { 00478 // if (fl_selection_buffer[0][i] == '\n') { 00479 // fl_selection_buffer[0][i] = '\0'; 00480 // } 00481 // } 00482 // 00483 // df->fWide = TRUE; 00484 // l = fl_utf2unicode((unsigned char*)fl_selection_buffer[0], 00485 // fl_selection_length[0], (xchar*)(((char*)pMem) 00486 // + sizeof(DROPFILES))); 00487 // 00488 // pMem[l * sizeof(WCHAR) + sizeof(DROPFILES)] = 0; 00489 // pMem[l * sizeof(WCHAR) + 1 + sizeof(DROPFILES)] = 0; 00490 // pMem[l * sizeof(WCHAR) + 2 + sizeof(DROPFILES)] = 0; 00491 // pMem[l * sizeof(WCHAR) + 3 + sizeof(DROPFILES)] = 0; 00492 pmedium->tymed = TYMED_HGLOBAL; 00493 pmedium->hGlobal = gh; 00494 pmedium->pUnkForRelease = NULL; 00495 GlobalUnlock( gh ); 00496 return S_OK; 00497 } 00498 return DV_E_FORMATETC; 00499 } 00500 HRESULT STDMETHODCALLTYPE QueryGetData( FORMATETC *pformatetc ) 00501 { 00502 if ((pformatetc->dwAspect & DVASPECT_CONTENT) && 00503 (pformatetc->tymed & TYMED_HGLOBAL) && 00504 (pformatetc->cfFormat == CF_UNICODETEXT)) 00505 return S_OK; 00506 return DV_E_FORMATETC; 00507 } 00508 // HRESULT STDMETHODCALLTYPE EnumFormatEtc( DWORD dir, IEnumFORMATETC** ppenumFormatEtc) { 00509 // *ppenumFormatEtc = m_EnumF; 00510 // return S_OK; 00511 // } 00512 00513 // all the following methods are not really needed for a DnD object 00514 HRESULT STDMETHODCALLTYPE GetDataHere( FORMATETC* /*pformatetcIn*/, STGMEDIUM* /*pmedium*/) { return E_NOTIMPL; } 00515 HRESULT STDMETHODCALLTYPE GetCanonicalFormatEtc( FORMATETC* /*in*/, FORMATETC* /*out*/) { return E_NOTIMPL; } 00516 HRESULT STDMETHODCALLTYPE SetData( FORMATETC* /*pformatetc*/, STGMEDIUM* /*pmedium*/, BOOL /*fRelease*/) { return E_NOTIMPL; } 00517 HRESULT STDMETHODCALLTYPE EnumFormatEtc( DWORD /*dir*/, IEnumFORMATETC** /*ppenumFormatEtc*/) { return E_NOTIMPL; } 00518 // HRESULT STDMETHODCALLTYPE EnumFormatEtc( DWORD dir, IEnumFORMATETC** ppenumFormatEtc) {*ppenumFormatEtc = m_EnumF; return S_OK;} 00519 HRESULT STDMETHODCALLTYPE DAdvise( FORMATETC* /*pformatetc*/, DWORD /*advf*/, 00520 IAdviseSink* /*pAdvSink*/, DWORD* /*pdwConnection*/) { return E_NOTIMPL; } 00521 HRESULT STDMETHODCALLTYPE DUnadvise( DWORD /*dwConnection*/) { return E_NOTIMPL; } 00522 HRESULT STDMETHODCALLTYPE EnumDAdvise( IEnumSTATDATA** /*ppenumAdvise*/) { return E_NOTIMPL; } 00523 }; 00524 00525 00526 int Fl::dnd() 00527 { 00528 DWORD dropEffect; 00529 ReleaseCapture(); 00530 00531 FLDataObject *fdo = new FLDataObject; 00532 fdo->AddRef(); 00533 FLDropSource *fds = new FLDropSource; 00534 fds->AddRef(); 00535 00536 HRESULT ret = DoDragDrop( fdo, fds, DROPEFFECT_MOVE|DROPEFFECT_LINK|DROPEFFECT_COPY, &dropEffect ); 00537 00538 fdo->Release(); 00539 fds->Release(); 00540 00541 Fl_Widget *w = Fl::pushed(); 00542 if ( w ) 00543 { 00544 int old_event = Fl::e_number; 00545 w->handle(Fl::e_number = FL_RELEASE); 00546 Fl::e_number = old_event; 00547 Fl::pushed( 0 ); 00548 } 00549 if ( ret==DRAGDROP_S_DROP ) return 1; // or DD_S_CANCEL 00550 return 0; 00551 } 00552 00553 // 00554 // End of "$Id: fl_dnd_win32.cxx 8028 2010-12-14 19:46:55Z AlbrechtS $". 00555 //