source: trunk/src/user32/clipboard.cpp@ 10595

Last change on this file since 10595 was 10595, checked in by sandervl, 21 years ago

KSO: Clipboard updates

File size: 107.0 KB
Line 
1/* $Id: clipboard.cpp,v 1.19 2004-05-03 12:09:00 sandervl Exp $ */
2
3/*
4 * Win32 Clipboard API functions for OS/2
5 *
6 * Copyright 1998 Sander van Leeuwen
7 * Copyright 1998 Patrick Haller
8 * Copyright 1998 Peter Fitzsimmons
9 * Copyright 2004 InnoTek Systemberatung GmbH
10 *
11 * NOTE: Use OS/2 frame handles for Open32 functions
12 *
13 * Project Odin Software License can be found in LICENSE.TXT
14 *
15 */
16
17/** @page user32_clipboard Clipboard
18 *
19 * The clipboard implemenation is based on using the OS/2 clipboard, sharing
20 * the few compatible formats while registering private formats for the rest.
21 *
22 * The OS/2 and Windows clipboards are very similar although the Windows one
23 * have evolved a bit further than the OS/2 one. Still, they send basically
24 * the same window messages to the clipboard owner and viewer. They both support
25 * having multiple formats present at the same time.
26 *
27 * Windows however, have a feature for automatic synthesizing of alternative
28 * data formats. For instance if there is one of the CF_TEXT, CF_UNICODETEXT,
29 * CF_OEMTEXT formats put onto the clipboard, the other two will be synthesized.
30 * Similar for CF_BITMAP, CF_DIB and CF_DIBV5. CF_DIB and CF_DIBV5 also causes
31 * CF_PALETTE to be synthesized. CF_METAFILEPICT and CF_ENHMETAFILE are also
32 * synthesized when the other is present.
33 *
34 * The Odin32 clipboard implementation will support synthesizing all but the
35 * metafiles and palette in it's current incarnation.
36 *
37 * CF_LOCALE is a special format which is generated when text is put onto the
38 * clipboard. It contains a MAKELCID DWORD. It's will be generated when the
39 * clipboard is closed since no other process (or thread for that matter) can
40 * access the clipboard when it's opened by someone else. CF_LOCALE will be
41 * faked if OS/2 put some text onto the clipboard.
42 *
43 * The ranges of private and gdi formats are registered with PM on demand
44 * to limit resource waste and minimize startup penalty.
45 *
46 * The synthesized format are reported, and we store a special fake handle
47 * for those which haven't yet been converted. This can of course only be
48 * done for formats which we do not share with PM; CF_TEXT, CF_BITMAP,
49 * and CF_PALETTE.
50 *
51 * When data is retrieved from the clipboard a copy is made for the calling
52 * process. In windows EmptyClipboard() will cleanup only in the global
53 * data and the local copies in the calling process. That means other
54 * processes which have retrieved data from the clipboard will not have
55 * their data invalidated till they them self call EmptyClipboard().
56 *
57 */
58
59
60/*******************************************************************************
61* Header Files *
62*******************************************************************************/
63#include <os2win.h>
64#include <string.h>
65#include "win32wbase.h"
66#include <unicode.h>
67#include <stdio.h>
68#include <ctype.h>
69#include "oslibclipbrd.h"
70#include "oslibutil.h"
71#include "oslibwin.h"
72
73/* missing somewhere */
74#ifndef LCS_sRGB
75#define LCS_sRGB 0x73524742 //'RGBs'
76#endif
77
78#define DBG_LOCALLOG DBG_clipboard
79#include "dbglocal.h"
80
81
82
83/*******************************************************************************
84* Defined Constants And Macros *
85*******************************************************************************/
86
87/** Define this to return the V5 DIB headers to the application.
88 * If not defined we will not convert anything to DIBV5 headers, but we'll still
89 * accept DIBV5 headers from the application.
90 */
91#define USE_DIBV5 1
92
93
94/**
95 * Debug assertion macro.
96 * @param expr Assert that this expression is true.
97 * @param msg Message to print if expr isn't true. It's given to dprintf,
98 * and must be inclosed in paratheses.
99 * @todo move this to some header in /include.
100 */
101#ifdef DEBUG
102 #define DebugAssert(expr, msg) \
103 do { if (expr) break; \
104 dprintf(("!!!ASSERTION FAILED!!!\nFILE=%s\nLINE=%d\nFUNCTION=%s\n", __FILE__, __LINE__, __FUNCTION__)); \
105 dprintf(msg); DebugInt3(); \
106 } while (0)
107#else
108 #define DebugAssert(expr, msg) do {} while (0)
109#endif
110
111/**
112 * Debug assertion failed macro.
113 * @param msg Message to print if expr isn't true. It's given to dprintf,
114 * and must be inclosed in paratheses.
115 * @todo move this to some header in /include.
116 */
117#ifdef DEBUG
118 #define DebugAssertFailed(msg) \
119 do { dprintf(("!!!ASSERTION FAILED!!!\nFILE=%s\nLINE=%d\nFUNCTION=%s\n", __FILE__, __LINE__, __FUNCTION__)); \
120 dprintf(msg); DebugInt3(); \
121 } while (0)
122#else
123 #define DebugAssertFailed(msg) do {} while (0)
124#endif
125
126
127/** Format name strings.
128 * @{ */
129#define SZFMT_PRIVATE_PREFIX "Odin32 Private #"
130#define SZFMT_GDIOBJ_PREFIX "Odin32 GDI Object #"
131/** @} */
132
133/** Dummy handle used for synthesized formats. */
134#define DUMMY_HANDLE 0xbeef0001
135
136
137/*******************************************************************************
138* Structures and Typedefs *
139*******************************************************************************/
140/** Dynamically registered formats, and the PRIVATE and GDI predefined ranges. */
141typedef struct _ClipboardDynamicFormatMapping
142{
143 /** Odin32 Format. */
144 UINT uOdin;
145 /** OS/2 format. */
146 ULONG ulPM;
147 /** Name for registered formats. (NULL for predefined) */
148 const char *pszName;
149 /** Pointer to the next in the list. */
150 struct _ClipboardDynamicFormatMapping *pNext;
151} CLIPDYNFORMMAP, *PCLIPDYNFORMMAP;
152
153/** Node in the list of local clipboard data. (the get-cache) */
154typedef struct _ClipboardLocalData
155{
156 /** Data type. */
157 enum
158 {
159 /** GlobalAlloc'ed object. */
160 enmGlobalMem,
161 /** GDI data - bitmap or palette. */
162 enmGDI,
163 /** Private data owner cleans up. */
164 enmPrivate
165 } enmType;
166 /** Clipboard format Format. */
167 UINT uFormat;
168 /** Handle / pointer to data. */
169 HANDLE h;
170 /** Pointer to the next node in the list. */
171 struct _ClipboardLocalData *pNext;
172} CLIPLOCALDATA, *PCLIPLOCALDATA;
173
174
175/** Header for Odin32 specific clipboard entries.
176 * (Used to get the correct size of the data.)
177 */
178typedef struct _Odin32ClipboardHeader
179{
180 /** magic number */
181 char achMagic[8];
182 /** Size of the following data.
183 * (The interpretation depends on the type.) */
184 unsigned cbData;
185 /** Odin32 format number. */
186 unsigned uFormat;
187} CLIPHEADER, *PCLIPHEADER;
188
189#define CLIPHEADER_MAGIC "Odin\1\0\1"
190
191
192/*******************************************************************************
193* Global Variables *
194*******************************************************************************/
195/** Static mappings. */
196static struct
197{
198 /** Odin32 Format. */
199 UINT uOdin;
200 /** OS/2 format. */
201 ULONG ulPM;
202 /** Format name for registration. */
203 const char *pszRegString;
204 /** Description. (debug) */
205 const char *pszDescr;
206} gaFormats[] =
207{
208 { CF_TEXT , OSLIB_CF_TEXT , NULL , "CF_TEXT"},
209 { CF_BITMAP , OSLIB_CF_BITMAP , NULL , "CF_BITMAP"},
210 { CF_PALETTE , OSLIB_CF_PALETTE , NULL , "CF_PALETTE"},
211 { CF_LOCALE , ~0 , "Odin32 Locale" , "CF_LOCALE"},
212 { CF_UNICODETEXT , ~0 , "Odin32 UnicodeText" , "CF_UNICODETEXT"},
213 { CF_OEMTEXT , ~0 , "Odin32 OEM Text" , "CF_OEMTEXT"},
214 { CF_DIB , ~0 , "Odin32 Device Independent Bitmap (DIB)" , "CF_DIB"},
215 { CF_DIBV5 , ~0 , "Odin32 Device Independent Bitmap V5 (DIBV5)" , "CF_DIBV5"},
216 { CF_METAFILEPICT , ~0 , "Odin32 MetaFilePict" , "CF_METAFILEPICT"},
217 { CF_ENHMETAFILE , ~0 , "Odin32 Enh. MetaFile" , "CF_ENHMETAFILE"},
218 { CF_TIFF , ~0 , "Odin32 Tagged Image Format (TIFF)" , "CF_TIFF"},
219 { CF_DIF , ~0 , "Odin32 Data Interchange Format (SYLK)" , "CF_DIF"},
220 { CF_HDROP , ~0 , "Odin32 HDROP" , "CF_HDROP"},
221 { CF_OWNERDISPLAY , ~0 , "Odin32 OwnerDisplay" , "CF_OWNERDISPLAY"},
222 { CF_PENDATA , ~0 , "Odin32 PenData" , "CF_PENDATA"},
223 { CF_SYLK , ~0 , "Odin32 Symlink Format" , "CF_SYLK"},
224 { CF_RIFF , ~0 , "Odin32 RIFF" , "CF_RIFF"},
225 { CF_WAVE , ~0 , "Odin32 Wave" , "CF_WAVE"},
226 { CF_DSPMETAFILEPICT, ~0 , "Odin32 DSP MetaFilePict" , "CF_DSPMETAFILEPICT"},
227 { CF_DSPENHMETAFILE , ~0 , "Odin32 DSP Enh. MetaFile" , "CF_DSPENHMETAFILE"},
228 { CF_DSPTEXT , OSLIB_CF_DSPTEXT , NULL , "CF_DSPTEXT"},
229 { CF_DSPBITMAP , OSLIB_CF_DSPBITMAP, NULL , "CF_DSPBITMAP"},
230};
231
232/** List of dynamically registered formats. (should perhaps be protected for updates...)
233 * This is used for the CF_PRIVATE, CF_GDIOBJ and registered formats. */
234PCLIPDYNFORMMAP gpDynFormats;
235
236/** List of locally allocated objects.
237 * SetClipboardData and GetClipboardData adds to this list.
238 * This list is freed by EmptyClipboard.
239 * (Access to this list is serialized by the clipboard semaphore in PM.)
240 */
241PCLIPLOCALDATA gpLocalData;
242
243/** The Odin window handle for the last OpenClipboard() call.
244 * We need to keep this around for the EmptyClipboard() so we can set
245 * the correct clipboard owner.
246 */
247HWND ghwndOpenClipboard;
248/** The OS/2 PM Window handle for ghwndOpenClipboard. */
249HWND ghwndOS2OpenClipboard;
250/** The Odin TID of the current clipboard (Odin only) Read/Write Owner.
251 * OpenClipboard and CloseClipboard updates while being behind the PM Clipboard
252 * sempahore. If ASSUMES noone calls Open32 or PM apis directly to close the
253 * clipboard. */
254DWORD gtidOpenClipboardThreadId;
255
256/** Whether or not the current OpenClipboard session have changed the clipboard.
257 * Used by CloseClipboard(). */
258BOOL gfClipboardChanged;
259
260/** Whether or not the current OpenClipboard session have put text onto the clipboard.
261 * Used to determin if CF_LOCALE can be generated correctly or not.
262 */
263BOOL gfClipboardChangedText;
264
265
266/*******************************************************************************
267* Internal Functions *
268*******************************************************************************/
269#ifdef DEBUG_LOGGING
270static const char *dbgGetFormatName(UINT uFormat);
271static void dbgDumpClipboardData(const char *pszPrefix, UINT uFormat, HANDLE hData);
272#else
273 #define dbgGetFormatName(uFormat) \
274 ("<!non debug logging mode!>")
275 #define dbgDumpClipboardData(pszPrefix, uFormat, hClibObj) \
276 do { } while(0)
277#endif
278UINT WIN32API clipboardPMToOdinFormat(ULONG ulPMFormat);
279ULONG WIN32API clipboardOdinToPMFormat(UINT uOdinFormat);
280static ULONG clipboardAddDynFormat(UINT uFormat, const char *pszFormatName);
281static BOOL clipboardIsRWOwner(void);
282static BOOL clipboardAddPM(UINT uOdinFormat, void *pv, unsigned cb);
283static BOOL clipboardAddPMHeader(UINT uOdinFormat, void *pv, unsigned cb);
284static BOOL clipboardAddPMHandle(UINT uOdinFormat, HANDLE h);
285static void * clipboardAllocPMBuffer(unsigned cb);
286static BOOL clipboardAddPMDummy(UINT uOdinFormat);
287static ULONG clipboardGetPMDataSize(void *pvData);
288static BOOL clipboardIsAvailable(UINT uFormat);
289static BOOL clipboardIsAvailableReal(UINT uFormat);
290static void clipboardSynthesize(BOOL fHaveModifiedIt);
291static BOOL clipboardShouldBeSynthesized(UINT uFormat);
292static HANDLE clipboardSynthesizeText(UINT uFormat);
293static HANDLE clipboardSynthesizeLocale(UINT uFormat);
294static HANDLE clipboardSynthesizeBitmap(UINT uFormat);
295static HANDLE clipboardSynthesizeDIB(UINT uFormat);
296#if 0 // not implemented yet
297static HANDLE clipboardSynthesizePalette(UINT uFormat);
298static HANDLE clipboardSynthesizeMetaFile(UINT uFormat);
299static HANDLE clipboardSynthesizeEnhMetaFile(UINT uFormat);
300#endif
301static unsigned clipboardTextCalcSize(void *pvData, unsigned cb);
302unsigned clipboardGetCodepage(UINT uType);
303static HANDLE clipboardCacheAllocGlobalDup(UINT uFormat, const void *pv, unsigned cb, PCLIPLOCALDATA *ppClip);
304static HANDLE clipboardCacheAllocGlobalAlloc(UINT uFormat, unsigned cb, PCLIPLOCALDATA *ppClip);
305static BOOL clipboardCacheAllocGlobalMem(UINT uFormat, HANDLE hMem, PCLIPLOCALDATA *ppLocalClip);
306static BOOL clipboardCacheAllocGDI(UINT uFormat, HANDLE hGDI, PCLIPLOCALDATA *ppLocalClip);
307//static HANDLE clipboardCacheAllocPrivate(UINT uFormat, HANDLE hPrivate);
308static HANDLE clipboardCacheInsertNode(PCLIPLOCALDATA p);
309static void clipboardCacheDeleteNode(PCLIPLOCALDATA p);
310static void clipboardPMBitmapDelete(HBITMAP hbmp);
311static HBITMAP clipboardPMBitmapDuplicate(HBITMAP hbmp);
312static UINT clipboardEnumClipboardFormats(UINT uFormat);
313
314
315
316/**
317 * Converts a PM clipboard format number to an Odin format.
318 *
319 * @returns Odin format number on success.
320 * @returns 0 on failure.
321 * @param ulPMFormat PM Clipboard format number.
322 */
323UINT clipboardPMToOdinFormat(ULONG ulPMFormat)
324{
325 for (int i = 0; i < sizeof(gaFormats) / sizeof(gaFormats[0]); i++)
326 if (gaFormats[i].ulPM == ulPMFormat)
327 return gaFormats[i].uOdin;
328 for (PCLIPDYNFORMMAP p = gpDynFormats; p; p = p->pNext)
329 if (p->ulPM == ulPMFormat)
330 return p->uOdin;
331
332 /*
333 * Now this becomes interesting.
334 *
335 * We need to check if this is one of the dynamically registered
336 * GDI formats or private formats. Another odin process can have
337 * started using it and we should see it.
338 *
339 * We can tell by the atom name.
340 */
341 char szAtomName[64];
342 ULONG cch;
343 cch = OSLibWinQueryAtomName(OSLibWinQuerySystemAtomTable(), ulPMFormat, &szAtomName[0], sizeof(szAtomName));
344 if (cch > 0)
345 {
346 char *psz;
347 if (!strncmp(szAtomName, SZFMT_GDIOBJ_PREFIX, sizeof(SZFMT_GDIOBJ_PREFIX) - 1))
348 psz = szAtomName + sizeof(SZFMT_GDIOBJ_PREFIX) - 1;
349 else if (!strncmp(szAtomName, SZFMT_PRIVATE_PREFIX, sizeof(SZFMT_PRIVATE_PREFIX) - 1))
350 psz = szAtomName + sizeof(SZFMT_PRIVATE_PREFIX) - 1;
351 else
352 return 0; /* not found! */
353 /* parse the number. */
354 UINT uRet = atoi(psz);
355 if (uRet >= CF_PRIVATEFIRST && uRet <= CF_GDIOBJLAST)
356 {
357 ULONG ulPMAdded = clipboardAddDynFormat(uRet, NULL);
358 DebugAssert(ulPMAdded == ulPMFormat,
359 ("ARG! Didn't get the same value for the same atoms! odin32=%d pm=%d pmadd=%d name='%s'\n",
360 uRet, ulPMFormat, ulPMAdded, szAtomName));
361 return uRet;
362 }
363 }
364
365 return 0; /* not found. */
366}
367
368
369/**
370 * Adds a dynamicly managed Odin clipboard format to the internal list.
371 *
372 * @returns PM format number.
373 * @returns 0 on failure.
374 * @param uFormat Odin clipboard format number.
375 * @param pszFormatName The format name.
376 * For the two predefined ranges this argument is NULL.
377 * @todo serialize this!
378 */
379ULONG clipboardAddDynFormat(UINT uFormat, const char *pszFormatName)
380{
381 char szFormat[64];
382
383 /*
384 * Generate name for the predefined ones.
385 */
386 if (!pszFormatName)
387 {
388 if (uFormat >= CF_PRIVATEFIRST && uFormat <= CF_PRIVATELAST)
389 sprintf(szFormat, SZFMT_PRIVATE_PREFIX "%u", uFormat);
390 else if (uFormat >= CF_GDIOBJFIRST && uFormat <= CF_GDIOBJLAST)
391 sprintf(szFormat, SZFMT_GDIOBJ_PREFIX "%u", uFormat);
392 else
393 {
394 DebugAssertFailed(("Invalid format range %u\n", uFormat));
395 return 0;
396 }
397 pszFormatName = szFormat;
398 }
399
400 /*
401 * Register atom
402 */
403 ULONG ulPMFormat = OSLibWinAddAtom(OSLibWinQuerySystemAtomTable(), pszFormatName);
404 if (ulPMFormat == 0)
405 {
406 DebugAssertFailed(("Faild to add atom '%s'. last error=%d\n", pszFormatName, OSLibWinGetLastError()));
407 return 0;
408 }
409
410 /*
411 * Create a dynamic structure and insert it into the LIFO.
412 */
413 PCLIPDYNFORMMAP p = (PCLIPDYNFORMMAP)malloc(sizeof(*p));
414 if (!p)
415 return 0;
416 p->pszName = pszFormatName != szFormat ? strdup(pszFormatName) : NULL;
417 p->ulPM = ulPMFormat;
418 p->uOdin = uFormat;
419 p->pNext = gpDynFormats;
420 gpDynFormats = p;
421
422 dprintf(("USER32: clipboardAddDynFormat: Added odin=%d pm=%d name='%s'\n", uFormat, ulPMFormat, pszFormatName));
423 return ulPMFormat;
424}
425
426
427/**
428 * Converts a PM clipboard format number to an Odin format.
429 *
430 * @returns Odin format number on success.
431 * @returns 0 on failure.
432 * @param ulPMFormat PM Clipboard format number.
433 */
434ULONG clipboardOdinToPMFormat(UINT uOdinFormat)
435{
436 if (uOdinFormat == 0)
437 return 0;
438 for (int i = 0; i < sizeof(gaFormats) / sizeof(gaFormats[0]); i++)
439 if (gaFormats[i].uOdin == uOdinFormat)
440 return gaFormats[i].ulPM;
441 for (PCLIPDYNFORMMAP p = gpDynFormats; p; p = p->pNext)
442 if (p->uOdin == uOdinFormat)
443 return p->ulPM;
444
445 /*
446 * Now this becomes interesting.
447 *
448 * A format showed up which we don't know yet. It could be one
449 * of the built in GDIOBJ or PRIVATE ones, if so we should
450 * register them in the dynamic list.
451 */
452 if (uOdinFormat >= CF_PRIVATEFIRST && uOdinFormat <= CF_GDIOBJLAST)
453 return clipboardAddDynFormat(uOdinFormat, NULL);
454 return 0; /* not found. */
455}
456
457
458#ifdef DEBUG_LOGGING
459/**
460 * Gets the name of a format.
461 *
462 * @returns Pointer to const
463 * @param uFormat Format number.
464 * @remark Note that for non standard formats a pointer to a static buffer is
465 * returned. This may be messed up if several threads are doing this
466 * at the same time. (fat chance)
467 */
468const char *dbgGetFormatName(UINT uFormat)
469{
470 static char szBuffer[256];
471 for (int i = 0; i < sizeof(gaFormats) / sizeof(gaFormats[0]); i++)
472 if (gaFormats[i].uOdin == uFormat)
473 return gaFormats[i].pszDescr;
474
475 for (PCLIPDYNFORMMAP p = gpDynFormats; p; p = p->pNext)
476 if (p->uOdin == uFormat)
477 {
478 if (p->pszName)
479 return p->pszName; /* registered */
480 if (uFormat >= CF_PRIVATEFIRST && uFormat <= CF_PRIVATELAST)
481 sprintf(szBuffer, "CF_PRIVATE no.%d", uFormat - CF_PRIVATEFIRST);
482 else if (uFormat >= CF_GDIOBJFIRST && uFormat <= CF_GDIOBJLAST)
483 sprintf(szBuffer, "CF_PRIVATE no.%d", uFormat - CF_GDIOBJFIRST);
484 DebugInt3();
485 break;
486 }
487
488 sprintf(szBuffer, "Unknown format %#x", uFormat);
489 return szBuffer;
490}
491
492/**
493 * Debug helper which dumps clipboard data.
494 *
495 * @param pszPrefix Message prefix.
496 * @param uFormat Data format of hData.
497 * @param hData Global memory handle.
498 */
499void dbgDumpClipboardData(const char *pszPrefix, UINT uFormat, HANDLE hData)
500{
501 LPVOID pv = NULL;
502 DWORD cb = 0;
503
504 /*
505 * Get the data.
506 */
507 switch (uFormat)
508 {
509 /* handles */
510 case CF_BITMAP:
511 case CF_METAFILEPICT:
512 case CF_DSPBITMAP:
513 case CF_DSPMETAFILEPICT:
514 case CF_ENHMETAFILE:
515 case CF_HDROP:
516 case CF_PALETTE:
517 pv = NULL;
518 break;
519
520 /* all the rest */
521 default:
522 if (uFormat >= CF_PRIVATEFIRST && uFormat <= CF_PRIVATELAST)
523 pv = NULL;
524 else
525 {
526 if (hData)
527 {
528 pv = GlobalLock(hData);
529 cb = GlobalSize(hData);
530 }
531 else
532 pv = NULL;
533 }
534 break;
535 }
536 dprintf(("%s: uFormat=%#x (%s) hData=%#x {locked=%p size=%d}\n",
537 pszPrefix, uFormat, dbgGetFormatName(uFormat), hData, pv, cb));
538
539 /*
540 * Dump the data.
541 */
542 if (pv)
543 {
544 switch (uFormat)
545 {
546 case CF_TEXT:
547 case CF_DSPTEXT:
548 dprintf(("%s: '%s'", pszPrefix, (char*)pv));
549 if (strlen((char *)pv) + 1 != cb)
550 dprintf(("%s: not properly null terminated? strlen()->%d", pszPrefix, strlen((char *)pv)));
551 break;
552 case CF_UNICODETEXT:
553 dprintf(("%s: '%ls'", pszPrefix, (wchar_t*)pv));
554 if (lstrlenW((LPCWSTR)pv) + 1 != cb / sizeof(wchar_t))
555 dprintf(("%s: not properly null terminated? wcslen()->%d", pszPrefix, lstrlenW((LPCWSTR)pv)));
556 break;
557
558 default:
559 {
560 /* quick and somewhat ugly memory dump routine. */
561 LPBYTE pb;
562 DWORD off;
563 for (off = 0, pb = (LPBYTE)pv; off < cb; off += 16, pb += 16)
564 {
565 char sz[80];
566 char *pszHex = &sz[sprintf(sz, "%08x ", off)];
567 char *pszBin = pszHex + 16*3 + 2;
568 for (int i = 0; i < 16; i++, pszHex += 3, pszBin++)
569 {
570 if (i + off < cb)
571 {
572 static const char szHexDigits[17] = "0123456789abcdef";
573 pszHex[0] = szHexDigits[pb[i] >> 4];
574 pszHex[1] = szHexDigits[pb[i] & 0xf];
575 pszHex[2] = i != 7 ? ' ' : '-';
576 if (isprint(pb[i]))
577 *pszBin = pb[i];
578 else
579 *pszBin = '.';
580 }
581 else
582 {
583 memset(pszHex, ' ', 3);
584 *pszBin = '\0';
585 }
586 }
587 pszHex[0] = ' ';
588 pszHex[1] = ' ';
589 *pszBin = '\0';
590 dprintf(("%s\n", sz));
591 }
592 break;
593 }
594 }
595 }
596}
597#endif
598
599
600/**
601 * Initalizes the clipboard formats Odin32 uses.
602 *
603 * These are not the same as the Open32 ones because Odin will put
604 * different data out on the clipboard (the CLIPHEADER header).
605 *
606 * @returns Success indicator.
607 */
608BOOL WIN32API InitClipboardFormats(void)
609{
610 dprintf2(("USER32: InitClipboardFormats\n"));
611 BOOL fRc = TRUE;
612 HANDLE hSysAtomTable = OSLibWinQuerySystemAtomTable();
613 for (int i = 0; i < sizeof(gaFormats) / sizeof(gaFormats[0]); i++)
614 {
615 if (gaFormats[i].pszRegString)
616 {
617 gaFormats[i].ulPM = OSLibWinAddAtom(hSysAtomTable, gaFormats[i].pszRegString);
618 DebugAssert(gaFormats[i].ulPM > 20 /* MAX OS/2 predefined format */,
619 ("WinAddAtom failed or returns to low value, %d, for '%s'.\n",
620 gaFormats[i].ulPM, gaFormats[i].pszRegString));
621 if (gaFormats[i].ulPM <= 20)
622 fRc = FALSE;
623 }
624 dprintf2(("odin=0x%04x os2=0x%04x %s\n", gaFormats[i].uOdin, gaFormats[i].ulPM, gaFormats[i].pszDescr));
625 }
626 return fRc;
627}
628
629
630
631//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
632//
633//
634// C L I P B O A R D V I E W E R S
635//
636//
637//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
638
639
640
641/**
642 * Adds a window to the clipboard viewer list.
643 *
644 * @returns HWND of the next window.
645 * @returns 0 on failure, last error set.
646 * @param hwndNewViewer Window to add.
647 * @status partially implemented
648 * @author knut st. osmundsen <bird-srcspam@anduin.net>
649 * @remark PM manages the list, not the caller, therefor the return is allways NULL.
650 */
651HWND WIN32API SetClipboardViewer(HWND hwndNewViewer)
652{
653 /*
654 * Validate and translate hwndNewViewer to an OS/2 handle.
655 */
656 HWND hwndOS2 = OSLIB_HWND_DESKTOP; /* open32 does this it seems. */
657 if (hwndNewViewer)
658 {
659 Win32BaseWindow * pWnd = Win32BaseWindow::GetWindowFromHandle(hwndNewViewer);
660 if (!pWnd)
661 {
662 SetLastError(ERROR_INVALID_WINDOW_HANDLE);
663 dprintf(("USER32: SetClipboardViewer: returns 0 (invalid window)\n"));
664 return NULL;
665 }
666 hwndOS2 = pWnd->getOS2WindowHandle();
667 RELEASE_WNDOBJ(pWnd);
668 }
669
670 /*
671 * Add the viewer.
672 */
673 if (!OSLibWin32AddClipbrdViewer(hwndOS2))
674 {
675 SetLastError(ERROR_NOT_ENOUGH_MEMORY); // just something.
676 dprintf(("USER32: Win32AddClipbrdViwer failed. lasterr=%#x\n", OSLibWinGetLastError()));
677 }
678 dprintf(("USER32: SetClipboardViewer returns 0 (allways)\n"));
679 return NULL;
680}
681
682
683/**
684 * Gets the current clipboard viewer.
685 *
686 * @returns Window handle of the clipboard viewer.
687 * @returns NULL if no viewer or non odin window.
688 * @status partially implemented.
689 * @author knut st. osmundsen <bird-srcspam@anduin.net>
690 * @remark Hides OS/2 windows.
691 */
692HWND WIN32API GetClipboardViewer(void)
693{
694 /*
695 * Query the viewer from PM and translate it to an Odin window handle.
696 */
697 HWND hwnd = NULL;
698 HWND hwndOS2 = OSLibWin32QueryClipbrdViewerChain();
699 if (hwndOS2)
700 {
701 Win32BaseWindow *pWnd = Win32BaseWindow::GetWindowFromOS2Handle(hwndOS2);
702 if (pWnd)
703 {
704 hwnd = pWnd->getWindowHandle();
705 RELEASE_WNDOBJ(pWnd);
706 }
707 }
708 dprintf(("USER32: GetClipboardViewer: returns %# (os2=%#x)\n", hwnd, hwndOS2));
709 return hwnd;
710}
711
712
713/**
714 * Removes a specific window from the chain of clipboard viewers.
715 *
716 * @returns Success indicator. Last error set on failure.
717 * @param hwndRemove Handle of viewer window to remove.
718 * @param hwndNext Handle to the next window in the chain.
719 * OS/2 doesn't support this, so we ignore it.
720 * @status partially implemented.
721 * @author knut st. osmundsen <bird-srcspam@anduin.net>
722 */
723BOOL WIN32API ChangeClipboardChain(HWND hwndRemove, HWND hwndNext)
724{
725 dprintf(("USER32: ChangeClipboardChain: hwndRemove=%#x hwndNext=%#x\n", hwndRemove, hwndNext));
726
727 /*
728 * Validate input handles and translate them to OS/2 windows.
729 */
730 Win32BaseWindow *pWnd = Win32BaseWindow::GetWindowFromHandle(hwndRemove);
731 if (!pWnd)
732 {
733 dprintf(("USER32: ChangeClipboardChain: window %x not found\n", hwndRemove));
734 SetLastError(ERROR_INVALID_WINDOW_HANDLE);
735 return FALSE;
736 }
737 HWND hwndOS2Remove = pWnd->getOS2WindowHandle();
738 RELEASE_WNDOBJ(pWnd);
739
740 if (hwndNext)
741 {
742 /*
743 * SetClipboardViewer never returns a hwndNext, so this must
744 * be an program trying to alter things in a way other than we like...
745 * We might find that we have to support this using the Wn32AddClipbrdViewer
746 * or something later, but for now we fail.
747 */
748
749 /* validate it, to come up with a more believable story. */
750 pWnd = Win32BaseWindow::GetWindowFromHandle(hwndNext);
751 if (!pWnd)
752 {
753 dprintf(("USER32: ChangeClipboardChain: window %x not found\n", hwndNext));
754 SetLastError(ERROR_INVALID_WINDOW_HANDLE);
755 return FALSE;
756 }
757 HWND hwndOS2Next = pWnd->getOS2WindowHandle();
758 RELEASE_WNDOBJ(pWnd);
759 DebugAssertFailed(("USER32: ChangeClipboardChain: hwndNext=%#x/%#x is not supported!!!\n", hwndNext, hwndOS2Next));
760 SetLastError(ERROR_INVALID_PARAMETER);
761 return FALSE;
762 }
763
764 /*
765 * Change the chain.
766 */
767 BOOL fRc = OSLibWin32RemoveClipbrdViewer(hwndOS2Remove);
768 dprintf(("USER32: ChangeClipboardChain returns %d\n", fRc));
769 return fRc;
770}
771
772
773
774
775//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
776//
777//
778// C L I P B O A R D N O N - O P E N O P E R A T I O N S
779//
780//
781//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
782
783/**
784 * Checks if a format is available on the PM clipboard.
785 *
786 * @returns TRUE if it's there, FALSE if it isn't
787 * @param uFormat Odin format number.
788 */
789BOOL clipboardIsAvailable(UINT uFormat)
790{
791 ULONG ulPMFormat = clipboardOdinToPMFormat(uFormat);
792 if (!ulPMFormat)
793 return FALSE;
794 ULONG flInfo;
795 return OSLibWinQueryClipbrdFmtInfo(GetThreadHAB(), ulPMFormat, &flInfo);
796}
797
798
799/**
800 * Checks if a real representation of a format is available on the PM
801 * clipboard. (Real representation means ignoring dummy entries.)
802 *
803 * @returns TRUE if it's there, FALSE if it isn't
804 * @param uFormat Odin format number.
805 */
806BOOL clipboardIsAvailableReal(UINT uFormat)
807{
808 ULONG ulPMFormat = clipboardOdinToPMFormat(uFormat);
809 if (!ulPMFormat)
810 return FALSE;
811 ULONG flInfo = 0;
812 HANDLE hab = GetThreadHAB();
813 if (!OSLibWinQueryClipbrdFmtInfo(hab, ulPMFormat, &flInfo))
814 return FALSE;
815 if (!(flInfo & OSLIB_CFI_HANDLE))
816 return TRUE;
817 return OSLibWinQueryClipbrdData(hab, ulPMFormat) != DUMMY_HANDLE;
818}
819
820
821/**
822 * Count the number of available clipboard formats.
823 *
824 * @returns Number of clipboard forats on the clipboard.
825 * @status completely implemented.
826 * @author knut st. osmundsen <bird-srcspam@anduin.net>
827 * @remark This call can be done without opening the clipboard.
828 */
829int WIN32API CountClipboardFormats(void)
830{
831 int cRet = 0;
832 UINT uFormat = 0;
833 HANDLE hab = GetThreadHAB();
834
835 while ((uFormat = clipboardEnumClipboardFormats(uFormat)) != 0)
836 cRet++;
837
838 dprintf(("USER32: CountClipboardFormats: returns %d\n", cRet));
839 return cRet;
840}
841
842
843/**
844 * Checks if a given format is available on the clipboard.
845 *
846 * @returns TRUE if it's availble, else false.
847 * @param uFormat Format to check for.
848 * @status completely implemented.
849 * @author knut st. osmundsen <bird-srcspam@anduin.net>
850 */
851BOOL WIN32API IsClipboardFormatAvailable(UINT uFormat)
852{
853 ULONG ulPMFormat = clipboardOdinToPMFormat(uFormat);
854 if (!ulPMFormat)
855 {
856 dprintf(("USER32: IsClipboardFormatAvailable: uFormat=%d returns FALSE (unknown format)\n", uFormat));
857 return FALSE;
858 }
859
860 ULONG flInfo;
861 BOOL fRc = OSLibWinQueryClipbrdFmtInfo(GetThreadHAB(), ulPMFormat, &flInfo);
862 if (!fRc && (!clipboardIsRWOwner() || !gfClipboardChanged))
863 fRc = clipboardShouldBeSynthesized(uFormat);
864 dprintf(("USER32: IsClipboardFormatAvailable: %x (%s) returning %d\n",
865 uFormat, dbgGetFormatName(uFormat), fRc));
866 return fRc;
867}
868
869
870/**
871 * Get the format with the lowest index in the passed in list.
872 *
873 * @returns format number with highest priority.
874 * @returns 0 if no formats in the list.
875 * @returns 0 if no data on the clipboard.
876 * @returns -1 if non of the formats was found.
877 * @param paFormatPriorityList
878 * @param cFormats
879 * @status partially implemented
880 * @author knut st. osmundsen <bird-srcspam@anduin.net>
881 * @todo We don't check if the thread is owning the clipboard.
882 */
883int WIN32API GetPriorityClipboardFormat(UINT *paFormatPriorityList, int cFormats)
884{
885 int i;
886 dprintf(("USER32: GetPriorityClipboardFormat: paFormatPriorityList=%p cFormat=%d\n",
887 paFormatPriorityList, cFormats));
888 /*
889 * Validate input.
890 */
891 if ((paFormatPriorityList == NULL && cFormats > 0) || cFormats < 0)
892 {
893 SetLastError(ERROR_NOACCESS);
894 dprintf(("USER32: GetPriorityClipboardFormat: returns 0 (bad list pointer)\n"));
895 return 0;
896 }
897#ifdef DEBUG_LOGGING
898 for (i = 0; i < cFormats; i++)
899 dprintf2((" %d - %#x (%s)\n", i, paFormatPriorityList[i],
900 dbgGetFormatName(paFormatPriorityList[i])));
901#endif
902
903 /*
904 * Check if list is empty.
905 */
906 if (cFormats <= 0)
907 {
908 dprintf(("USER32: GetPriorityClipboardFormat: return -1 (list is empty)\n"));
909 return -1;
910 }
911
912 /*
913 * Check if clipboard is empty.
914 */
915 HANDLE hab = GetThreadHAB();
916 if (!OSLibWinEnumClipbrdFmts(hab, 0))
917 {
918 dprintf(("USER32: GetPriorityClipboardFormat: return 0 (clipboard is empty)\n"));
919 return 0;
920 }
921
922 /*
923 * Walk the list.
924 */
925 for (i = 0; i < cFormats; i++)
926 {
927 if (IsClipboardFormatAvailable(paFormatPriorityList[i]))
928 {
929 dprintf(("USER32: GetPriorityClipboardFormat: return %d (%s), index %d\n",
930 paFormatPriorityList[i], dbgGetFormatName(paFormatPriorityList[i]), i));
931 return paFormatPriorityList[i];
932 }
933 }
934
935 dprintf(("USER32: GetPriorityClipboardFormat: return -1 (not found)\n"));
936 return -1;
937}
938
939/**
940 * Gets the format name of a registered clipboard format.
941 *
942 * @returns number of bytes in lpszFormatName which was used not counting the terminator.
943 * @returns 0 on failure, last error set.
944 * @param uFormat Format number.
945 * @param lpszFormatName Where to store the name.
946 * @param cchMaxCount Size of the buffer.
947 * @status completely implemented.
948 * @author knut st. osmundsen <bird-srcspam@anduin.net>
949 */
950int WIN32API GetClipboardFormatNameA(UINT uFormat, LPSTR lpszFormatName, int cchMaxCount)
951{
952 dprintf(("USER32: GetClipboardFormatNameA: uFormat=%d buf=%p cchBuf=%d\n",
953 uFormat, lpszFormatName, cchMaxCount));
954
955 /*
956 * Validate input.
957 */
958 if (uFormat < MAXINTATOM)
959 {
960 SetLastError(ERROR_INVALID_PARAMETER);
961 dprintf(("USER32: GetClipboardFormatNameA: returns 0 (builtin format)\n"));
962 return 0;
963 }
964
965 /*
966 * Do work.
967 */
968 int rc = GetAtomNameA((ATOM)uFormat, lpszFormatName, cchMaxCount);
969 dprintf(("USER32: GetClipboardFormatNameA: returns %d (%s)\n", rc, rc > 0 ? lpszFormatName : NULL));
970 return rc;
971}
972
973
974/**
975 * Gets the format name of a registered clipboard format.
976 *
977 * @returns number of bytes in lpszFormatName which was used not counting the terminator.
978 * @returns 0 on failure, last error set.
979 * @param uFormat Format number.
980 * @param lpszFormatName Where to store the name.
981 * @param cchMaxCount Size of the buffer.
982 * @status completely implemented.
983 * @author knut st. osmundsen <bird-srcspam@anduin.net>
984 */
985int WIN32API GetClipboardFormatNameW(UINT uFormat, LPWSTR lpszFormatName, int cchMaxCount)
986{
987 dprintf(("USER32: GetClipboardFormatNameW: uFormat=%d buf=%p cchBuf=%d\n",
988 uFormat, lpszFormatName, cchMaxCount));
989
990 /*
991 * Validate input.
992 */
993 if (uFormat < MAXINTATOM)
994 {
995 SetLastError(ERROR_INVALID_PARAMETER);
996 dprintf(("USER32: GetClipboardFormatNameW: returns 0 (builtin format)\n"));
997 return 0;
998 }
999
1000 /*
1001 * Do work.
1002 */
1003 int rc = GetAtomNameW((ATOM)uFormat, lpszFormatName, cchMaxCount);
1004 dprintf(("USER32: GetClipboardFormatNameW: returns %d (%ls)\n", rc, rc > 0 ? lpszFormatName : NULL));
1005 return rc;
1006}
1007
1008
1009/**
1010 * Register a name application specific clipboard format.
1011 *
1012 * @returns The clipboard number for the format.
1013 * @returns 0 on failure, last error set.
1014 * @param pszName Clipboard format name.
1015 * @status completely implemented.
1016 * @author knut st. osmundsen <bird-srcspam@anduin.net>
1017 */
1018UINT WIN32API RegisterClipboardFormatA(LPCSTR pszName)
1019{
1020 dprintf(("USER32: RegisterClipboardFormatA: pszName=%s\n", pszName));
1021
1022 /*
1023 * Custom formats are atoms.
1024 * And for some reason which isn't too obvious to me, they are local
1025 * atoms, not global atoms like in OS/2. I might be wrong here...
1026 */
1027 UINT uFormat = AddAtomA(pszName);
1028 if (uFormat)
1029 {
1030 char szName[256];
1031 sprintf(szName, "odin32 dyn: %.242s", pszName);
1032 clipboardAddDynFormat(uFormat, szName);
1033 }
1034 dprintf(("USER32: RegisterClipboardFormatA: returns %u\n", uFormat));
1035 return uFormat;
1036}
1037
1038
1039/**
1040 * Register a name application specific clipboard format.
1041 *
1042 * @returns The clipboard number for the format.
1043 * @returns 0 on failure, last error set.
1044 * @param pszName Clipboard format name.
1045 * @status completely implemented.
1046 * @author knut st. osmundsen <bird-srcspam@anduin.net>
1047 */
1048UINT WIN32API RegisterClipboardFormatW(LPCWSTR pszName)
1049{
1050 dprintf(("USER32: RegisterClipboardFormatW: pszName=%ls\n", pszName));
1051
1052 /*
1053 * Custom formats are atoms.
1054 * And for some reason which isn't too obvious to me, they are local
1055 * atoms, not global atoms like in OS/2. I might be wrong here...
1056 */
1057 UINT uFormat = AddAtomW(pszName);
1058 if (uFormat)
1059 {
1060 char szName[256];
1061 sprintf(szName, "odin32 dyn: %.242ls", pszName); /* bogus to use crt for unicode->ascii conversion? */
1062 clipboardAddDynFormat(uFormat, szName);
1063 }
1064 dprintf(("USER32: RegisterClipboardFormatW: returns %u\n", uFormat));
1065 return uFormat;
1066}
1067
1068
1069/**
1070 * Gets the window handle of the current clipboard owner.
1071 *
1072 * @returns HWND of current owner.
1073 * @returns NULL if no owner.
1074 * @status partially implemented.
1075 * @author knut st. osmundsen <bird-srcspam@anduin.net>
1076 * @remark We do not report back any OS/2 windows.
1077 */
1078HWND WIN32API GetClipboardOwner(void)
1079{
1080 /*
1081 * Query the owner from PM and translate it to an Odin window handle.
1082 */
1083 HWND hwnd = NULL;
1084 HWND hwndOS2 = OSLibWinQueryClipbrdOwner(GetThreadHAB());
1085 if (hwndOS2)
1086 {
1087 Win32BaseWindow *pWnd = Win32BaseWindow::GetWindowFromOS2Handle(hwndOS2);
1088 if (pWnd)
1089 {
1090 hwnd = pWnd->getWindowHandle();
1091 RELEASE_WNDOBJ(pWnd);
1092 }
1093 }
1094
1095 dprintf(("USER32: GetClipboardOwner: returns %#x (os2=%#x)\n", hwnd, hwndOS2));
1096 return hwnd;
1097}
1098
1099
1100/**
1101 * Gets the hwnd of the window which currently have the clipboard open.
1102 *
1103 * @returns the HWND of the window.
1104 * @returns NULL if the clipboard is not opened by anyone or the open
1105 * didn't supply a window handle (like PM).
1106 * @status completely implemented.
1107 * @author knut st. osmundsen <bird-srcspam@anduin.net>
1108 */
1109HWND WIN32API GetOpenClipboardWindow(void)
1110{
1111 /*
1112 * Get the open windown handle and translate it.
1113 */
1114 HWND hwnd = NULL;
1115 HWND hwndOS2 = OSLibWin32QueryOpenClipbrdWindow();
1116 if (hwndOS2)
1117 {
1118 Win32BaseWindow *pWnd = Win32BaseWindow::GetWindowFromOS2Handle(hwndOS2);
1119 if (pWnd)
1120 {
1121 hwnd = pWnd->getWindowHandle();
1122 RELEASE_WNDOBJ(pWnd);
1123 }
1124 }
1125 DebugAssert(ghwndOpenClipboard == hwnd, ("ghwndOpenClipboard=%#x actual=%#x\n", ghwndOpenClipboard, hwnd));
1126 DebugAssert((!hwnd && !ghwndOS2OpenClipboard) || (hwnd && ghwndOS2OpenClipboard != hwndOS2),
1127 ("ghwndOS2OpenClipboard=%#x actual=%#x\n", ghwndOS2OpenClipboard, hwndOS2));
1128 dprintf(("USER32: GetOpenCliboardWindow: returning %#x (os2=%#x)\n", hwnd, hwndOS2));
1129 return hwnd;
1130}
1131
1132
1133
1134
1135
1136
1137//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
1138//
1139//
1140// C L I P B O A R D O P E N E D O P E R A T I O N S
1141//
1142//
1143//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
1144
1145
1146/**
1147 * Checks if the current thread is the clipboard owner with read/write access.
1148 *
1149 * @returns TRUE if we're the owner, FALSE if not.
1150 */
1151BOOL clipboardIsRWOwner(void)
1152{
1153#if 1
1154 /*
1155 * The simple way.
1156 */
1157 return gtidOpenClipboardThreadId == GetCurrentThreadId();
1158#else
1159 /*
1160 * This is gonna be a bit hacky.
1161 * We'll try to open the clipboard and then determin whether or not
1162 * we already owned it by the return code and such.
1163 */
1164 BOOL fRc = FALSE;
1165 HAB hab = GetThreadHAB();
1166 OSLibWinSetErrorInfo(0, 0);
1167 OSLibWinGetLastError();
1168 if (!OSLib_OpenClipbrd(hab, (HWND)0xdeadface))
1169 {
1170 /* check why we failed. */
1171 if ((OSLibWinGetLastError() & 0xffff) == OSLIB_PMERR_CALL_FROM_WRONG_THREAD)
1172 fRc = TRUE;
1173 }
1174 else
1175 {
1176 /* we might have to close it ... */
1177 ULONG ulRc = OSLibWinGetLastError();
1178 if ((ulRc & 0xffff) == OSLIB_PMERR_CALL_FROM_WRONG_THREAD)
1179 {
1180 fRc = TRUE;
1181 DebugAssertFailed(("Open returned TRUE while last error was PMERR_CALL_FROM_WRONG_THREAD. bad heuristics!!!\n"));
1182 }
1183 else
1184 {
1185 DebugAssert(ulRc == 0, ("Last error is %#x and not 0x0 as we expected!!!\n", ulRc));
1186 OSLibWinCloseClipbrd(hab);
1187 }
1188 }
1189 return fRc;
1190#endif
1191}
1192
1193
1194/**
1195 * Adds an item to the PM clipboard.
1196 *
1197 * @returns success indicator.
1198 * @param uOdinFormat Odin format number.
1199 * @param pv Pointer to a buffer containing the data.
1200 * If fAllocate is clear this is a buffer allocated
1201 * using clipboardAllocPMBuffer()
1202 * @param cb Size of the data in the buffer.
1203 */
1204BOOL clipboardAddPM(UINT uOdinFormat, void *pv, unsigned cb)
1205{
1206 DebugAssert(uOdinFormat == CF_TEXT || uOdinFormat == CF_BITMAP || uOdinFormat == CF_PALETTE,
1207 ("%d should have a header. fixme!!!\n", uOdinFormat));
1208 /*
1209 * Validate and translate the format number.
1210 */
1211 ULONG ulPMFormat = clipboardOdinToPMFormat(uOdinFormat);
1212 DebugAssert(ulPMFormat > 0, ("failed to convert odin format %d to PM!!!\n", uOdinFormat));
1213 if (ulPMFormat == 0)
1214 return FALSE;
1215
1216 /*
1217 * Allocate PM Clipboard buffer.
1218 */
1219 void *pvBuf = (PCLIPHEADER)clipboardAllocPMBuffer(cb);
1220 if (!pvBuf)
1221 return FALSE;
1222 pv = memcpy(pvBuf, pv, cb);
1223
1224 /*
1225 * Place it on the clipboard.
1226 */
1227 if (OSLibWinSetClipbrdData(GetThreadHAB(),(ULONG)pvBuf, ulPMFormat, OSLIB_CFI_POINTER))
1228 return TRUE;
1229 DebugAssertFailed(("WinSetClipbrdData failed!!! lasterr=%#x\n", OSLibWinGetLastError()));
1230 return FALSE;
1231}
1232
1233
1234/**
1235 * Adds an item to the PM clipboard.
1236 *
1237 * @returns success indicator.
1238 * @param uOdinFormat Odin format number.
1239 * @param pv Pointer to a buffer containing the data.
1240 * If fAllocate is clear this is a buffer allocated
1241 * using clipboardAllocPMBuffer()
1242 * @param cb Size of the data in the buffer.
1243 */
1244BOOL clipboardAddPMHeader(UINT uOdinFormat, void *pv, unsigned cb)
1245{
1246 DebugAssert(uOdinFormat != CF_TEXT && uOdinFormat != CF_BITMAP && uOdinFormat != CF_PALETTE,
1247 ("%d should not have a header. fixme!!!\n", uOdinFormat));
1248 /*
1249 * Validate and translate the format number.
1250 */
1251 ULONG ulPMFormat = clipboardOdinToPMFormat(uOdinFormat);
1252 DebugAssert(ulPMFormat > 0, ("failed to convert odin format %d to PM!!!\n", uOdinFormat));
1253 if (ulPMFormat == 0)
1254 return FALSE;
1255
1256 /*
1257 * Allocate PM Clipboard buffer.
1258 */
1259 PCLIPHEADER pClip = (PCLIPHEADER)clipboardAllocPMBuffer(cb + sizeof(CLIPHEADER));
1260 if (!pClip)
1261 return FALSE;
1262 memcpy(pClip->achMagic, CLIPHEADER_MAGIC, sizeof(CLIPHEADER_MAGIC));
1263 pClip->cbData = cb;
1264 pClip->uFormat = uOdinFormat;
1265 pv = memcpy(pClip + 1, pv, cb);
1266
1267 /*
1268 * Place it on the clipboard.
1269 */
1270 if (OSLibWinSetClipbrdData(GetThreadHAB(),(ULONG)pClip, ulPMFormat, OSLIB_CFI_POINTER))
1271 return TRUE;
1272 DebugAssertFailed(("WinSetClipbrdData failed!!! lasterr=%#x\n", OSLibWinGetLastError()));
1273 return FALSE;
1274}
1275
1276
1277/**
1278 * Adds an item to the PM clipboard.
1279 *
1280 * @returns success indicator.
1281 * @param uOdinFormat Odin format number.
1282 * @param h Handle.
1283 */
1284BOOL clipboardAddPMHandle(UINT uOdinFormat, HANDLE h)
1285{
1286 DebugAssert(uOdinFormat == CF_TEXT || uOdinFormat == CF_BITMAP || uOdinFormat == CF_PALETTE,
1287 ("%d should have a header. fixme!!!\n", uOdinFormat));
1288 /*
1289 * Validate and translate the format number.
1290 */
1291 ULONG ulPMFormat = clipboardOdinToPMFormat(uOdinFormat);
1292 DebugAssert(ulPMFormat > 0, ("failed to convert odin format %d to PM!!!\n", uOdinFormat));
1293 if (ulPMFormat == 0)
1294 return FALSE;
1295
1296 /*
1297 * Place it on the clipboard.
1298 */
1299 if (OSLibWinSetClipbrdData(GetThreadHAB(),(ULONG)h, ulPMFormat, OSLIB_CFI_HANDLE))
1300 return TRUE;
1301 DebugAssertFailed(("WinSetClipbrdData failed!!! lasterr=%#x\n", OSLibWinGetLastError()));
1302 return FALSE;
1303}
1304
1305
1306/**
1307 * Allocates a buffer for use with the PM clipboard.
1308 *
1309 * @returns Pointer to buffer.
1310 * @returns NULL on failure.
1311 * @param cb Size of buffer.
1312 */
1313void * clipboardAllocPMBuffer(unsigned cb)
1314{
1315 /*
1316 * Dos alloc a shared buffer.
1317 */
1318 PVOID pv = NULL;
1319 ULONG rc = OSLibDosAllocSharedMem(&pv, NULL, (cb + 0xfff) & ~0xfff, OSLIB_PAG_READ | OSLIB_PAG_WRITE | OSLIB_PAG_COMMIT | OSLIB_OBJ_GIVEABLE);
1320 if (rc)
1321 return NULL;
1322 return pv;
1323}
1324
1325
1326
1327/**
1328 * Inserts a dummy placeholder in the clipboard.
1329 *
1330 * @returns Success indicator.
1331 * @param uOdinFormat Odin clipboard format number.
1332 * @remark The few other applications using the Open32 defined
1333 * format names may not like this...
1334 */
1335BOOL clipboardAddPMDummy(UINT uOdinFormat)
1336{
1337 /*
1338 * Validate and translate the format number.
1339 */
1340 ULONG ulPMFormat = clipboardOdinToPMFormat(uOdinFormat);
1341 DebugAssert(ulPMFormat > 0, ("failed to convert odin format %d to PM!!!\n", uOdinFormat));
1342 if (ulPMFormat == 0)
1343 return FALSE;
1344
1345 /*
1346 * Insert a dummy handle.
1347 */
1348 BOOL fRc = OSLibWinSetClipbrdData(GetThreadHAB(), DUMMY_HANDLE, ulPMFormat, OSLIB_CFI_HANDLE);
1349 DebugAssert(fRc, ("WinSetClipbrdData failed. lasterr=%#x\n", OSLibWinGetLastError()));
1350 return fRc;
1351}
1352
1353
1354/**
1355 * Tries to figure out the size of the data retrieved from the clipboard.
1356 *
1357 * @returns 0 on failure.
1358 * @returns size in bytes of the data.
1359 * @param pvData Data retrieved from the clipboard.
1360 */
1361ULONG clipboardGetPMDataSize(void *pvData)
1362{
1363 ULONG fl = ~0;
1364 ULONG cb = ~0;
1365 ULONG ulRc = OSLibDosQueryMem(pvData, &cb, &fl);
1366 if (ulRc)
1367 { /* retry */
1368 fl = ~0;
1369 cb = 512*1024*1024;
1370 ulRc = OSLibDosQueryMem(pvData, &cb, &fl);
1371 }
1372 if (ulRc)
1373 {
1374 DebugAssertFailed(("DosQueryMem(%#x,,) failed with rc=%d\n", pvData, ulRc));
1375 return 0;
1376 }
1377
1378 dprintf2(("data: %#x size: %d flags: %#x\n", pvData, cb, fl));
1379 return cb;
1380}
1381
1382
1383/**
1384 * Opens the clipboard.
1385 *
1386 * @returns Success indicator.
1387 * @param hwnd Handle to window which is to become owner
1388 * when EmptyClipboard is called.
1389 * If NULL the clipboard is to be associated with
1390 * the current thread.
1391 * @status completely implemented
1392 * @author knut st. osmundsen <bird-srcspam@anduin.net>
1393 * @remark This should not block, although there is a possiblity that a competing
1394 * thread may cause us to block. This is PM's fault.
1395 */
1396BOOL WIN32API OpenClipboard(HWND hwnd)
1397{
1398 HWND hwndOS2 = NULL;
1399
1400 /*
1401 * Validate input and translate window handle.
1402 */
1403 if (hwnd)
1404 {
1405 Win32BaseWindow *pWnd = Win32BaseWindow::GetWindowFromHandle(hwnd);
1406 if (!pWnd)
1407 {
1408 dprintf(("USER32: OpenClipboard: window %x not found", hwnd));
1409 SetLastError(ERROR_INVALID_WINDOW_HANDLE);
1410 return 0;
1411 }
1412 hwndOS2 = pWnd->getOS2WindowHandle();
1413 RELEASE_WNDOBJ(pWnd);
1414 }
1415
1416 /*
1417 * Open the clipboard.
1418 */
1419 dprintf(("USER32: OpenClipboard(%#x/%#x)\n", hwnd, hwndOS2));
1420 BOOL fRc = OSLib_OpenClipbrd(GetThreadHAB(), hwndOS2);
1421 if (fRc)
1422 {
1423 ghwndOpenClipboard = hwnd;
1424 ghwndOS2OpenClipboard = hwndOS2;
1425 gtidOpenClipboardThreadId = GetCurrentThreadId();
1426 gfClipboardChanged = FALSE;
1427 gfClipboardChangedText= FALSE;
1428 }
1429 dprintf(("USER32: OpenClipboard: returning %d\n", fRc));
1430 return fRc;
1431}
1432
1433
1434/**
1435 * Empty the clipboard.
1436 *
1437 * This will empty the clipboard freeing all global resources.
1438 * It will further free all local resources associated with the
1439 * clipboard.
1440 *
1441 * The window specified in the OpenClipboard() call will become
1442 * the owner of the clipboard upon successful return from this
1443 * call.
1444 *
1445 * @returns Success indicator.
1446 * @status completely implemented.
1447 * @author knut st. osmundsen <bird-srcspam@anduin.net>
1448 */
1449BOOL WIN32API EmptyClipboard(void)
1450{
1451 dprintf(("USER32: EmptyClipboard. ghwndOpenClipboard=%#x/%#x\n", ghwndOpenClipboard, ghwndOS2OpenClipboard));
1452 BOOL fRc = OSLibWinEmptyClipbrd(GetThreadHAB());
1453 if (!fRc)
1454 {
1455 ULONG ulRc = OSLibWinGetLastError();
1456 if ((ulRc & 0xffff) == OSLIB_PMERR_CALL_FROM_WRONG_THREAD)
1457 SetLastError(ERROR_CLIPBOARD_NOT_OPEN);
1458 else
1459 SetLastError(ERROR_GEN_FAILURE);
1460 dprintf(("USER32: EmptyClipboard: WinEmptyClipbrd failed. lasterr=%#x\n", ulRc));
1461 return FALSE;
1462 }
1463
1464 /*
1465 * Take clipboard ownership.
1466 */
1467 if (!OSLibWinSetClipbrdOwner(GetThreadHAB(), ghwndOS2OpenClipboard))
1468 {
1469 DebugAssertFailed(("WinSetClipbrdOwner failed!! lasterr=%#x\n", OSLibWinGetLastError()));
1470 #if 0 /* Not sure what kind of action which makes most sense. */
1471 SetLastError(ERROR_INVALID_WINDOW_HANDLE);
1472 return FALSE;
1473 #else
1474 OSLibWinSetClipbrdOwner(GetThreadHAB(), NULL);
1475 #endif
1476 }
1477
1478 /*
1479 * Free per process resources.
1480 */
1481 for (PCLIPLOCALDATA p = gpLocalData, pNext = NULL; p; p = pNext)
1482 {
1483 pNext = p->pNext;
1484 clipboardCacheDeleteNode(p);
1485 }
1486 gpLocalData = NULL;
1487 gfClipboardChanged = TRUE;
1488 gfClipboardChangedText = FALSE;
1489
1490 dprintf(("USER32: EmptyClipboard: returns successfully\n"));
1491 return TRUE;
1492}
1493
1494
1495/**
1496 * Puts data onto the clipboard.
1497 *
1498 * @returns hCliObj on success.
1499 * @returns NULL on failure, last error may be set.
1500 * @param uFormat The format of hClipObj.
1501 * @param hClipObj Handle to data to put on the clipboard.
1502 * @status partially implemented.
1503 * @author knut st. osmundsen <bird-srcspam@anduin.net>
1504 * @todo Checkup last errors!
1505 */
1506HANDLE WIN32API SetClipboardData(UINT uFormat, HANDLE hClipObj)
1507{
1508 dprintf(("SetClipboardData uFormat=%#x (%s) hClipObj=%#x", uFormat, dbgGetFormatName(uFormat), hClipObj));
1509 dbgDumpClipboardData("SetClipboardData", uFormat, hClipObj);
1510
1511 /*
1512 * Validate that the thread have opened the clipboard.
1513 */
1514 if (/* !clipboardIsRWOwner() - must allow rendering. PM catches it. ||*/ !uFormat)
1515 {
1516 SetLastError(ERROR_CLIPBOARD_NOT_OPEN);
1517 dprintf(("USER32: SetClipboardData: returns NULL (no openclipboard)\n"));
1518 return NULL;
1519 }
1520
1521 /*
1522 * Validate format.
1523 */
1524 ULONG ulPMFormat = clipboardOdinToPMFormat(uFormat);
1525 DebugAssert(!uFormat || ulPMFormat > 0, ("failed to convert odin format %d to PM!!!\n", uFormat));
1526 if (!ulPMFormat)
1527 {
1528 //last error?
1529 dprintf(("USER32: SetClipboardData: return NULL (invalid format %d)\n", uFormat));
1530 return NULL;
1531 }
1532
1533 /*
1534 * For some formats we just put out OS/2 handles, for the
1535 * others we duplicate the memory buffer passed in to us.
1536 */
1537 PCLIPLOCALDATA pLocalClip = NULL; /* Cache node for per process data. */
1538 ULONG flPMData = 0;
1539 ULONG ulPMData = 0;
1540 BOOL fHeader = TRUE; /* Whether or not to prepend an odin clip data header. */
1541 switch (uFormat)
1542 {
1543 /*
1544 * Make a duplication of the PM handle for the PM clipboard and
1545 * put the Odin32 handle in the cache.
1546 */
1547 case CF_BITMAP:
1548 case CF_DSPBITMAP:
1549 case CF_PALETTE:
1550 flPMData = OSLIB_CFI_HANDLE;
1551 if (hClipObj)
1552 {
1553 ulPMData = O32_GetPMHandleFromGDIHandle(hClipObj);
1554 if (!ulPMData)
1555 {
1556 dprintf(("USER32: SetClipboardData: return NULL. Failed to get PM handle from Odin32 %s handle %#x\n",
1557 dbgGetFormatName(uFormat), hClipObj));
1558 return NULL;
1559 }
1560
1561 /*
1562 * Duplicate the PM handle.
1563 */
1564 switch (uFormat)
1565 {
1566 case CF_BITMAP:
1567 case CF_DSPBITMAP:
1568 ulPMData = (ULONG)OSLibClipboardPMBitmapDuplicate((HBITMAP)ulPMData);
1569 break;
1570 case CF_PALETTE:
1571 ulPMData = (ULONG)OSLibClipboardPMPaletteDuplicate((HPALETTE)ulPMData);
1572 break;
1573 }
1574 if (!ulPMData)
1575 {
1576 dprintf(("USER32: SetClipboardData: return NULL. Failed to duplicate PM handle!\n"));
1577 return NULL;
1578 }
1579
1580 /*
1581 * Allocate cache node.
1582 */
1583 if (!clipboardCacheAllocGDI(uFormat, hClipObj, &pLocalClip))
1584 DebugAssertFailed(("out of memory"));
1585 }
1586 break;
1587
1588 /*
1589 * Put the metafile bits onto the clipboard.
1590 * Put hClipObj in cache for delayed freeing.
1591 */
1592 case CF_METAFILEPICT:
1593 case CF_DSPMETAFILEPICT:
1594 {
1595#if 0 //todo implement get code.
1596 flPMData = OSLIB_CFI_POINTER;
1597 if (hClipObj)
1598 {
1599 /* get the data */
1600 LPMETAFILEPICT pMeta = (LPMETAFILEPICT)GlobalLock(hClipObj);
1601 if (!pMeta)
1602 {
1603 SetLastError(ERROR_INVALID_PARAMETER);
1604 dprintf(("USER32: SetClipboardData: returns NULL (metafilepict lock)\n"));
1605 return NULL;
1606 }
1607 /* get size */
1608 DWORD cb = GetMetaFileBitsEx(pMeta->hMF, 0, NULL);
1609 dprintf2(("GetMetaFileBitsEx -> %d\n", cb));
1610 if (!cb)
1611 { /* ?? */
1612 SetLastError(ERROR_INVALID_PARAMETER);
1613 dprintf(("USER32: SetClipboardData: returns NULL (metafilepict handle)\n"));
1614 return NULL;
1615 }
1616 /* allocate shared */
1617 DWORD cbTotal = sizeof(CLIPHEADER) + sizeof(METAFILEPICT) + cb;
1618 PCLIPHEADER pClip = (PCLIPHEADER)clipboardAllocPMBuffer(cbTotal);
1619 if (!pClip)
1620 {
1621 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1622 dprintf(("USER32: SetClipboardData: returns NULL (metafilepict mem)\n"));
1623 return NULL;
1624 }
1625 /* make block */
1626 memcpy(pClip->achMagic, CLIPHEADER_MAGIC, sizeof(CLIPHEADER_MAGIC));
1627 pClip->cbData = cbTotal; /* bits + metafilepict */
1628 pClip->uFormat = uFormat;
1629 *(LPMETAFILEPICT)(pClip + 1) = *pMeta;
1630 /* (ASSUMES it's not be touched since last call to this api.) */
1631 GetMetaFileBitsEx(pMeta->hMF, cb, (char*)(pClip + 1) + sizeof(*pMeta));
1632 }
1633 break;
1634#else
1635 DebugAssertFailed(("metafile support not enabled"));
1636 return NULL;
1637#endif
1638 }
1639
1640 /*
1641 * Put the enh. metafile bits onto the clipboard.
1642 * Put hClipObj in cache for delayed freeing.
1643 */
1644 case CF_ENHMETAFILE:
1645 case CF_DSPENHMETAFILE:
1646 {
1647#if 0 //todo implement get code.
1648 flPMData = OSLIB_CFI_POINTER;
1649 if (hClipObj)
1650 {
1651 /* get size */
1652 DWORD cb = GetEnhMetaFileBits(hClipObj, 0, NULL);
1653 dprintf2(("GetEnhMetaFileBits -> %d\n", cb));
1654 if (!cb)
1655 { /* ?? */
1656 SetLastError(ERROR_INVALID_PARAMETER);
1657 dprintf(("USER32: SetClipboardData: returns NULL (enhmetafile handle)\n"));
1658 return NULL;
1659 }
1660 /* allocate shared */
1661 DWORD cbTotal = sizeof(CLIPHEADER) + cb;
1662 PCLIPHEADER pClip = (PCLIPHEADER)clipboardAllocPMBuffer(cbTotal);
1663 if (!pClip)
1664 {
1665 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1666 dprintf(("USER32: SetClipboardData: returns NULL (enhmetafile mem)\n"));
1667 return NULL;
1668 }
1669 /* make block */
1670 pClip->cbData = cbTotal; /* bits */
1671 pClip->uFormat = uFormat;
1672 /* (ASSUMES it's not be touched since last call to this api.) */
1673 GetEnhMetaFileBits(hClipObj, cb, (LPBYTE)(pClip + 1));
1674 }
1675 break;
1676#else
1677 DebugAssertFailed(("metafile support not enabled"));
1678 return NULL;
1679#endif
1680 }
1681
1682 /*
1683 * The Owner display, the data must be NULL.
1684 */
1685 case CF_OWNERDISPLAY:
1686 {
1687 flPMData = OSLIB_CFI_OWNERDISPLAY | OSLIB_CFI_HANDLE;
1688 if (hClipObj)
1689 {
1690 SetLastError(ERROR_INVALID_PARAMETER); /** @todo check this last error */
1691 dprintf(("USER32: SetClipboardData: returns NULL (owner display data)\n"));
1692 return NULL;
1693 }
1694 break;
1695 }
1696
1697 /*
1698 * Allocate shared data.
1699 */
1700 case CF_TEXT:
1701 case CF_DSPTEXT:
1702 /* these are shared with OS/2 and shall have no header */
1703 fHeader = FALSE;
1704 /* fallthru */
1705 case CF_UNICODETEXT:
1706 case CF_OEMTEXT:
1707 case CF_LOCALE:
1708 case CF_DIB:
1709 case CF_DIBV5:
1710 case CF_HDROP:
1711 case CF_SYLK:
1712 case CF_DIF:
1713 case CF_TIFF:
1714 case CF_PENDATA:
1715 case CF_RIFF:
1716 case CF_WAVE:
1717 flPMData = OSLIB_CFI_POINTER;
1718 /* fall thru */
1719 default:
1720 if (uFormat >= CF_GDIOBJFIRST && uFormat <= CF_GDIOBJFIRST)
1721 {
1722 DebugAssertFailed(("CF_GDIOBJ* is not implemented!!!\n"));
1723 SetLastError(ERROR_GEN_FAILURE);
1724 dprintf(("USER32: SetClipboardData: returns NULL (gdiobj)\n"));
1725 return NULL;
1726 }
1727
1728 /*
1729 * We assume the rest is global handles, if not we'll check treat
1730 * them as handles we don't care to much about.
1731 */
1732 if (hClipObj)
1733 {
1734 PVOID pv = GlobalLock(hClipObj);
1735 if (pv)
1736 {
1737 /*
1738 * Global memory object.
1739 * Duplicate it and put hClipObj in the cache for delayed deletion.
1740 */
1741 DWORD cb = GlobalSize(hClipObj);
1742 ulPMData = (ULONG)clipboardAllocPMBuffer(cb + (fHeader ? sizeof(CLIPHEADER) : 0));
1743 if (!ulPMData)
1744 {
1745 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1746 GlobalUnlock(hClipObj);
1747 dprintf(("USER32: SetClipboardData: returns NULL (shared alloc failed)\n"));
1748 return NULL;
1749 }
1750 if (fHeader)
1751 {
1752 PCLIPHEADER pClip = (PCLIPHEADER)(void*)ulPMData;
1753 memcpy(pClip->achMagic, CLIPHEADER_MAGIC, sizeof(CLIPHEADER_MAGIC));
1754 pClip->cbData = cb;
1755 pClip->uFormat = uFormat;
1756 memcpy((void*)(ulPMData + sizeof(CLIPHEADER)), pv, cb);
1757 }
1758 else
1759 memcpy((void*)ulPMData, pv, cb);
1760 GlobalUnlock(hClipObj);
1761 flPMData = OSLIB_CFI_POINTER;
1762
1763 /* Allocate a cache node. */
1764 if (!clipboardCacheAllocGlobalMem(uFormat, hClipObj, &pLocalClip))
1765 DebugAssertFailed(("out of memory"));
1766 }
1767 else
1768 { /*
1769 * Handle of some other kind?
1770 * Check if it's supposed to be a pointer.
1771 */
1772 if (flPMData)
1773 { /* it's a predefined format which is supposed to be a global memory handle. */
1774 SetLastError(ERROR_INVALID_PARAMETER); /** @todo check this last error */
1775 DebugAssertFailed(("expected GlobalAlloc handle, got %#x!! format=%d (%s)\n",
1776 hClipObj, uFormat, dbgGetFormatName(uFormat))); /* (for application debugging.) */
1777 dprintf(("USER32: SetClipboardData: returns NULL (bad global handle)\n"));
1778 return NULL;
1779 }
1780
1781 /* some kind of handle, this might not work to well... */
1782 flPMData = OSLIB_CFI_HANDLE;
1783 dprintf(("USER32: SetClipboardData: Warning: format %d data %#x is not a Global memory handle!!!\n",
1784 uFormat, hClipObj));
1785 }
1786 }
1787 else
1788 {
1789 /*
1790 * To be rendered.
1791 */
1792 if (!flPMData)
1793 flPMData = OSLIB_CFI_POINTER; /* must be set to something, and pointer is a safe bet. */
1794 }
1795 break;
1796 }
1797
1798 /*
1799 * Put it onto the PM clipboard.
1800 */
1801 dprintf2(("calling OSLibWinSetClipbrdData(%#x, %#x, %d, %#x)\n", GetThreadHAB(), ulPMData, ulPMFormat, flPMData));
1802 if (!OSLibWinSetClipbrdData(GetThreadHAB(), ulPMData, ulPMFormat, flPMData))
1803 {
1804 /*
1805 * Failed!
1806 */
1807 if ((OSLibWinGetLastError() & 0xffff) == OSLIB_PMERR_CALL_FROM_WRONG_THREAD)
1808 SetLastError(ERROR_CLIPBOARD_NOT_OPEN);
1809 else
1810 DebugAssertFailed(("OSLibWinSetClipbrdData(%#x, %#x, %d, %#x) failed last error=%d\n",
1811 GetThreadHAB(), ulPMData, ulPMFormat, flPMData, OSLibWinGetLastError()));
1812
1813 /* cleanup */
1814 if ((flPMData & OSLIB_CFI_POINTER) && ulPMData)
1815 OSLibDosFreeMem((void*)ulPMData);
1816 else
1817 switch (uFormat)
1818 {
1819 case CF_BITMAP:
1820 case CF_DSPBITMAP:
1821 OSLibClipboardPMBitmapDelete(ulPMData);
1822 break;
1823 case CF_PALETTE:
1824 OSLibClipboardPMPaletteDelete(ulPMData);
1825 break;
1826 }
1827
1828 if (pLocalClip)
1829 free(pLocalClip); /* Do not free the data suplied! */
1830
1831 dprintf(("USER32: SetClipboardData: returns NULL (set clipboard failed)\n"));
1832 return NULL;
1833 }
1834
1835 /*
1836 * Success!
1837 */
1838 /* update globals */
1839 gfClipboardChanged = TRUE;
1840 switch (uFormat)
1841 {
1842 case CF_TEXT:
1843 case CF_OEMTEXT:
1844 case CF_UNICODETEXT:
1845 gfClipboardChangedText = TRUE;
1846 break;
1847 }
1848
1849 /* insert node into cache if required. */
1850 if (pLocalClip)
1851 hClipObj = clipboardCacheInsertNode(pLocalClip);
1852
1853 dprintf(("USER32: SetClipboardData: returns %#x\n", hClipObj));
1854 return hClipObj;
1855}
1856
1857
1858/**
1859 * Gets a specific form of the clipboard if it's there.
1860 *
1861 * @returns handle to clipboard data on success.
1862 * @returns NULL on failure. Last error may be set, depends on the failure.
1863 * @param uFormat The clipboard format to get off the clipboard.
1864 * @status partially implemented.
1865 * @author knut st. osmundsen <bird-srcspam@anduin.net>
1866 * @remark we don't like metafiles at the present.
1867 * @remark we never return the same hMem for the same data, this is mentioned as a @todo in the code.
1868 */
1869HANDLE WIN32API GetClipboardData(UINT uFormat)
1870{
1871 dprintf(("USER32: GetClipboardData: uFormat=%u (%s)\n", uFormat, dbgGetFormatName(uFormat)));
1872
1873 /*
1874 * Validate that the thread have opened the clipboard.
1875 */
1876 if (!clipboardIsRWOwner())
1877 {
1878 SetLastError(ERROR_CLIPBOARD_NOT_OPEN);
1879 dprintf(("USER32: GetClipboardData: returns NULL (no openclipboard)\n"));
1880 return NULL;
1881 }
1882
1883 /*
1884 * Validate and translate the format number.
1885 */
1886 ULONG ulPMFormat = clipboardOdinToPMFormat(uFormat);
1887 DebugAssert(!uFormat || ulPMFormat > 0, ("failed to convert odin format %d to PM!!!\n", uFormat));
1888 if (ulPMFormat == 0)
1889 {
1890 //no last error?
1891 dprintf(("USER32: GetClipboardData: returns NULL (invalid format!!!)\n"));
1892 return NULL;
1893 }
1894
1895 /*
1896 * We need to synthesize formats in case OS/2 were the one
1897 * which put stuff on the clipboard.
1898 */
1899 if (!gfClipboardChanged)
1900 clipboardSynthesize(gfClipboardChangedText);
1901
1902 /*
1903 * Get the data.
1904 */
1905 HANDLE hab = GetThreadHAB();
1906 ULONG ulPMInfo;
1907 if (!OSLibWinQueryClipbrdFmtInfo(hab, ulPMFormat, &ulPMInfo))
1908 {
1909 //no last error?
1910 dprintf(("USER32: GetClipboardData: returns NULL (format not present)\n"));
1911 return NULL;
1912 }
1913 ULONG ulPMData = OSLibWinQueryClipbrdData(hab, ulPMFormat);
1914 if (!ulPMData)
1915 {
1916 //no last error?
1917 dprintf(("USER32: GetClipboardData: returns NULL (format not present)\n"));
1918 return NULL;
1919 }
1920
1921 /*
1922 * Allocate local copies of the data like Odin expects.
1923 *
1924 * In this process we'll synthesize formats and convert
1925 * from OS/2 PM formats to Odin formats.
1926 */
1927 /* dummy handle? */
1928 if ( (ulPMInfo & (OSLIB_CFI_HANDLE | OSLIB_CFI_POINTER | OSLIB_CFI_OWNERDISPLAY | OSLIB_CFI_OWNERFREE))
1929 == OSLIB_CFI_HANDLE
1930 && ulPMData == DUMMY_HANDLE)
1931 { /* synthesized */
1932 /** @todo check if we've done this operation on this data before. */
1933 HANDLE hRet;
1934 switch (uFormat)
1935 {
1936 case CF_TEXT:
1937 case CF_UNICODETEXT:
1938 case CF_OEMTEXT:
1939 hRet = clipboardSynthesizeText(uFormat);
1940 break;
1941
1942 case CF_LOCALE:
1943 hRet = clipboardSynthesizeLocale(uFormat);
1944 break;
1945
1946 case CF_BITMAP:
1947 hRet = clipboardSynthesizeBitmap(uFormat);
1948 break;
1949
1950 case CF_DIB:
1951 case CF_DIBV5:
1952 hRet = clipboardSynthesizeDIB(uFormat);
1953 break;
1954
1955 #if 0 // not implemented yet.
1956 case CF_PALETTE:
1957 hRet = clipboardSynthesizePalette(uFormat);
1958 break;
1959
1960 case CF_METAFILEPICT:
1961 hRet = clipboardSynthesizeMetaFile(uFormat);
1962 break;
1963 case CF_ENHMETAFILE:
1964 hRet = clipboardSynthesizeEnhMetaFile(uFormat);
1965 break;
1966 #endif
1967
1968 default:
1969 DebugAssertFailed(("Format %d doesn't do dummy handles!\n", uFormat));
1970 dprintf(("USER32: GetClipboardData: returns NULL (internal error!!!)\n"));
1971 return NULL;
1972 }
1973 dprintf(("USER32: GetClipboardData: returns %#x (synthesized)\n", hRet));
1974 return hRet;
1975 }
1976 else if (ulPMInfo & OSLIB_CFI_POINTER)
1977 { /* pointers: text */
1978 /* Sanity check. */
1979 switch (uFormat)
1980 {
1981 case CF_BITMAP:
1982 case CF_DSPBITMAP:
1983 case CF_PALETTE:
1984 dprintf(("USER32: GetClipboardData: return NULL (format/data mismatch)\n"));
1985 return NULL;
1986
1987 case CF_ENHMETAFILE:
1988 case CF_DSPENHMETAFILE:
1989 case CF_METAFILEPICT:
1990 case CF_DSPMETAFILEPICT:
1991 DebugAssertFailed(("Metafile support isn't enabled\n"));
1992 return NULL;
1993 }
1994
1995 /** @todo check if we've done this operation on this data before. */
1996
1997 /*
1998 * Duplicate the data raw in a GlobalAlloc'ed block local to the calling process.
1999 */
2000 /* Figure out the size of the data */
2001 ULONG cbOdin;
2002 void *pvOdin;
2003 if (uFormat != CF_TEXT && uFormat != CF_BITMAP && uFormat != CF_PALETTE
2004 && !memcmp(((PCLIPHEADER)ulPMData)->achMagic, CLIPHEADER_MAGIC, sizeof(CLIPHEADER_MAGIC)))
2005 { /* Have Odin header */
2006 PCLIPHEADER pClip = (PCLIPHEADER)ulPMData;
2007 DebugAssert(pClip->uFormat == uFormat, ("Format mismatch %d != %d\n", pClip->uFormat, uFormat));
2008 cbOdin = pClip->cbData;
2009 pvOdin = (void*)(pClip + 1);
2010 }
2011 else
2012 {
2013 DebugAssert(uFormat == CF_TEXT || uFormat == CF_BITMAP || uFormat == CF_PALETTE,
2014 ("%d should have a header!!!\n", uFormat));
2015 pvOdin = (void*)ulPMData;
2016 ULONG cb = clipboardGetPMDataSize(pvOdin);
2017 if (!cb)
2018 {
2019 dprintf(("USER32: GetClipboardData: return NULL (cannot determin size of data)\n"));
2020 return NULL;
2021 }
2022
2023 /* find the size of the odin data. */
2024 cbOdin = cb;
2025 switch (uFormat)
2026 {
2027 case CF_TEXT:
2028 cbOdin = clipboardTextCalcSize(pvOdin, cb);
2029 break;
2030 }
2031 }
2032
2033 /* allocate object. */
2034 PCLIPLOCALDATA pLocalClip;
2035 HANDLE hMem = clipboardCacheAllocGlobalDup(uFormat, pvOdin, cbOdin, &pLocalClip);
2036 if (!hMem)
2037 {
2038 dprintf(("USER32: GetClipboardData: returns NULL (GlobalAlloc(,%d) failed)\n", cbOdin));
2039 return NULL;
2040 }
2041
2042 /* insert cache object. */
2043 hMem = clipboardCacheInsertNode(pLocalClip);
2044
2045 dprintf(("USER32: GetClipboardData: return %#x (%d bytes)\n", hMem, cbOdin));
2046 return hMem;
2047 }
2048 else if (ulPMInfo & OSLIB_CFI_HANDLE)
2049 { /* handles: palette or bitmap */
2050 HANDLE hGDI;
2051 switch (uFormat)
2052 {
2053 case CF_BITMAP:
2054 case CF_DSPBITMAP:
2055 hGDI = O32_CreateBitmapFromPMHandle((HBITMAP)ulPMData);
2056 break;
2057
2058 case CF_PALETTE:
2059 hGDI = O32_CreateBitmapFromPMHandle((HPALETTE)ulPMData);
2060 break;
2061
2062 /** @todo make cases for the other which are defined as handles. */
2063 /* (for now we assume that everything else is Odin handles.) */
2064 default:
2065 dprintf(("USER32: GetClipboardData: returns NULL (funny stuff on clipboard)\n"));
2066 return (HANDLE)ulPMData;
2067 }
2068
2069 /* allocate and insert cache node. */
2070 PCLIPLOCALDATA pLocalClip;
2071 if (clipboardCacheAllocGDI(uFormat, hGDI, &pLocalClip))
2072 hGDI = clipboardCacheInsertNode(pLocalClip);
2073
2074 dprintf(("USER32: GetClipboardData: returns %#x (translated OS/2 handle)\n", hGDI));
2075 return hGDI;
2076 }
2077 else
2078 {
2079 DebugAssertFailed(("Something is on the clipboard without any understandable attributes!! ulInfo=%#x ulPMData=%#x\n",
2080 ulPMInfo, ulPMData));
2081 dprintf(("USER32: GetClipboardData: returns NULL (funny stuff on clipboard)\n"));
2082 return NULL;
2083 }
2084}
2085
2086
2087/**
2088 * Enumerate clipboard formats.
2089 *
2090 * Must be RW owner of clipboard (i.e. OpenClipboard()).
2091 *
2092 * @returns next clipboard format.
2093 * @returns 0 if no more formats in the clipboard.
2094 * @param uFormat Current format. Use 0 for the starting
2095 * the enumeration.
2096 * @status completely implemented.
2097 * @author knut st. osmundsen <bird-srcspam@anduin.net>
2098 */
2099UINT WIN32API EnumClipboardFormats(UINT uFormat)
2100{
2101 dprintf(("USER32: EnumClipboardFormats: uFormat=%d (%s)\n", uFormat,
2102 uFormat ? dbgGetFormatName(uFormat) : "start enum"));
2103
2104 /*
2105 * Validate that the thread have opened the clipboard.
2106 */
2107 if (!clipboardIsRWOwner())
2108 {
2109 SetLastError(ERROR_CLIPBOARD_NOT_OPEN);
2110 dprintf(("USER32: EnumClipboardFormats: returns 0 (no openclipboard)\n"));
2111 return 0;
2112 }
2113
2114 UINT rc = clipboardEnumClipboardFormats(uFormat);
2115 dprintf(("USER32: EnumClipboardFormats: returns %d\n"));
2116 return rc;
2117}
2118
2119
2120/**
2121 * Internal worker for EnumClipboardFormats.
2122 * Also used by CountClipboardFormats();
2123 *
2124 * @returns next clipboard format.
2125 * @returns 0 if no more formats in the clipboard.
2126 * @param uFormat Current format. Use 0 for the starting
2127 * the enumeration.
2128 * @status completely implemented.
2129 * @author knut st. osmundsen <bird-srcspam@anduin.net>
2130 */
2131UINT clipboardEnumClipboardFormats(UINT uFormat)
2132{
2133 dprintf(("USER32: clipboardEnumClipboardFormats: uFormat=%d (%s)\n", uFormat,
2134 uFormat ? dbgGetFormatName(uFormat) : "start enum"));
2135
2136 /*
2137 * Validate/translate input.
2138 */
2139 ULONG ulPMFormat = 0;
2140 if (uFormat)
2141 {
2142 ulPMFormat = clipboardOdinToPMFormat(uFormat);
2143 if (!ulPMFormat)
2144 {
2145 dprintf(("USER32: clipboardEnumClipboardFormats: invalid uFormat(=%u)!!\n", uFormat));
2146 return 0;
2147 }
2148 }
2149
2150 /*
2151 * Enumerate next OS/2 format.
2152 */
2153 HANDLE hab = GetThreadHAB();
2154 while ((ulPMFormat = OSLibWinEnumClipbrdFmts(GetThreadHAB(), ulPMFormat)) != 0)
2155 {
2156 UINT uNextFormat = clipboardPMToOdinFormat(ulPMFormat);
2157 if (uNextFormat)
2158 {
2159 dprintf(("USER32: clipboardEnumClipboardFormats: returning %u (%s)\n", uNextFormat, dbgGetFormatName(uNextFormat)));
2160 return uNextFormat;
2161 }
2162 dprintf2(("USER32: clipboardEnumClipboardFormats: skipping OS/2 only format %lu\n", ulPMFormat));
2163 }
2164
2165 /*
2166 * Since we cannot know what non Odin applications are doing,
2167 * we will have to check for synthesized formats here.
2168 *
2169 * We're not doing this if we're the clipboard owner and have changed
2170 * the clipboard in any way. This is to not synthesize stuff to early
2171 * compared to W2K. See GetClipboardFormat.
2172 */
2173 if (uFormat && (!clipboardIsRWOwner() || !gfClipboardChanged))
2174 {
2175 static UINT auSeq[] = { CF_TEXT, CF_UNICODETEXT, CF_OEMTEXT, CF_DIB, CF_DIBV5, CF_BITMAP, 0 }; /** @todo complete and check this. */
2176 ULONG flInfo;
2177
2178 /* find starting index */
2179 int i = 0;
2180 if (!clipboardIsAvailable(uFormat))
2181 {
2182 for (i = 0; auSeq[i]; i++)
2183 if (auSeq[i] == uFormat)
2184 {
2185 i++;
2186 break;
2187 }
2188 }
2189
2190 /*
2191 * Find the next synthesized format.
2192 */
2193 while ((uFormat = auSeq[i]) != 0)
2194 {
2195 if (clipboardShouldBeSynthesized(uFormat))
2196 { /* not there, potentially synthesized format. */
2197 dprintf(("USER32: clipboardEnumClipboardFormats: returning %u (%s)\n", uFormat, dbgGetFormatName(uFormat)));
2198 return uFormat;
2199 }
2200 /* next */
2201 i++;
2202 }
2203
2204 }
2205
2206 dprintf(("USER32: clipboardEnumClipboardFormats: returning 0\n"));
2207 return 0;
2208}
2209
2210
2211
2212/**
2213 * Closes the clipboard.
2214 *
2215 * @returns Success indicator.
2216 * @status completely implemented.
2217 * @author knut st. osmundsen <bird-srcspam@anduin.net>
2218 */
2219BOOL WIN32API CloseClipboard(void)
2220{
2221 dprintf(("USER32: CloseClipboard"));
2222
2223 /*
2224 * Check that we're owning the clipboard.
2225 */
2226 if (!clipboardIsRWOwner())
2227 {
2228 SetLastError(ERROR_CLIPBOARD_NOT_OPEN);
2229 dprintf(("USER32: CloseClipboard returns FALSE (clipboard not open!!)\n"));
2230 return FALSE;
2231 }
2232
2233 HAB hab = GetThreadHAB();
2234
2235 /*
2236 * Synthesize formats.
2237 */
2238 if (gfClipboardChanged)
2239 clipboardSynthesize(gfClipboardChangedText);
2240
2241 /*
2242 * Actually close it.
2243 */
2244 if (gtidOpenClipboardThreadId == GetCurrentThreadId()) /* paranoia */
2245 gtidOpenClipboardThreadId = 0;
2246 BOOL fRc = OSLibWinCloseClipbrd(hab);
2247 DebugAssert(fRc, ("WinCloseClipbrd failed!!! lasterr=%#x\n", OSLibWinGetLastError()));
2248 dprintf(("USER32: CloseClipboard: returning %s\n", fRc ? "TRUE" : "FALSE"));
2249 return fRc;
2250}
2251
2252
2253/**
2254 * Makes dummies for synthesized formats.
2255 *
2256 * This is called by CloseClipboard() and GetClipboardData(). The latter
2257 * because Odin32 might not have been the one to put data on the clipboard.
2258 */
2259void clipboardSynthesize(BOOL fHaveAddedText)
2260{
2261 dprintf2(("USER32: clipboardSynthesize: fHaveAddedText=%d\n", fHaveAddedText));
2262 /* text */
2263 BOOL fCF_OEMTEXT = clipboardIsAvailable(CF_OEMTEXT);
2264 BOOL fCF_UNICODETEXT = clipboardIsAvailable(CF_UNICODETEXT);
2265 BOOL fCF_TEXT = clipboardIsAvailable(CF_TEXT);
2266 if (fCF_TEXT || fCF_UNICODETEXT || fCF_OEMTEXT)
2267 {
2268 /*
2269 * Add the CF_LOCALE if we have modified the clipboard.
2270 */
2271 if (!clipboardIsAvailable(CF_LOCALE))
2272 {
2273 if (!fHaveAddedText)
2274 clipboardAddPMDummy(CF_LOCALE);
2275 else
2276 {
2277 LCID lcid = GetThreadLocale();
2278 clipboardAddPMHeader(CF_LOCALE, &lcid, sizeof(lcid));
2279 }
2280 }
2281
2282 /*
2283 * Add dummies.
2284 */
2285 if (!fCF_TEXT)
2286 {
2287 /* CT_TEXT must be synthesized so PM can see the text. */
2288 HANDLE hMem = clipboardSynthesizeText(CF_TEXT);
2289 if (hMem)
2290 {
2291 void *pv = GlobalLock(hMem);
2292 clipboardAddPM(CF_TEXT, pv, GlobalSize(hMem));
2293 GlobalUnlock(hMem);
2294 }
2295 }
2296 if (!fCF_UNICODETEXT)
2297 clipboardAddPMDummy(CF_UNICODETEXT);
2298 if (!fCF_OEMTEXT)
2299 clipboardAddPMDummy(CF_OEMTEXT);
2300 }
2301 else
2302 {
2303 /* DIBs */
2304 BOOL fCF_DIBV5 = clipboardIsAvailable(CF_DIBV5);
2305 BOOL fCF_DIB = clipboardIsAvailable(CF_DIB);
2306 BOOL fCF_BITMAP = clipboardIsAvailable(CF_BITMAP);
2307 if (fCF_BITMAP || fCF_DIB || fCF_DIBV5)
2308 {
2309 /*
2310 * Add dummies.
2311 */
2312 if (!fCF_BITMAP)
2313 { /* CT_BITMAP must be synthesized so PM can understand it. */
2314 HANDLE hbm = clipboardSynthesizeBitmap(CF_BITMAP);
2315 if (hbm)
2316 {
2317 if (!SetClipboardData(CF_BITMAP, hbm))
2318 DebugAssertFailed(("SetClipboardData for synthesized bitmap %#x failed!\n", hbm));
2319 }
2320 }
2321 if (!fCF_DIB)
2322 clipboardAddPMDummy(CF_DIB);
2323 if (!fCF_DIBV5)
2324 clipboardAddPMDummy(CF_DIBV5);
2325 }
2326 else
2327 {
2328 /** @todo metafiles and palettes */
2329 }
2330 }
2331
2332}
2333
2334
2335
2336/**
2337 * Checks whether or not a given format will be synthesized by GetClipboardData
2338 * in the current clipboard state.
2339 *
2340 * @returns TRUE if it will be synthesized, FALSE if not.
2341 * @param uFormat Odin format number
2342 */
2343BOOL clipboardShouldBeSynthesized(UINT uFormat)
2344{
2345 /* Should be, that means to be done in GetClipboardData. */
2346 if (clipboardIsAvailable(uFormat))
2347 return FALSE;
2348
2349 switch (uFormat)
2350 {
2351 case CF_TEXT:
2352 return clipboardIsAvailable(CF_OEMTEXT)
2353 || clipboardIsAvailable(CF_UNICODETEXT);
2354 case CF_OEMTEXT:
2355 return clipboardIsAvailable(CF_TEXT)
2356 || clipboardIsAvailable(CF_UNICODETEXT);
2357 case CF_UNICODETEXT:
2358 return clipboardIsAvailable(CF_TEXT)
2359 || clipboardIsAvailable(CF_OEMTEXT);
2360
2361 case CF_LOCALE:
2362 return clipboardIsAvailable(CF_TEXT)
2363 || clipboardIsAvailable(CF_OEMTEXT)
2364 || clipboardIsAvailable(CF_UNICODETEXT);
2365
2366 case CF_BITMAP:
2367 return clipboardIsAvailable(CF_DIB)
2368 || clipboardIsAvailable(CF_DIBV5);
2369 case CF_DIB:
2370 return clipboardIsAvailable(CF_BITMAP)
2371 || clipboardIsAvailable(CF_DIBV5);
2372 case CF_DIBV5:
2373 return clipboardIsAvailable(CF_BITMAP)
2374 || clipboardIsAvailable(CF_DIB);
2375
2376 #if 0
2377 case CF_PALETTE:
2378 return clipboardIsAvailable(CF_BITMAP)
2379 || clipboardIsAvailable(CF_DIB)
2380 || clipboardIsAvailable(CF_DIBV5);
2381 /* metafiles */
2382 #endif
2383
2384 default:
2385 return FALSE;
2386 }
2387}
2388
2389
2390/**
2391 * Synthesizes the given text format from the available text format
2392 * on the clipboard.
2393 *
2394 * @returns Handle to global memory object containing the synthesized text.
2395 * @returns NULL on failure.
2396 * @param uFormat Format to synthesize.
2397 */
2398HANDLE clipboardSynthesizeText(UINT uFormat)
2399{
2400 dprintf2(("USER32: clipboardSynthesizeText: uFormat=%d (%s)\n", uFormat, dbgGetFormatName(uFormat)));
2401 DebugAssert(uFormat == CF_TEXT || uFormat == CF_OEMTEXT || uFormat == CF_UNICODETEXT,
2402 ("invalid format %d\n", uFormat));
2403
2404 /*
2405 * Check what's available.
2406 */
2407 BOOL fCF_TEXT = clipboardIsAvailableReal(CF_TEXT);
2408 BOOL fCF_UNICODETEXT= clipboardIsAvailableReal(CF_UNICODETEXT);
2409 BOOL fCF_OEMTEXT = clipboardIsAvailableReal(CF_OEMTEXT);
2410 DebugAssert(fCF_TEXT || fCF_UNICODETEXT || fCF_OEMTEXT, ("no text is available!!!"));
2411
2412 /*
2413 * Figure out format to convert from.
2414 */
2415 UINT uSrcFormat;
2416 switch (uFormat)
2417 {
2418 case CF_TEXT:
2419 uSrcFormat = fCF_UNICODETEXT ? CF_UNICODETEXT : fCF_OEMTEXT ? CF_OEMTEXT : 0;
2420 break;
2421 case CF_OEMTEXT:
2422 uSrcFormat = fCF_UNICODETEXT ? CF_UNICODETEXT : fCF_TEXT ? CF_TEXT : 0;
2423 break;
2424 case CF_UNICODETEXT:
2425 uSrcFormat = fCF_TEXT ? CF_TEXT : fCF_OEMTEXT ? CF_OEMTEXT : 0;
2426 break;
2427 }
2428 dprintf2(("USER32: clipboardSynthesizeText: uSrcFormat=%d (%s)\n", uSrcFormat, dbgGetFormatName(uSrcFormat)));
2429
2430 /*
2431 * Get the data.
2432 */
2433 HANDLE hRet = NULL;
2434 HANDLE hMem = GetClipboardData(uSrcFormat);
2435 if (hMem)
2436 {
2437 const void *pv = GlobalLock(hMem);
2438 if (pv)
2439 {
2440 DWORD cb = GlobalSize(hMem);
2441
2442 /*
2443 * determin size of converted text
2444 */
2445 unsigned cbRet;
2446 unsigned uCp;
2447 switch (uSrcFormat)
2448 {
2449 case CF_TEXT:
2450 case CF_OEMTEXT:
2451 cbRet = strlen((char*)pv) + 1; /* OEM better not bet multibyte/dbcs. */
2452 if (uFormat == CF_UNICODETEXT)
2453 cbRet *= sizeof(WCHAR);
2454 break;
2455 case CF_UNICODETEXT:
2456 uCp = clipboardGetCodepage(uFormat == CF_TEXT ? LOCALE_IDEFAULTANSICODEPAGE : LOCALE_IDEFAULTCODEPAGE);
2457 cbRet = WideCharToMultiByte(uCp, 0, (LPCWSTR)pv, cb / sizeof(WCHAR), NULL, 0, NULL, NULL);
2458 break;
2459 }
2460
2461 /*
2462 * Allocate memory.
2463 */
2464 PCLIPLOCALDATA pLocalClip;
2465 hRet = clipboardCacheAllocGlobalAlloc(uFormat, cbRet, &pLocalClip);
2466 if (hRet)
2467 {
2468 void * pvRet = GlobalLock(hRet);
2469
2470 /*
2471 * Do the convertion.
2472 */
2473 switch (uFormat)
2474 {
2475 case CF_TEXT:
2476 switch (uSrcFormat)
2477 {
2478 case CF_OEMTEXT:
2479 OemToCharBuffA((LPCSTR)pv, (LPSTR)pvRet, cbRet);
2480 break;
2481 case CF_UNICODETEXT:
2482 WideCharToMultiByte(uCp, 0, (LPCWSTR)pv, cb / sizeof(WCHAR), (LPSTR)pvRet, cb, NULL, NULL);
2483 break;
2484 }
2485 break;
2486
2487 case CF_OEMTEXT:
2488 switch (uSrcFormat)
2489 {
2490 case CF_TEXT:
2491 CharToOemBuffA((LPCSTR)pv, (LPSTR)pvRet, cbRet);
2492 break;
2493 case CF_UNICODETEXT:
2494 WideCharToMultiByte(uCp, 0, (LPCWSTR)pv, cb / sizeof(WCHAR), (LPSTR)pvRet, cb, NULL, NULL);
2495 break;
2496 }
2497 break;
2498
2499 case CF_UNICODETEXT:
2500 uCp = clipboardGetCodepage(uFormat == CF_TEXT ? LOCALE_IDEFAULTANSICODEPAGE : LOCALE_IDEFAULTCODEPAGE);
2501 MultiByteToWideChar(uCp, MB_PRECOMPOSED, (LPCSTR)pv, cb, (LPWSTR)pvRet, cbRet / sizeof(WCHAR));
2502 break;
2503 }
2504 GlobalUnlock(hRet);
2505
2506 hRet = clipboardCacheInsertNode(pLocalClip);
2507 }
2508 GlobalUnlock(hMem);
2509 }
2510 else
2511 DebugAssertFailed(("Failed to lock object %#x format %d!!!\n", hMem, uSrcFormat));
2512 }
2513 else
2514 DebugAssertFailed(("now why isn't %d on the clipboard????\n", uSrcFormat));
2515
2516 return hRet;
2517}
2518
2519
2520/**
2521 * Synthesizes a locale structure.
2522 *
2523 * @returns Handle to global memory object containing the synthesized locale.
2524 * @returns NULL on failure.
2525 * @param uFormat Format to synthesize.
2526 */
2527HANDLE clipboardSynthesizeLocale(UINT uFormat)
2528{
2529 dprintf2(("USER32: clipboardSynthesizeLocale: uFormat=%d (%s)\n", uFormat, dbgGetFormatName(uFormat)));
2530 DebugAssert(uFormat == CF_LOCALE, ("invalid format %d\n", uFormat));
2531
2532 /*
2533 * Guess an appropriate Locale.
2534 */
2535 LCID lcid = GetSystemDefaultLCID();
2536
2537 /*
2538 * Allocate a block in the 'cache'.
2539 */
2540 PCLIPLOCALDATA pLocalClip;
2541 HANDLE hMem = clipboardCacheAllocGlobalDup(uFormat, &lcid, sizeof(LCID), &pLocalClip);
2542 if (!hMem)
2543 return NULL;
2544
2545 /* insert */
2546 hMem = clipboardCacheInsertNode(pLocalClip);
2547
2548 dprintf2(("USER32: clipboardSynthesizeLocale: returning %#x (lcid=%#x)\n", hMem, lcid));
2549 return hMem;
2550}
2551
2552
2553/**
2554 * Synthesizes a bitmap from the avilable DIB format on the clipboard
2555 *
2556 * @returns Handle to GDI bitmap.
2557 * @returns NULL on failure.
2558 * @param uFormat Format to synthesize. (CF_BITMAP)
2559 */
2560HANDLE clipboardSynthesizeBitmap(UINT uFormat)
2561{
2562 dprintf2(("USER32: clipboardSynthesizeBitmap: uFormat=%d (%s)\n", uFormat, dbgGetFormatName(uFormat)));
2563 DebugAssert(uFormat == CF_BITMAP, ("invalid format %d\n", uFormat));
2564
2565 /*
2566 * Find DIB format to convert from.
2567 */
2568 UINT uSrcFormat = CF_DIB;
2569 if (!clipboardIsAvailableReal(uSrcFormat))
2570 {
2571 uSrcFormat = CF_DIBV5;
2572 if (!clipboardIsAvailableReal(uSrcFormat))
2573 {
2574 DebugAssertFailed(("no DIB data avilable!\n"));
2575 return NULL;
2576 }
2577 }
2578 dprintf2(("USER32: clipboardSynthesizeBitmap: uSrcFormat=%d (%s)\n", uSrcFormat, dbgGetFormatName(uSrcFormat)));
2579
2580 /*
2581 * Get the data.
2582 */
2583 PCLIPHEADER pClip = (PCLIPHEADER)OSLibWinQueryClipbrdData(GetThreadHAB(), clipboardOdinToPMFormat(uSrcFormat));
2584 if ( !pClip
2585 || pClip == (PCLIPHEADER)DUMMY_HANDLE
2586 || memcmp(pClip->achMagic, CLIPHEADER_MAGIC, sizeof(CLIPHEADER_MAGIC)))
2587 {
2588 DebugAssertFailed(("invalid clipboard data for format %d\n", uSrcFormat));
2589 return NULL;
2590 }
2591
2592 /*
2593 * Check the content a little bit.
2594 */
2595 union u
2596 {
2597 PVOID pv;
2598 char * pch;
2599 LPBITMAPINFOHEADER pHdr;
2600 LPBITMAPV5HEADER pHdrV5;
2601 } u = { (void*)(pClip + 1) };
2602 if (u.pHdr->biSize < sizeof(BITMAPCOREHEADER) || u.pHdr->biSize > sizeof(BITMAPV5HEADER))
2603 {
2604 DebugAssertFailed(("invalid clipboard DIB data: biSize=%d\n", u.pHdr->biSize));
2605 return NULL;
2606 }
2607 switch (u.pHdr->biBitCount)
2608 {
2609 case 1:
2610 case 2:
2611 case 4:
2612 case 8:
2613 case 16:
2614 case 24:
2615 case 32:
2616 break;
2617 default:
2618 DebugAssertFailed(("invalid clipboard DIB data: biBitCount=%d\n", u.pHdr->biBitCount));
2619 return NULL;
2620 }
2621 if ( u.pHdrV5->bV5Size == sizeof(BITMAPV5HEADER)
2622 && u.pHdrV5->bV5CSType != LCS_sRGB)
2623 {
2624 DebugAssertFailed(("unexpected clipboard DIBV5 data: bV5CSType=%#x\n", u.pHdrV5->bV5CSType));
2625 return NULL;
2626 }
2627 /* todo more checking. */
2628
2629 /*
2630 * Calc start of bits.
2631 */
2632 void *pvBits = (char*)u.pv + u.pHdr->biSize;
2633 if (u.pHdr->biBitCount <= 8)
2634 pvBits = (char*)pvBits + sizeof(RGBQUAD) * (1 << u.pHdr->biBitCount);
2635
2636 /*
2637 * Create the bitmap.
2638 */
2639 HBITMAP hbm;
2640 HDC hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
2641 if (hdc)
2642 {
2643 hbm = CreateDIBitmap(hdc, u.pHdr, CBM_INIT, pvBits, (PBITMAPINFO)u.pHdr, DIB_RGB_COLORS);
2644 if (hbm)
2645 {
2646 /* allocate and insert it into the cache. */
2647 PCLIPLOCALDATA pLocalClip;
2648 if (clipboardCacheAllocGDI(uFormat, hbm, &pLocalClip))
2649 hbm = clipboardCacheInsertNode(pLocalClip);
2650 dprintf(("synthesized bitmap %#x\n", hbm));
2651 }
2652 else
2653 DebugAssertFailed(("CreateBitmapIndirect failed\n"));
2654 DeleteDC(hdc);
2655 }
2656
2657 return hbm;
2658}
2659
2660/**
2661 * Synthesizes the given DIB format from the available DIB or bitmap
2662 * on the clipboard.
2663 *
2664 * @returns Handle to global memory object containing the synthesized DIB.
2665 * @returns NULL on failure.
2666 * @param uFormat Format to synthesize. (CF_BITMAP)
2667 */
2668HANDLE clipboardSynthesizeDIB(UINT uFormat)
2669{
2670 dprintf2(("USER32: clipboardSynthesizeDIB: uFormat=%d (%s)\n", uFormat, dbgGetFormatName(uFormat)));
2671 OSLIB_BITMAPINFOHEADER2 bih2;
2672 DebugAssert(uFormat == CF_DIB || uFormat == CF_DIBV5, ("invalid format %d\n", uFormat));
2673
2674 /*
2675 * Find convert format and calculate the size of the converted bitmap.
2676 */
2677 UINT uSrcFormat = CF_DIB;
2678 if (!clipboardIsAvailableReal(uSrcFormat))
2679 {
2680 uSrcFormat = CF_DIBV5;
2681 if (!clipboardIsAvailableReal(uSrcFormat))
2682 {
2683 uSrcFormat = CF_BITMAP;
2684 if (!clipboardIsAvailableReal(uSrcFormat))
2685 {
2686 DebugAssertFailed(("no bitmap or DIB available on the clipboard\n"));
2687 return NULL;
2688 }
2689 }
2690 }
2691 dprintf2(("USER32: clipboardSynthesizeDIB: uSrcFormat=%d (%s)\n", uSrcFormat, dbgGetFormatName(uSrcFormat)));
2692
2693 /*
2694 * Get the data.
2695 */
2696 void *pv = (void*)OSLibWinQueryClipbrdData(GetThreadHAB(), clipboardOdinToPMFormat(uSrcFormat));
2697 if ( !pv
2698 || pv == (void*)DUMMY_HANDLE
2699 || ( uSrcFormat != CF_BITMAP
2700 && memcmp(pv, CLIPHEADER_MAGIC, sizeof(CLIPHEADER_MAGIC))
2701 )
2702 )
2703 {
2704 DebugAssertFailed(("invalid clipboard data for format %d\n", uSrcFormat));
2705 return NULL;
2706 }
2707
2708
2709 /*
2710 * Do the conversion.
2711 */
2712 switch (uSrcFormat)
2713 {
2714 /*
2715 * Convert an OS/2 bitmap to a DIB or DIBV5.
2716 */
2717 case CF_BITMAP:
2718 {
2719 /* We're letting GPI do the major bit of the work actually. */
2720 HBITMAP hbm = O32_CreateBitmapFromPMHandle((HBITMAP)pv);
2721 if (!hbm)
2722 {
2723 DebugAssertFailed(("invalid OS/2 hbitmap %#x on clipboard\n", (unsigned)pv));
2724 return NULL;
2725 }
2726
2727 HANDLE hMem = NULL;
2728 HDC hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
2729 if (hdc)
2730 {
2731 SelectObject(hdc, hbm);
2732
2733 /*
2734 * Figure out the sizes.
2735 */
2736 unsigned cbTrgHeader = uFormat == CF_DIB ? sizeof(BITMAPINFOHEADER) : sizeof(BITMAPV5HEADER);
2737 BITMAPINFOHEADER hdr = {sizeof(BITMAPINFOHEADER), 0};
2738 if (GetDIBits(hdc, hbm, 0, 0, NULL, (PBITMAPINFO)&hdr, DIB_RGB_COLORS))
2739 { /* we've got the header now */
2740 unsigned cbTrgColorTable = 0;
2741 switch (hdr.biBitCount)
2742 {
2743 case 1:
2744 case 2:
2745 case 4:
2746 case 8:
2747 cbTrgColorTable = (1 << hdr.biBitCount) * sizeof(RGBQUAD);
2748 break;
2749 }
2750
2751 unsigned cbTrgBits = hdr.biSizeImage;
2752 if (!cbTrgBits)
2753 {
2754 cbTrgBits = ((hdr.biWidth * hdr.biBitCount + 31) >> 5) << 2;
2755 cbTrgBits *= abs(hdr.biHeight);
2756 }
2757
2758 unsigned cbTotal = cbTrgHeader + cbTrgColorTable + cbTrgBits;
2759
2760 /*
2761 * Allocate a cache object.
2762 */
2763 PCLIPLOCALDATA pLocalClip;
2764 hMem = clipboardCacheAllocGlobalAlloc(uFormat, cbTotal, &pLocalClip);
2765 if (hMem)
2766 {
2767 union u
2768 {
2769 PVOID pv;
2770 char * pch;
2771 LPBITMAPINFOHEADER pHdr;
2772 LPBITMAPV5HEADER pHdrV5;
2773 } uTrg;
2774 uTrg.pv = GlobalLock(hMem);
2775
2776 /*
2777 * Get the bitmap bits and pieces.
2778 */
2779 memcpy(uTrg.pv, &hdr, sizeof(hdr));
2780 if (GetDIBits(hdc, hbm, 0, hdr.biHeight,
2781 uTrg.pch + cbTrgHeader + cbTrgColorTable,
2782 (PBITMAPINFO)uTrg.pv,
2783 DIB_RGB_COLORS))
2784 {
2785 /* adjust the header+color table for CF_DIBV5 */
2786 #ifdef USE_DIBV5
2787 if (uFormat == CF_DIBV5)
2788 {
2789 if (cbTrgColorTable)
2790 memmove(uTrg.pch + sizeof(BITMAPV5HEADER), uTrg.pch + sizeof(hdr), cbTrgColorTable);
2791 memset(uTrg.pch + sizeof(hdr), 0, sizeof(BITMAPV5HEADER) - sizeof(hdr));
2792 uTrg.pHdrV5->bV5Size = sizeof(BITMAPV5HEADER);
2793 uTrg.pHdrV5->bV5CSType = LCS_sRGB;
2794 }
2795 #endif
2796 if (!uTrg.pHdr->biClrImportant)
2797 uTrg.pHdr->biClrImportant = uTrg.pHdr->biClrUsed;
2798
2799 DeleteDC(hdc);
2800 HANDLE hRet = clipboardCacheInsertNode(pLocalClip);
2801 dprintf2(("USER32: clipboardSynthesizeDIB: returning %#x\n", hRet));
2802 return hRet;
2803 }
2804 else
2805 DebugAssertFailed(("GetDIBits failed lasterr=%d\n", GetLastError()));
2806
2807 /* failure */
2808 clipboardCacheDeleteNode(pLocalClip);
2809 }
2810 else
2811 DebugAssertFailed(("GlobalAlloc failed lasterr=%d\n", GetLastError()));
2812 }
2813 else
2814 DebugAssertFailed(("GetDIBits (header) failed lasterr=%d\n", GetLastError()));
2815 DeleteDC(hdc);
2816 }
2817 else
2818 DebugAssertFailed(("CreateDCA failed lasterr=%d\n", GetLastError()));
2819 return NULL;
2820 }
2821
2822 /*
2823 * DIB <-> DIBV5: basically only header adjustments
2824 * (We do not yet support advanced DIBV5 formats.)
2825 */
2826 case CF_DIB:
2827 case CF_DIBV5:
2828 {
2829 union u
2830 {
2831 PVOID pv;
2832 char * pch;
2833 LPBITMAPINFOHEADER pHdr;
2834 LPBITMAPV5HEADER pHdrV5;
2835 } uSrc, uTrg;
2836 uSrc.pv = (char*)pv + sizeof(CLIPHEADER);
2837 unsigned cbSrc = ((PCLIPHEADER)pv)->cbData;
2838
2839 /*
2840 * Validate the bitmap data a little bit.
2841 */
2842 if (uSrc.pHdr->biSize < sizeof(BITMAPCOREHEADER) || uSrc.pHdr->biSize > sizeof(BITMAPV5HEADER))
2843 {
2844 DebugAssertFailed(("Unknown header size %d\n", uSrc.pHdr->biSize));
2845 return NULL;
2846 }
2847 switch (uSrc.pHdr->biBitCount)
2848 {
2849 case 1:
2850 case 2:
2851 case 4:
2852 case 8:
2853 case 16:
2854 case 24:
2855 case 32:
2856 break;
2857 default:
2858 DebugAssertFailed(("invalid clipboard DIB data: biBitCount=%d\n", uSrc.pHdr->biBitCount));
2859 return NULL;
2860 }
2861 if ( uSrc.pHdrV5->bV5Size == sizeof(BITMAPV5HEADER)
2862 && uSrc.pHdrV5->bV5CSType != LCS_sRGB)
2863 {
2864 DebugAssertFailed(("unexpected clipboard DIBV5 data: bV5CSType=%#x\n", uSrc.pHdrV5->bV5CSType));
2865 return NULL;
2866 }
2867
2868 /*
2869 * Figure out the size of the target bitmap and allocate memory for this.
2870 */
2871 unsigned cbTrgHeader = uFormat == CF_DIB ? sizeof(BITMAPINFOHEADER) : sizeof(BITMAPV5HEADER);
2872 unsigned cbTotal = cbSrc + (cbTrgHeader - uSrc.pHdr->biSize);
2873 PCLIPLOCALDATA pLocalClip;
2874 HANDLE hMem = clipboardCacheAllocGlobalAlloc(uFormat, cbTotal, &pLocalClip);
2875 if (!hMem)
2876 return NULL;
2877 uTrg.pv = GlobalLock(hMem);
2878
2879 /*
2880 * Convert the bitmap data.
2881 * Note that the source and target DIB data might be in the same format.
2882 */
2883 if (cbTrgHeader != uTrg.pHdr->biSize)
2884 {
2885 /** @todo Only a subset of DIB V5 bitmaps are supported, implement it fully all around Odin32. */
2886 switch (uFormat)
2887 {
2888 case CF_DIBV5:
2889 #ifdef USE_DIBV5
2890 memcpy(uTrg.pv, uSrc.pv, uSrc.pHdr->biSize);
2891 memset(uTrg.pch + uSrc.pHdr->biSize, 0, sizeof(BITMAPV5HEADER) - uSrc.pHdr->biSize);
2892 uTrg.pHdrV5->bV5Size = sizeof(BITMAPV5HEADER);
2893 uTrg.pHdrV5->bV5CSType = LCS_sRGB;
2894 memcpy(uTrg.pch + sizeof(BITMAPV5HEADER), uSrc.pch + uSrc.pHdr->biSize, cbSrc - uSrc.pHdr->biSize);
2895 break;
2896 #else
2897 //fallthru
2898 #endif
2899 case CF_DIB:
2900 memcpy(uTrg.pv, uSrc.pv, min(uSrc.pHdr->biSize, sizeof(BITMAPINFOHEADER)));
2901 if (uSrc.pHdr->biSize < sizeof(BITMAPINFOHEADER))
2902 memset(uTrg.pch + uSrc.pHdr->biSize, 0, sizeof(BITMAPINFOHEADER) - uSrc.pHdr->biSize);
2903 memcpy(uTrg.pch + sizeof(BITMAPINFOHEADER), uSrc.pch + uSrc.pHdr->biSize, cbSrc - uSrc.pHdr->biSize);
2904 break;
2905 }
2906 }
2907 GlobalUnlock(hMem);
2908 /* done */
2909 return hMem;
2910 }
2911 }
2912
2913 return NULL;
2914}
2915
2916#if 0 // not implemented yet
2917HANDLE clipboardSynthesizePalette(UINT uFormat)
2918{
2919 return NULL;
2920}
2921
2922HANDLE clipboardSynthesizeMetaFile(UINT uFormat)
2923{
2924 return NULL;
2925}
2926
2927HANDLE clipboardSynthesizeEnhMetaFile(UINT uFormat)
2928{
2929 return NULL;
2930}
2931#endif
2932
2933
2934/**
2935 * Get the length of a text on the clipboard.
2936 *
2937 * @returns up to cb.
2938 * @param pvData Data pointer.
2939 * @param cb Data size.
2940 */
2941unsigned clipboardTextCalcSize(void *pvData, unsigned cb)
2942{
2943 const char *psz = (const char*)pvData;
2944 const char *pszEnd = psz + cb;
2945 while (psz + 1 < pszEnd)
2946 {
2947 if (!*psz && !psz[1]) /* Check for two '\0' to keep out of dbcs trouble. */
2948 return psz - (char*)pvData + 1;
2949 psz++;
2950 }
2951 return cb;
2952}
2953
2954
2955/**
2956 * Gets the clipboad code page using the CF_LOCALE entry if present, if not
2957 * present the system default is used.
2958 *
2959 * @returns Codepage corresponding to uType.
2960 * @param uType Code page type.
2961 */
2962unsigned clipboardGetCodepage(UINT uType)
2963{
2964 /*
2965 * Find the LCID to use.
2966 */
2967 HANDLE hMem = GetClipboardData(CF_LOCALE);
2968 LCID lcid;
2969 LCID *plcid;
2970 if (hMem && (plcid = (LCID *)GlobalLock(hMem)) != NULL)
2971 {
2972 lcid = *plcid;
2973 GlobalUnlock(hMem);
2974 }
2975 else
2976 lcid = GetSystemDefaultLCID();
2977
2978 char szCp[6];
2979 if (GetLocaleInfoA(lcid, uType, szCp, sizeof(szCp)))
2980 return atoi(szCp);
2981
2982 switch (uType)
2983 {
2984 case LOCALE_IDEFAULTCODEPAGE : return CP_OEMCP;
2985 case LOCALE_IDEFAULTANSICODEPAGE: return CP_ACP;
2986 default : return CP_MACCP;
2987 }
2988}
2989
2990
2991/**
2992 * GlobalAllocs a block of memory for the cache initializing it from the
2993 * the memory block specified pv.
2994 *
2995 * @returns Handle to 'global' memory object.
2996 * @returns NULL on failure.
2997 * @param uFormat Odin format number.
2998 * @param pv Pointer to memory block to duplicate.
2999 * @param cb Number of bytes to allocate and duplicate.
3000 * @param ppLocalClip Where to put the cache structure.
3001 */
3002HANDLE clipboardCacheAllocGlobalDup(UINT uFormat, const void *pv, unsigned cb, PCLIPLOCALDATA *ppClip)
3003{
3004 dprintf2(("USER32: clipboardCacheAllocGlobalDup: uFormat=%d (%s) pv=%p cb=%d\n",
3005 uFormat, dbgGetFormatName(uFormat), pv, cb));
3006
3007 /*
3008 * Allocate cache block and copy data.
3009 */
3010 HANDLE hMem = clipboardCacheAllocGlobalAlloc(uFormat, cb, ppClip);
3011 if (hMem)
3012 {
3013 PVOID pvMem = GlobalLock(hMem);
3014 memcpy(pvMem, pv, cb);
3015 GlobalUnlock(hMem);
3016 }
3017
3018 return hMem;
3019}
3020
3021
3022
3023/**
3024 * GlobalAllocs a block of memory for the cache.
3025 *
3026 * @returns Handle to 'global' memory object.
3027 * @returns NULL on failure.
3028 * @param uFormat Odin format number.
3029 * @param cb Number of bytes to allocate.
3030 * @param ppLocalClip Where to put the cache structure.
3031 */
3032HANDLE clipboardCacheAllocGlobalAlloc(UINT uFormat, unsigned cb, PCLIPLOCALDATA *ppLocalClip)
3033{
3034 dprintf2(("USER32: clipboardCacheAllocGlobalAlloc: uFormat=%d (%s) cb=%d\n",
3035 uFormat, dbgGetFormatName(uFormat), cb));
3036 /*
3037 * Allocate object.
3038 */
3039 HANDLE hMem = GlobalAlloc(GMEM_MOVEABLE, cb);
3040 if (!hMem)
3041 {
3042 dprintf(("USER32: GetClipboardData: returns NULL (GlobalAlloc(,%d) failed)\n", cb));
3043 return NULL;
3044 }
3045
3046 /*
3047 * Allocate and initialize cache node.
3048 */
3049 if (clipboardCacheAllocGlobalMem(uFormat, hMem, ppLocalClip))
3050 return hMem;
3051
3052 /* failed */
3053 GlobalFree(hMem);
3054 return NULL;
3055}
3056
3057
3058/**
3059 * Allocates a cache node for a global memory handle.
3060 *
3061 * @returns Handle to 'global' memory object.
3062 * @returns NULL on failure.
3063 * @param uFormat Odin format number.
3064 * @param cb Number of bytes to allocate.
3065 * @param ppLocalClip Where to put the cache structure.
3066 */
3067BOOL clipboardCacheAllocGlobalMem(UINT uFormat, HANDLE hMem, PCLIPLOCALDATA *ppLocalClip)
3068{
3069 dprintf2(("USER32: clipboardCacheAllocGlobalMem: uFormat=%d (%s) hMem=%#x\n",
3070 uFormat, dbgGetFormatName(uFormat), hMem));
3071
3072 /*
3073 * Allocate and initialize cache node.
3074 */
3075 PCLIPLOCALDATA pLocalClip = (PCLIPLOCALDATA)malloc(sizeof(*pLocalClip));
3076 *ppLocalClip = pLocalClip;
3077 if (!pLocalClip)
3078 return FALSE;
3079
3080 pLocalClip->enmType = CLIPLOCALDATA::enmGlobalMem;
3081 pLocalClip->h = hMem;
3082 pLocalClip->uFormat = uFormat;
3083 pLocalClip->pNext = NULL;
3084
3085 return TRUE;
3086}
3087
3088
3089/**
3090 * Allocates a cache node for a GDI handle.
3091 *
3092 * @returns hGDI on success.
3093 * @returns NULL on failure.
3094 * @param uFormat Clipboard format number.
3095 * @param hGDI GDI handle.
3096 * @param ppLocalClip Where to store the pointer to the allocated cache node.
3097 */
3098BOOL clipboardCacheAllocGDI(UINT uFormat, HANDLE hGDI, PCLIPLOCALDATA *ppLocalClip)
3099{
3100 dprintf2(("USER32: clipboardCacheAllocGDI: uFormat=%d (%s) hGdi=%#x\n",
3101 uFormat, dbgGetFormatName(uFormat), hGDI));
3102 /*
3103 * Allocate and initialize cache node.
3104 */
3105 PCLIPLOCALDATA pLocalClip = (PCLIPLOCALDATA)malloc(sizeof(*pLocalClip));
3106 *ppLocalClip = pLocalClip;
3107 if (!pLocalClip)
3108 return FALSE;
3109
3110 pLocalClip->enmType = CLIPLOCALDATA::enmGDI;
3111 pLocalClip->h = hGDI;
3112 pLocalClip->uFormat = uFormat;
3113 pLocalClip->pNext = NULL;
3114
3115 return TRUE;
3116}
3117
3118
3119/**
3120 * Inserts a previously allocated local cache node.
3121 *
3122 * Since this is a cache, pNew might be rejected because of the data
3123 * already existing in the cache. Therefor always use the returned handle.
3124 *
3125 * @returns The handle in the cached node.
3126 * @param pNew Node to insert.
3127 */
3128HANDLE clipboardCacheInsertNode(PCLIPLOCALDATA pNew)
3129{
3130 dprintf2(("USER32: clipboardCacheInsertNode: pNew=%p format=%d (%s) h=%#x\n",
3131 pNew, pNew->uFormat, dbgGetFormatName(pNew->uFormat), pNew->h));
3132 /*
3133 * Find the previous node with the same format.
3134 */
3135 PCLIPLOCALDATA p = gpLocalData;
3136 PCLIPLOCALDATA pPrev = NULL;
3137 while (p && p->uFormat != pNew->uFormat)
3138 p = p->pNext;
3139 if (p)
3140 {
3141 /*
3142 * If the old and new cache nodes are idendical we'll keep the old one.
3143 */
3144 if (p->enmType == pNew->enmType)
3145 {
3146 switch (p->enmType)
3147 {
3148 case CLIPLOCALDATA::enmGlobalMem:
3149 {
3150 DWORD cb = GlobalSize(p->h);
3151 if (cb == GlobalSize(pNew->h))
3152 {
3153 PVOID pv = GlobalLock(p->h);
3154 PVOID pvNew = GlobalLock(pNew->h);
3155 int diff = -1;
3156 if (pv && pvNew)
3157 diff = memcmp(pv, pvNew, cb);
3158 GlobalUnlock(pNew->h);
3159 GlobalUnlock(p->h);
3160 if (!diff)
3161 {
3162 clipboardCacheDeleteNode(pNew);
3163 dprintf2(("USER32: clipboardCacheInsertNode: returning existing node %#x (cache hit)\n", p->h));
3164 return p->h;
3165 }
3166 }
3167 break;
3168 }
3169
3170 case CLIPLOCALDATA::enmGDI:
3171 /** @todo */
3172 break;
3173
3174 case CLIPLOCALDATA::enmPrivate:
3175 default:
3176 DebugAssertFailed(("Don't know how to handle this type\n"));
3177 break;
3178 }
3179
3180 }
3181
3182 /*
3183 * Remove and delete the old node.
3184 */
3185 dprintf2(("USER32: clipboardCacheInsertNode: removing old node %p h=%#x\n", p, p->h));
3186 if (pPrev)
3187 pPrev->pNext = p->pNext;
3188 else
3189 gpLocalData = p->pNext;
3190 clipboardCacheDeleteNode(p);
3191 }
3192
3193 /*
3194 * Insert the new node.
3195 */
3196 pNew->pNext = gpLocalData;
3197 gpLocalData = pNew;
3198
3199 return pNew->h;
3200}
3201
3202
3203/**
3204 * Delete Odin resources associated with a cache node.
3205 *
3206 * The node must be unlinked from the cache before this function is called.
3207 *
3208 * @param p Node to delete.
3209 */
3210void clipboardCacheDeleteNode(PCLIPLOCALDATA p)
3211{
3212 dprintf2(("USER32: clipboardCacheDeleteNode: p=%p format=%d (%s) h=%#x\n",
3213 p, p->uFormat, dbgGetFormatName(p->uFormat), p->h));
3214 switch (p->enmType)
3215 {
3216 case CLIPLOCALDATA::enmGlobalMem:
3217 if (GlobalFree(p->h))
3218 DebugAssertFailed(("GlobalFree failed freeing %#x (format %d). lasterr=%d\n",
3219 p->h, p->uFormat, GetLastError()));
3220 p->h = NULL;
3221 break;
3222
3223 case CLIPLOCALDATA::enmGDI:
3224 if (!DeleteObject(p->h))
3225 DebugAssertFailed(("DeleteObject failed freeing %#x (format %d). lasterr=%d\n",
3226 p->h, p->uFormat, GetLastError()));
3227 p->h = NULL;
3228 break;
3229
3230 case CLIPLOCALDATA::enmPrivate:
3231 DebugAssertFailed(("shit! don't know how to handle this cache type!"));
3232 break;
3233 default:
3234 DebugAssertFailed(("!cache corrupted! invalid type %d", p->enmType));
3235 break;
3236 }
3237 free(p);
3238}
3239
Note: See TracBrowser for help on using the repository browser.