source: branches/gcc-kmk/src/user32/clipboard.cpp@ 21687

Last change on this file since 21687 was 21573, checked in by dmik, 15 years ago

user32: Disable an assertion in the debug build that doesn't look right.

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#if 0
1126 DebugAssert(ghwndOpenClipboard == hwnd, ("ghwndOpenClipboard=%#x actual=%#x\n", ghwndOpenClipboard, hwnd));
1127 DebugAssert((!hwnd && !ghwndOS2OpenClipboard) || (hwnd && ghwndOS2OpenClipboard != hwndOS2),
1128 ("ghwndOS2OpenClipboard=%#x actual=%#x\n", ghwndOS2OpenClipboard, hwndOS2));
1129#endif
1130 dprintf(("USER32: GetOpenCliboardWindow: returning %#x (os2=%#x)\n", hwnd, hwndOS2));
1131 return hwnd;
1132}
1133
1134
1135
1136
1137
1138
1139//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
1140//
1141//
1142// 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
1143//
1144//
1145//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
1146
1147
1148/**
1149 * Checks if the current thread is the clipboard owner with read/write access.
1150 *
1151 * @returns TRUE if we're the owner, FALSE if not.
1152 */
1153BOOL clipboardIsRWOwner(void)
1154{
1155#if 1
1156 /*
1157 * The simple way.
1158 */
1159 return gtidOpenClipboardThreadId == GetCurrentThreadId();
1160#else
1161 /*
1162 * This is gonna be a bit hacky.
1163 * We'll try to open the clipboard and then determin whether or not
1164 * we already owned it by the return code and such.
1165 */
1166 BOOL fRc = FALSE;
1167 HAB hab = GetThreadHAB();
1168 OSLibWinSetErrorInfo(0, 0);
1169 OSLibWinGetLastError();
1170 if (!OSLib_OpenClipbrd(hab, (HWND)0xdeadface))
1171 {
1172 /* check why we failed. */
1173 if ((OSLibWinGetLastError() & 0xffff) == OSLIB_PMERR_CALL_FROM_WRONG_THREAD)
1174 fRc = TRUE;
1175 }
1176 else
1177 {
1178 /* we might have to close it ... */
1179 ULONG ulRc = OSLibWinGetLastError();
1180 if ((ulRc & 0xffff) == OSLIB_PMERR_CALL_FROM_WRONG_THREAD)
1181 {
1182 fRc = TRUE;
1183 DebugAssertFailed(("Open returned TRUE while last error was PMERR_CALL_FROM_WRONG_THREAD. bad heuristics!!!\n"));
1184 }
1185 else
1186 {
1187 DebugAssert(ulRc == 0, ("Last error is %#x and not 0x0 as we expected!!!\n", ulRc));
1188 OSLibWinCloseClipbrd(hab);
1189 }
1190 }
1191 return fRc;
1192#endif
1193}
1194
1195
1196/**
1197 * Adds an item to the PM clipboard.
1198 *
1199 * @returns success indicator.
1200 * @param uOdinFormat Odin format number.
1201 * @param pv Pointer to a buffer containing the data.
1202 * If fAllocate is clear this is a buffer allocated
1203 * using clipboardAllocPMBuffer()
1204 * @param cb Size of the data in the buffer.
1205 */
1206BOOL clipboardAddPM(UINT uOdinFormat, void *pv, unsigned cb)
1207{
1208 DebugAssert(uOdinFormat == CF_TEXT || uOdinFormat == CF_BITMAP || uOdinFormat == CF_PALETTE,
1209 ("%d should have a header. fixme!!!\n", uOdinFormat));
1210 /*
1211 * Validate and translate the format number.
1212 */
1213 ULONG ulPMFormat = clipboardOdinToPMFormat(uOdinFormat);
1214 DebugAssert(ulPMFormat > 0, ("failed to convert odin format %d to PM!!!\n", uOdinFormat));
1215 if (ulPMFormat == 0)
1216 return FALSE;
1217
1218 /*
1219 * Allocate PM Clipboard buffer.
1220 */
1221 void *pvBuf = (PCLIPHEADER)clipboardAllocPMBuffer(cb);
1222 if (!pvBuf)
1223 return FALSE;
1224 pv = memcpy(pvBuf, pv, cb);
1225
1226 /*
1227 * Place it on the clipboard.
1228 */
1229 if (OSLibWinSetClipbrdData(GetThreadHAB(),(ULONG)pvBuf, ulPMFormat, OSLIB_CFI_POINTER))
1230 return TRUE;
1231 DebugAssertFailed(("WinSetClipbrdData failed!!! lasterr=%#x\n", OSLibWinGetLastError()));
1232 return FALSE;
1233}
1234
1235
1236/**
1237 * Adds an item to the PM clipboard.
1238 *
1239 * @returns success indicator.
1240 * @param uOdinFormat Odin format number.
1241 * @param pv Pointer to a buffer containing the data.
1242 * If fAllocate is clear this is a buffer allocated
1243 * using clipboardAllocPMBuffer()
1244 * @param cb Size of the data in the buffer.
1245 */
1246BOOL clipboardAddPMHeader(UINT uOdinFormat, void *pv, unsigned cb)
1247{
1248 DebugAssert(uOdinFormat != CF_TEXT && uOdinFormat != CF_BITMAP && uOdinFormat != CF_PALETTE,
1249 ("%d should not have a header. fixme!!!\n", uOdinFormat));
1250 /*
1251 * Validate and translate the format number.
1252 */
1253 ULONG ulPMFormat = clipboardOdinToPMFormat(uOdinFormat);
1254 DebugAssert(ulPMFormat > 0, ("failed to convert odin format %d to PM!!!\n", uOdinFormat));
1255 if (ulPMFormat == 0)
1256 return FALSE;
1257
1258 /*
1259 * Allocate PM Clipboard buffer.
1260 */
1261 PCLIPHEADER pClip = (PCLIPHEADER)clipboardAllocPMBuffer(cb + sizeof(CLIPHEADER));
1262 if (!pClip)
1263 return FALSE;
1264 memcpy(pClip->achMagic, CLIPHEADER_MAGIC, sizeof(CLIPHEADER_MAGIC));
1265 pClip->cbData = cb;
1266 pClip->uFormat = uOdinFormat;
1267 pv = memcpy(pClip + 1, pv, cb);
1268
1269 /*
1270 * Place it on the clipboard.
1271 */
1272 if (OSLibWinSetClipbrdData(GetThreadHAB(),(ULONG)pClip, ulPMFormat, OSLIB_CFI_POINTER))
1273 return TRUE;
1274 DebugAssertFailed(("WinSetClipbrdData failed!!! lasterr=%#x\n", OSLibWinGetLastError()));
1275 return FALSE;
1276}
1277
1278
1279/**
1280 * Adds an item to the PM clipboard.
1281 *
1282 * @returns success indicator.
1283 * @param uOdinFormat Odin format number.
1284 * @param h Handle.
1285 */
1286BOOL clipboardAddPMHandle(UINT uOdinFormat, HANDLE h)
1287{
1288 DebugAssert(uOdinFormat == CF_TEXT || uOdinFormat == CF_BITMAP || uOdinFormat == CF_PALETTE,
1289 ("%d should have a header. fixme!!!\n", uOdinFormat));
1290 /*
1291 * Validate and translate the format number.
1292 */
1293 ULONG ulPMFormat = clipboardOdinToPMFormat(uOdinFormat);
1294 DebugAssert(ulPMFormat > 0, ("failed to convert odin format %d to PM!!!\n", uOdinFormat));
1295 if (ulPMFormat == 0)
1296 return FALSE;
1297
1298 /*
1299 * Place it on the clipboard.
1300 */
1301 if (OSLibWinSetClipbrdData(GetThreadHAB(),(ULONG)h, ulPMFormat, OSLIB_CFI_HANDLE))
1302 return TRUE;
1303 DebugAssertFailed(("WinSetClipbrdData failed!!! lasterr=%#x\n", OSLibWinGetLastError()));
1304 return FALSE;
1305}
1306
1307
1308/**
1309 * Allocates a buffer for use with the PM clipboard.
1310 *
1311 * @returns Pointer to buffer.
1312 * @returns NULL on failure.
1313 * @param cb Size of buffer.
1314 */
1315void * clipboardAllocPMBuffer(unsigned cb)
1316{
1317 /*
1318 * Dos alloc a shared buffer.
1319 */
1320 PVOID pv = NULL;
1321 ULONG rc = OSLibDosAllocSharedMem(&pv, NULL, (cb + 0xfff) & ~0xfff, OSLIB_PAG_READ | OSLIB_PAG_WRITE | OSLIB_PAG_COMMIT | OSLIB_OBJ_GIVEABLE);
1322 if (rc)
1323 return NULL;
1324 return pv;
1325}
1326
1327
1328
1329/**
1330 * Inserts a dummy placeholder in the clipboard.
1331 *
1332 * @returns Success indicator.
1333 * @param uOdinFormat Odin clipboard format number.
1334 * @remark The few other applications using the Open32 defined
1335 * format names may not like this...
1336 */
1337BOOL clipboardAddPMDummy(UINT uOdinFormat)
1338{
1339 /*
1340 * Validate and translate the format number.
1341 */
1342 ULONG ulPMFormat = clipboardOdinToPMFormat(uOdinFormat);
1343 DebugAssert(ulPMFormat > 0, ("failed to convert odin format %d to PM!!!\n", uOdinFormat));
1344 if (ulPMFormat == 0)
1345 return FALSE;
1346
1347 /*
1348 * Insert a dummy handle.
1349 */
1350 BOOL fRc = OSLibWinSetClipbrdData(GetThreadHAB(), DUMMY_HANDLE, ulPMFormat, OSLIB_CFI_HANDLE);
1351 DebugAssert(fRc, ("WinSetClipbrdData failed. lasterr=%#x\n", OSLibWinGetLastError()));
1352 return fRc;
1353}
1354
1355
1356/**
1357 * Tries to figure out the size of the data retrieved from the clipboard.
1358 *
1359 * @returns 0 on failure.
1360 * @returns size in bytes of the data.
1361 * @param pvData Data retrieved from the clipboard.
1362 */
1363ULONG clipboardGetPMDataSize(void *pvData)
1364{
1365 ULONG fl = ~0;
1366 ULONG cb = ~0;
1367 ULONG ulRc = OSLibDosQueryMem(pvData, &cb, &fl);
1368 if (ulRc)
1369 { /* retry */
1370 fl = ~0;
1371 cb = 512*1024*1024;
1372 ulRc = OSLibDosQueryMem(pvData, &cb, &fl);
1373 }
1374 if (ulRc)
1375 {
1376 DebugAssertFailed(("DosQueryMem(%#x,,) failed with rc=%d\n", pvData, ulRc));
1377 return 0;
1378 }
1379
1380 dprintf2(("data: %#x size: %d flags: %#x\n", pvData, cb, fl));
1381 return cb;
1382}
1383
1384
1385/**
1386 * Opens the clipboard.
1387 *
1388 * @returns Success indicator.
1389 * @param hwnd Handle to window which is to become owner
1390 * when EmptyClipboard is called.
1391 * If NULL the clipboard is to be associated with
1392 * the current thread.
1393 * @status completely implemented
1394 * @author knut st. osmundsen <bird-srcspam@anduin.net>
1395 * @remark This should not block, although there is a possiblity that a competing
1396 * thread may cause us to block. This is PM's fault.
1397 */
1398BOOL WIN32API OpenClipboard(HWND hwnd)
1399{
1400 HWND hwndOS2 = NULL;
1401
1402 /*
1403 * Validate input and translate window handle.
1404 */
1405 if (hwnd)
1406 {
1407 Win32BaseWindow *pWnd = Win32BaseWindow::GetWindowFromHandle(hwnd);
1408 if (!pWnd)
1409 {
1410 dprintf(("USER32: OpenClipboard: window %x not found", hwnd));
1411 SetLastError(ERROR_INVALID_WINDOW_HANDLE);
1412 return 0;
1413 }
1414 hwndOS2 = pWnd->getOS2WindowHandle();
1415 RELEASE_WNDOBJ(pWnd);
1416 }
1417
1418 /*
1419 * Open the clipboard.
1420 */
1421 dprintf(("USER32: OpenClipboard(%#x/%#x)\n", hwnd, hwndOS2));
1422 BOOL fRc = OSLib_OpenClipbrd(GetThreadHAB(), hwndOS2);
1423 if (fRc)
1424 {
1425 ghwndOpenClipboard = hwnd;
1426 ghwndOS2OpenClipboard = hwndOS2;
1427 gtidOpenClipboardThreadId = GetCurrentThreadId();
1428 gfClipboardChanged = FALSE;
1429 gfClipboardChangedText= FALSE;
1430 }
1431 dprintf(("USER32: OpenClipboard: returning %d\n", fRc));
1432 return fRc;
1433}
1434
1435
1436/**
1437 * Empty the clipboard.
1438 *
1439 * This will empty the clipboard freeing all global resources.
1440 * It will further free all local resources associated with the
1441 * clipboard.
1442 *
1443 * The window specified in the OpenClipboard() call will become
1444 * the owner of the clipboard upon successful return from this
1445 * call.
1446 *
1447 * @returns Success indicator.
1448 * @status completely implemented.
1449 * @author knut st. osmundsen <bird-srcspam@anduin.net>
1450 */
1451BOOL WIN32API EmptyClipboard(void)
1452{
1453 dprintf(("USER32: EmptyClipboard. ghwndOpenClipboard=%#x/%#x\n", ghwndOpenClipboard, ghwndOS2OpenClipboard));
1454 BOOL fRc = OSLibWinEmptyClipbrd(GetThreadHAB());
1455 if (!fRc)
1456 {
1457 ULONG ulRc = OSLibWinGetLastError();
1458 if ((ulRc & 0xffff) == OSLIB_PMERR_CALL_FROM_WRONG_THREAD)
1459 SetLastError(ERROR_CLIPBOARD_NOT_OPEN);
1460 else
1461 SetLastError(ERROR_GEN_FAILURE);
1462 dprintf(("USER32: EmptyClipboard: WinEmptyClipbrd failed. lasterr=%#x\n", ulRc));
1463 return FALSE;
1464 }
1465
1466 /*
1467 * Take clipboard ownership.
1468 */
1469 if (!OSLibWinSetClipbrdOwner(GetThreadHAB(), ghwndOS2OpenClipboard))
1470 {
1471 DebugAssertFailed(("WinSetClipbrdOwner failed!! lasterr=%#x\n", OSLibWinGetLastError()));
1472 #if 0 /* Not sure what kind of action which makes most sense. */
1473 SetLastError(ERROR_INVALID_WINDOW_HANDLE);
1474 return FALSE;
1475 #else
1476 OSLibWinSetClipbrdOwner(GetThreadHAB(), NULL);
1477 #endif
1478 }
1479
1480 /*
1481 * Free per process resources.
1482 */
1483 for (PCLIPLOCALDATA p = gpLocalData, pNext = NULL; p; p = pNext)
1484 {
1485 pNext = p->pNext;
1486 clipboardCacheDeleteNode(p);
1487 }
1488 gpLocalData = NULL;
1489 gfClipboardChanged = TRUE;
1490 gfClipboardChangedText = FALSE;
1491
1492 dprintf(("USER32: EmptyClipboard: returns successfully\n"));
1493 return TRUE;
1494}
1495
1496
1497/**
1498 * Puts data onto the clipboard.
1499 *
1500 * @returns hCliObj on success.
1501 * @returns NULL on failure, last error may be set.
1502 * @param uFormat The format of hClipObj.
1503 * @param hClipObj Handle to data to put on the clipboard.
1504 * @status partially implemented.
1505 * @author knut st. osmundsen <bird-srcspam@anduin.net>
1506 * @todo Checkup last errors!
1507 */
1508HANDLE WIN32API SetClipboardData(UINT uFormat, HANDLE hClipObj)
1509{
1510 dprintf(("SetClipboardData uFormat=%#x (%s) hClipObj=%#x", uFormat, dbgGetFormatName(uFormat), hClipObj));
1511 dbgDumpClipboardData("SetClipboardData", uFormat, hClipObj);
1512
1513 /*
1514 * Validate that the thread have opened the clipboard.
1515 */
1516 if (/* !clipboardIsRWOwner() - must allow rendering. PM catches it. ||*/ !uFormat)
1517 {
1518 SetLastError(ERROR_CLIPBOARD_NOT_OPEN);
1519 dprintf(("USER32: SetClipboardData: returns NULL (no openclipboard)\n"));
1520 return NULL;
1521 }
1522
1523 /*
1524 * Validate format.
1525 */
1526 ULONG ulPMFormat = clipboardOdinToPMFormat(uFormat);
1527 DebugAssert(!uFormat || ulPMFormat > 0, ("failed to convert odin format %d to PM!!!\n", uFormat));
1528 if (!ulPMFormat)
1529 {
1530 //last error?
1531 dprintf(("USER32: SetClipboardData: return NULL (invalid format %d)\n", uFormat));
1532 return NULL;
1533 }
1534
1535 /*
1536 * For some formats we just put out OS/2 handles, for the
1537 * others we duplicate the memory buffer passed in to us.
1538 */
1539 PCLIPLOCALDATA pLocalClip = NULL; /* Cache node for per process data. */
1540 ULONG flPMData = 0;
1541 ULONG ulPMData = 0;
1542 BOOL fHeader = TRUE; /* Whether or not to prepend an odin clip data header. */
1543 switch (uFormat)
1544 {
1545 /*
1546 * Make a duplication of the PM handle for the PM clipboard and
1547 * put the Odin32 handle in the cache.
1548 */
1549 case CF_BITMAP:
1550 case CF_DSPBITMAP:
1551 case CF_PALETTE:
1552 flPMData = OSLIB_CFI_HANDLE;
1553 if (hClipObj)
1554 {
1555 ulPMData = O32_GetPMHandleFromGDIHandle(hClipObj);
1556 if (!ulPMData)
1557 {
1558 dprintf(("USER32: SetClipboardData: return NULL. Failed to get PM handle from Odin32 %s handle %#x\n",
1559 dbgGetFormatName(uFormat), hClipObj));
1560 return NULL;
1561 }
1562
1563 /*
1564 * Duplicate the PM handle.
1565 */
1566 switch (uFormat)
1567 {
1568 case CF_BITMAP:
1569 case CF_DSPBITMAP:
1570 ulPMData = (ULONG)OSLibClipboardPMBitmapDuplicate((HBITMAP)ulPMData);
1571 break;
1572 case CF_PALETTE:
1573 ulPMData = (ULONG)OSLibClipboardPMPaletteDuplicate((HPALETTE)ulPMData);
1574 break;
1575 }
1576 if (!ulPMData)
1577 {
1578 dprintf(("USER32: SetClipboardData: return NULL. Failed to duplicate PM handle!\n"));
1579 return NULL;
1580 }
1581
1582 /*
1583 * Allocate cache node.
1584 */
1585 if (!clipboardCacheAllocGDI(uFormat, hClipObj, &pLocalClip))
1586 DebugAssertFailed(("out of memory"));
1587 }
1588 break;
1589
1590 /*
1591 * Put the metafile bits onto the clipboard.
1592 * Put hClipObj in cache for delayed freeing.
1593 */
1594 case CF_METAFILEPICT:
1595 case CF_DSPMETAFILEPICT:
1596 {
1597#if 0 //todo implement get code.
1598 flPMData = OSLIB_CFI_POINTER;
1599 if (hClipObj)
1600 {
1601 /* get the data */
1602 LPMETAFILEPICT pMeta = (LPMETAFILEPICT)GlobalLock(hClipObj);
1603 if (!pMeta)
1604 {
1605 SetLastError(ERROR_INVALID_PARAMETER);
1606 dprintf(("USER32: SetClipboardData: returns NULL (metafilepict lock)\n"));
1607 return NULL;
1608 }
1609 /* get size */
1610 DWORD cb = GetMetaFileBitsEx(pMeta->hMF, 0, NULL);
1611 dprintf2(("GetMetaFileBitsEx -> %d\n", cb));
1612 if (!cb)
1613 { /* ?? */
1614 SetLastError(ERROR_INVALID_PARAMETER);
1615 dprintf(("USER32: SetClipboardData: returns NULL (metafilepict handle)\n"));
1616 return NULL;
1617 }
1618 /* allocate shared */
1619 DWORD cbTotal = sizeof(CLIPHEADER) + sizeof(METAFILEPICT) + cb;
1620 PCLIPHEADER pClip = (PCLIPHEADER)clipboardAllocPMBuffer(cbTotal);
1621 if (!pClip)
1622 {
1623 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1624 dprintf(("USER32: SetClipboardData: returns NULL (metafilepict mem)\n"));
1625 return NULL;
1626 }
1627 /* make block */
1628 memcpy(pClip->achMagic, CLIPHEADER_MAGIC, sizeof(CLIPHEADER_MAGIC));
1629 pClip->cbData = cbTotal; /* bits + metafilepict */
1630 pClip->uFormat = uFormat;
1631 *(LPMETAFILEPICT)(pClip + 1) = *pMeta;
1632 /* (ASSUMES it's not be touched since last call to this api.) */
1633 GetMetaFileBitsEx(pMeta->hMF, cb, (char*)(pClip + 1) + sizeof(*pMeta));
1634 }
1635 break;
1636#else
1637 DebugAssertFailed(("metafile support not enabled"));
1638 return NULL;
1639#endif
1640 }
1641
1642 /*
1643 * Put the enh. metafile bits onto the clipboard.
1644 * Put hClipObj in cache for delayed freeing.
1645 */
1646 case CF_ENHMETAFILE:
1647 case CF_DSPENHMETAFILE:
1648 {
1649#if 0 //todo implement get code.
1650 flPMData = OSLIB_CFI_POINTER;
1651 if (hClipObj)
1652 {
1653 /* get size */
1654 DWORD cb = GetEnhMetaFileBits(hClipObj, 0, NULL);
1655 dprintf2(("GetEnhMetaFileBits -> %d\n", cb));
1656 if (!cb)
1657 { /* ?? */
1658 SetLastError(ERROR_INVALID_PARAMETER);
1659 dprintf(("USER32: SetClipboardData: returns NULL (enhmetafile handle)\n"));
1660 return NULL;
1661 }
1662 /* allocate shared */
1663 DWORD cbTotal = sizeof(CLIPHEADER) + cb;
1664 PCLIPHEADER pClip = (PCLIPHEADER)clipboardAllocPMBuffer(cbTotal);
1665 if (!pClip)
1666 {
1667 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1668 dprintf(("USER32: SetClipboardData: returns NULL (enhmetafile mem)\n"));
1669 return NULL;
1670 }
1671 /* make block */
1672 pClip->cbData = cbTotal; /* bits */
1673 pClip->uFormat = uFormat;
1674 /* (ASSUMES it's not be touched since last call to this api.) */
1675 GetEnhMetaFileBits(hClipObj, cb, (LPBYTE)(pClip + 1));
1676 }
1677 break;
1678#else
1679 DebugAssertFailed(("metafile support not enabled"));
1680 return NULL;
1681#endif
1682 }
1683
1684 /*
1685 * The Owner display, the data must be NULL.
1686 */
1687 case CF_OWNERDISPLAY:
1688 {
1689 flPMData = OSLIB_CFI_OWNERDISPLAY | OSLIB_CFI_HANDLE;
1690 if (hClipObj)
1691 {
1692 SetLastError(ERROR_INVALID_PARAMETER); /** @todo check this last error */
1693 dprintf(("USER32: SetClipboardData: returns NULL (owner display data)\n"));
1694 return NULL;
1695 }
1696 break;
1697 }
1698
1699 /*
1700 * Allocate shared data.
1701 */
1702 case CF_TEXT:
1703 case CF_DSPTEXT:
1704 /* these are shared with OS/2 and shall have no header */
1705 fHeader = FALSE;
1706 /* fallthru */
1707 case CF_UNICODETEXT:
1708 case CF_OEMTEXT:
1709 case CF_LOCALE:
1710 case CF_DIB:
1711 case CF_DIBV5:
1712 case CF_HDROP:
1713 case CF_SYLK:
1714 case CF_DIF:
1715 case CF_TIFF:
1716 case CF_PENDATA:
1717 case CF_RIFF:
1718 case CF_WAVE:
1719 flPMData = OSLIB_CFI_POINTER;
1720 /* fall thru */
1721 default:
1722 if (uFormat >= CF_GDIOBJFIRST && uFormat <= CF_GDIOBJFIRST)
1723 {
1724 DebugAssertFailed(("CF_GDIOBJ* is not implemented!!!\n"));
1725 SetLastError(ERROR_GEN_FAILURE);
1726 dprintf(("USER32: SetClipboardData: returns NULL (gdiobj)\n"));
1727 return NULL;
1728 }
1729
1730 /*
1731 * We assume the rest is global handles, if not we'll check treat
1732 * them as handles we don't care to much about.
1733 */
1734 if (hClipObj)
1735 {
1736 PVOID pv = GlobalLock(hClipObj);
1737 if (pv)
1738 {
1739 /*
1740 * Global memory object.
1741 * Duplicate it and put hClipObj in the cache for delayed deletion.
1742 */
1743 DWORD cb = GlobalSize(hClipObj);
1744 ulPMData = (ULONG)clipboardAllocPMBuffer(cb + (fHeader ? sizeof(CLIPHEADER) : 0));
1745 if (!ulPMData)
1746 {
1747 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1748 GlobalUnlock(hClipObj);
1749 dprintf(("USER32: SetClipboardData: returns NULL (shared alloc failed)\n"));
1750 return NULL;
1751 }
1752 if (fHeader)
1753 {
1754 PCLIPHEADER pClip = (PCLIPHEADER)(void*)ulPMData;
1755 memcpy(pClip->achMagic, CLIPHEADER_MAGIC, sizeof(CLIPHEADER_MAGIC));
1756 pClip->cbData = cb;
1757 pClip->uFormat = uFormat;
1758 memcpy((void*)(ulPMData + sizeof(CLIPHEADER)), pv, cb);
1759 }
1760 else
1761 memcpy((void*)ulPMData, pv, cb);
1762 GlobalUnlock(hClipObj);
1763 flPMData = OSLIB_CFI_POINTER;
1764
1765 /* Allocate a cache node. */
1766 if (!clipboardCacheAllocGlobalMem(uFormat, hClipObj, &pLocalClip))
1767 DebugAssertFailed(("out of memory"));
1768 }
1769 else
1770 { /*
1771 * Handle of some other kind?
1772 * Check if it's supposed to be a pointer.
1773 */
1774 if (flPMData)
1775 { /* it's a predefined format which is supposed to be a global memory handle. */
1776 SetLastError(ERROR_INVALID_PARAMETER); /** @todo check this last error */
1777 DebugAssertFailed(("expected GlobalAlloc handle, got %#x!! format=%d (%s)\n",
1778 hClipObj, uFormat, dbgGetFormatName(uFormat))); /* (for application debugging.) */
1779 dprintf(("USER32: SetClipboardData: returns NULL (bad global handle)\n"));
1780 return NULL;
1781 }
1782
1783 /* some kind of handle, this might not work to well... */
1784 flPMData = OSLIB_CFI_HANDLE;
1785 dprintf(("USER32: SetClipboardData: Warning: format %d data %#x is not a Global memory handle!!!\n",
1786 uFormat, hClipObj));
1787 }
1788 }
1789 else
1790 {
1791 /*
1792 * To be rendered.
1793 */
1794 if (!flPMData)
1795 flPMData = OSLIB_CFI_POINTER; /* must be set to something, and pointer is a safe bet. */
1796 }
1797 break;
1798 }
1799
1800 /*
1801 * Put it onto the PM clipboard.
1802 */
1803 dprintf2(("calling OSLibWinSetClipbrdData(%#x, %#x, %d, %#x)\n", GetThreadHAB(), ulPMData, ulPMFormat, flPMData));
1804 if (!OSLibWinSetClipbrdData(GetThreadHAB(), ulPMData, ulPMFormat, flPMData))
1805 {
1806 /*
1807 * Failed!
1808 */
1809 if ((OSLibWinGetLastError() & 0xffff) == OSLIB_PMERR_CALL_FROM_WRONG_THREAD)
1810 SetLastError(ERROR_CLIPBOARD_NOT_OPEN);
1811 else
1812 DebugAssertFailed(("OSLibWinSetClipbrdData(%#x, %#x, %d, %#x) failed last error=%d\n",
1813 GetThreadHAB(), ulPMData, ulPMFormat, flPMData, OSLibWinGetLastError()));
1814
1815 /* cleanup */
1816 if ((flPMData & OSLIB_CFI_POINTER) && ulPMData)
1817 OSLibDosFreeMem((void*)ulPMData);
1818 else
1819 switch (uFormat)
1820 {
1821 case CF_BITMAP:
1822 case CF_DSPBITMAP:
1823 OSLibClipboardPMBitmapDelete(ulPMData);
1824 break;
1825 case CF_PALETTE:
1826 OSLibClipboardPMPaletteDelete(ulPMData);
1827 break;
1828 }
1829
1830 if (pLocalClip)
1831 free(pLocalClip); /* Do not free the data suplied! */
1832
1833 dprintf(("USER32: SetClipboardData: returns NULL (set clipboard failed)\n"));
1834 return NULL;
1835 }
1836
1837 /*
1838 * Success!
1839 */
1840 /* update globals */
1841 gfClipboardChanged = TRUE;
1842 switch (uFormat)
1843 {
1844 case CF_TEXT:
1845 case CF_OEMTEXT:
1846 case CF_UNICODETEXT:
1847 gfClipboardChangedText = TRUE;
1848 break;
1849 }
1850
1851 /* insert node into cache if required. */
1852 if (pLocalClip)
1853 hClipObj = clipboardCacheInsertNode(pLocalClip);
1854
1855 dprintf(("USER32: SetClipboardData: returns %#x\n", hClipObj));
1856 return hClipObj;
1857}
1858
1859
1860/**
1861 * Gets a specific form of the clipboard if it's there.
1862 *
1863 * @returns handle to clipboard data on success.
1864 * @returns NULL on failure. Last error may be set, depends on the failure.
1865 * @param uFormat The clipboard format to get off the clipboard.
1866 * @status partially implemented.
1867 * @author knut st. osmundsen <bird-srcspam@anduin.net>
1868 * @remark we don't like metafiles at the present.
1869 * @remark we never return the same hMem for the same data, this is mentioned as a @todo in the code.
1870 */
1871HANDLE WIN32API GetClipboardData(UINT uFormat)
1872{
1873 dprintf(("USER32: GetClipboardData: uFormat=%u (%s)\n", uFormat, dbgGetFormatName(uFormat)));
1874
1875 /*
1876 * Validate that the thread have opened the clipboard.
1877 */
1878 if (!clipboardIsRWOwner())
1879 {
1880 SetLastError(ERROR_CLIPBOARD_NOT_OPEN);
1881 dprintf(("USER32: GetClipboardData: returns NULL (no openclipboard)\n"));
1882 return NULL;
1883 }
1884
1885 /*
1886 * Validate and translate the format number.
1887 */
1888 ULONG ulPMFormat = clipboardOdinToPMFormat(uFormat);
1889 DebugAssert(!uFormat || ulPMFormat > 0, ("failed to convert odin format %d to PM!!!\n", uFormat));
1890 if (ulPMFormat == 0)
1891 {
1892 //no last error?
1893 dprintf(("USER32: GetClipboardData: returns NULL (invalid format!!!)\n"));
1894 return NULL;
1895 }
1896
1897 /*
1898 * We need to synthesize formats in case OS/2 were the one
1899 * which put stuff on the clipboard.
1900 */
1901 if (!gfClipboardChanged)
1902 clipboardSynthesize(gfClipboardChangedText);
1903
1904 /*
1905 * Get the data.
1906 */
1907 HANDLE hab = GetThreadHAB();
1908 ULONG ulPMInfo;
1909 if (!OSLibWinQueryClipbrdFmtInfo(hab, ulPMFormat, &ulPMInfo))
1910 {
1911 //no last error?
1912 dprintf(("USER32: GetClipboardData: returns NULL (format not present)\n"));
1913 return NULL;
1914 }
1915 ULONG ulPMData = OSLibWinQueryClipbrdData(hab, ulPMFormat);
1916 if (!ulPMData)
1917 {
1918 //no last error?
1919 dprintf(("USER32: GetClipboardData: returns NULL (format not present)\n"));
1920 return NULL;
1921 }
1922
1923 /*
1924 * Allocate local copies of the data like Odin expects.
1925 *
1926 * In this process we'll synthesize formats and convert
1927 * from OS/2 PM formats to Odin formats.
1928 */
1929 /* dummy handle? */
1930 if ( (ulPMInfo & (OSLIB_CFI_HANDLE | OSLIB_CFI_POINTER | OSLIB_CFI_OWNERDISPLAY | OSLIB_CFI_OWNERFREE))
1931 == OSLIB_CFI_HANDLE
1932 && ulPMData == DUMMY_HANDLE)
1933 { /* synthesized */
1934 /** @todo check if we've done this operation on this data before. */
1935 HANDLE hRet;
1936 switch (uFormat)
1937 {
1938 case CF_TEXT:
1939 case CF_UNICODETEXT:
1940 case CF_OEMTEXT:
1941 hRet = clipboardSynthesizeText(uFormat);
1942 break;
1943
1944 case CF_LOCALE:
1945 hRet = clipboardSynthesizeLocale(uFormat);
1946 break;
1947
1948 case CF_BITMAP:
1949 hRet = clipboardSynthesizeBitmap(uFormat);
1950 break;
1951
1952 case CF_DIB:
1953 case CF_DIBV5:
1954 hRet = clipboardSynthesizeDIB(uFormat);
1955 break;
1956
1957 #if 0 // not implemented yet.
1958 case CF_PALETTE:
1959 hRet = clipboardSynthesizePalette(uFormat);
1960 break;
1961
1962 case CF_METAFILEPICT:
1963 hRet = clipboardSynthesizeMetaFile(uFormat);
1964 break;
1965 case CF_ENHMETAFILE:
1966 hRet = clipboardSynthesizeEnhMetaFile(uFormat);
1967 break;
1968 #endif
1969
1970 default:
1971 DebugAssertFailed(("Format %d doesn't do dummy handles!\n", uFormat));
1972 dprintf(("USER32: GetClipboardData: returns NULL (internal error!!!)\n"));
1973 return NULL;
1974 }
1975 dprintf(("USER32: GetClipboardData: returns %#x (synthesized)\n", hRet));
1976 return hRet;
1977 }
1978 else if (ulPMInfo & OSLIB_CFI_POINTER)
1979 { /* pointers: text */
1980 /* Sanity check. */
1981 switch (uFormat)
1982 {
1983 case CF_BITMAP:
1984 case CF_DSPBITMAP:
1985 case CF_PALETTE:
1986 dprintf(("USER32: GetClipboardData: return NULL (format/data mismatch)\n"));
1987 return NULL;
1988
1989 case CF_ENHMETAFILE:
1990 case CF_DSPENHMETAFILE:
1991 case CF_METAFILEPICT:
1992 case CF_DSPMETAFILEPICT:
1993 DebugAssertFailed(("Metafile support isn't enabled\n"));
1994 return NULL;
1995 }
1996
1997 /** @todo check if we've done this operation on this data before. */
1998
1999 /*
2000 * Duplicate the data raw in a GlobalAlloc'ed block local to the calling process.
2001 */
2002 /* Figure out the size of the data */
2003 ULONG cbOdin;
2004 void *pvOdin;
2005 if (uFormat != CF_TEXT && uFormat != CF_BITMAP && uFormat != CF_PALETTE
2006 && !memcmp(((PCLIPHEADER)ulPMData)->achMagic, CLIPHEADER_MAGIC, sizeof(CLIPHEADER_MAGIC)))
2007 { /* Have Odin header */
2008 PCLIPHEADER pClip = (PCLIPHEADER)ulPMData;
2009 DebugAssert(pClip->uFormat == uFormat, ("Format mismatch %d != %d\n", pClip->uFormat, uFormat));
2010 cbOdin = pClip->cbData;
2011 pvOdin = (void*)(pClip + 1);
2012 }
2013 else
2014 {
2015 DebugAssert(uFormat == CF_TEXT || uFormat == CF_BITMAP || uFormat == CF_PALETTE,
2016 ("%d should have a header!!!\n", uFormat));
2017 pvOdin = (void*)ulPMData;
2018 ULONG cb = clipboardGetPMDataSize(pvOdin);
2019 if (!cb)
2020 {
2021 dprintf(("USER32: GetClipboardData: return NULL (cannot determin size of data)\n"));
2022 return NULL;
2023 }
2024
2025 /* find the size of the odin data. */
2026 cbOdin = cb;
2027 switch (uFormat)
2028 {
2029 case CF_TEXT:
2030 cbOdin = clipboardTextCalcSize(pvOdin, cb);
2031 break;
2032 }
2033 }
2034
2035 /* allocate object. */
2036 PCLIPLOCALDATA pLocalClip;
2037 HANDLE hMem = clipboardCacheAllocGlobalDup(uFormat, pvOdin, cbOdin, &pLocalClip);
2038 if (!hMem)
2039 {
2040 dprintf(("USER32: GetClipboardData: returns NULL (GlobalAlloc(,%d) failed)\n", cbOdin));
2041 return NULL;
2042 }
2043
2044 /* insert cache object. */
2045 hMem = clipboardCacheInsertNode(pLocalClip);
2046
2047 dprintf(("USER32: GetClipboardData: return %#x (%d bytes)\n", hMem, cbOdin));
2048 return hMem;
2049 }
2050 else if (ulPMInfo & OSLIB_CFI_HANDLE)
2051 { /* handles: palette or bitmap */
2052 HANDLE hGDI;
2053 switch (uFormat)
2054 {
2055 case CF_BITMAP:
2056 case CF_DSPBITMAP:
2057 hGDI = O32_CreateBitmapFromPMHandle((HBITMAP)ulPMData);
2058 break;
2059
2060 case CF_PALETTE:
2061 hGDI = O32_CreateBitmapFromPMHandle((HPALETTE)ulPMData);
2062 break;
2063
2064 /** @todo make cases for the other which are defined as handles. */
2065 /* (for now we assume that everything else is Odin handles.) */
2066 default:
2067 dprintf(("USER32: GetClipboardData: returns NULL (funny stuff on clipboard)\n"));
2068 return (HANDLE)ulPMData;
2069 }
2070
2071 /* allocate and insert cache node. */
2072 PCLIPLOCALDATA pLocalClip;
2073 if (clipboardCacheAllocGDI(uFormat, hGDI, &pLocalClip))
2074 hGDI = clipboardCacheInsertNode(pLocalClip);
2075
2076 dprintf(("USER32: GetClipboardData: returns %#x (translated OS/2 handle)\n", hGDI));
2077 return hGDI;
2078 }
2079 else
2080 {
2081 DebugAssertFailed(("Something is on the clipboard without any understandable attributes!! ulInfo=%#x ulPMData=%#x\n",
2082 ulPMInfo, ulPMData));
2083 dprintf(("USER32: GetClipboardData: returns NULL (funny stuff on clipboard)\n"));
2084 return NULL;
2085 }
2086}
2087
2088
2089/**
2090 * Enumerate clipboard formats.
2091 *
2092 * Must be RW owner of clipboard (i.e. OpenClipboard()).
2093 *
2094 * @returns next clipboard format.
2095 * @returns 0 if no more formats in the clipboard.
2096 * @param uFormat Current format. Use 0 for the starting
2097 * the enumeration.
2098 * @status completely implemented.
2099 * @author knut st. osmundsen <bird-srcspam@anduin.net>
2100 */
2101UINT WIN32API EnumClipboardFormats(UINT uFormat)
2102{
2103 dprintf(("USER32: EnumClipboardFormats: uFormat=%d (%s)\n", uFormat,
2104 uFormat ? dbgGetFormatName(uFormat) : "start enum"));
2105
2106 /*
2107 * Validate that the thread have opened the clipboard.
2108 */
2109 if (!clipboardIsRWOwner())
2110 {
2111 SetLastError(ERROR_CLIPBOARD_NOT_OPEN);
2112 dprintf(("USER32: EnumClipboardFormats: returns 0 (no openclipboard)\n"));
2113 return 0;
2114 }
2115
2116 UINT rc = clipboardEnumClipboardFormats(uFormat);
2117 dprintf(("USER32: EnumClipboardFormats: returns %d\n"));
2118 return rc;
2119}
2120
2121
2122/**
2123 * Internal worker for EnumClipboardFormats.
2124 * Also used by CountClipboardFormats();
2125 *
2126 * @returns next clipboard format.
2127 * @returns 0 if no more formats in the clipboard.
2128 * @param uFormat Current format. Use 0 for the starting
2129 * the enumeration.
2130 * @status completely implemented.
2131 * @author knut st. osmundsen <bird-srcspam@anduin.net>
2132 */
2133UINT clipboardEnumClipboardFormats(UINT uFormat)
2134{
2135 dprintf(("USER32: clipboardEnumClipboardFormats: uFormat=%d (%s)\n", uFormat,
2136 uFormat ? dbgGetFormatName(uFormat) : "start enum"));
2137
2138 /*
2139 * Validate/translate input.
2140 */
2141 ULONG ulPMFormat = 0;
2142 if (uFormat)
2143 {
2144 ulPMFormat = clipboardOdinToPMFormat(uFormat);
2145 if (!ulPMFormat)
2146 {
2147 dprintf(("USER32: clipboardEnumClipboardFormats: invalid uFormat(=%u)!!\n", uFormat));
2148 return 0;
2149 }
2150 }
2151
2152 /*
2153 * Enumerate next OS/2 format.
2154 */
2155 HANDLE hab = GetThreadHAB();
2156 while ((ulPMFormat = OSLibWinEnumClipbrdFmts(GetThreadHAB(), ulPMFormat)) != 0)
2157 {
2158 UINT uNextFormat = clipboardPMToOdinFormat(ulPMFormat);
2159 if (uNextFormat)
2160 {
2161 dprintf(("USER32: clipboardEnumClipboardFormats: returning %u (%s)\n", uNextFormat, dbgGetFormatName(uNextFormat)));
2162 return uNextFormat;
2163 }
2164 dprintf2(("USER32: clipboardEnumClipboardFormats: skipping OS/2 only format %lu\n", ulPMFormat));
2165 }
2166
2167 /*
2168 * Since we cannot know what non Odin applications are doing,
2169 * we will have to check for synthesized formats here.
2170 *
2171 * We're not doing this if we're the clipboard owner and have changed
2172 * the clipboard in any way. This is to not synthesize stuff to early
2173 * compared to W2K. See GetClipboardFormat.
2174 */
2175 if (uFormat && (!clipboardIsRWOwner() || !gfClipboardChanged))
2176 {
2177 static UINT auSeq[] = { CF_TEXT, CF_UNICODETEXT, CF_OEMTEXT, CF_DIB, CF_DIBV5, CF_BITMAP, 0 }; /** @todo complete and check this. */
2178 ULONG flInfo;
2179
2180 /* find starting index */
2181 int i = 0;
2182 if (!clipboardIsAvailable(uFormat))
2183 {
2184 for (i = 0; auSeq[i]; i++)
2185 if (auSeq[i] == uFormat)
2186 {
2187 i++;
2188 break;
2189 }
2190 }
2191
2192 /*
2193 * Find the next synthesized format.
2194 */
2195 while ((uFormat = auSeq[i]) != 0)
2196 {
2197 if (clipboardShouldBeSynthesized(uFormat))
2198 { /* not there, potentially synthesized format. */
2199 dprintf(("USER32: clipboardEnumClipboardFormats: returning %u (%s)\n", uFormat, dbgGetFormatName(uFormat)));
2200 return uFormat;
2201 }
2202 /* next */
2203 i++;
2204 }
2205
2206 }
2207
2208 dprintf(("USER32: clipboardEnumClipboardFormats: returning 0\n"));
2209 return 0;
2210}
2211
2212
2213
2214/**
2215 * Closes the clipboard.
2216 *
2217 * @returns Success indicator.
2218 * @status completely implemented.
2219 * @author knut st. osmundsen <bird-srcspam@anduin.net>
2220 */
2221BOOL WIN32API CloseClipboard(void)
2222{
2223 dprintf(("USER32: CloseClipboard"));
2224
2225 /*
2226 * Check that we're owning the clipboard.
2227 */
2228 if (!clipboardIsRWOwner())
2229 {
2230 SetLastError(ERROR_CLIPBOARD_NOT_OPEN);
2231 dprintf(("USER32: CloseClipboard returns FALSE (clipboard not open!!)\n"));
2232 return FALSE;
2233 }
2234
2235 HAB hab = GetThreadHAB();
2236
2237 /*
2238 * Synthesize formats.
2239 */
2240 if (gfClipboardChanged)
2241 clipboardSynthesize(gfClipboardChangedText);
2242
2243 /*
2244 * Actually close it.
2245 */
2246 if (gtidOpenClipboardThreadId == GetCurrentThreadId()) /* paranoia */
2247 gtidOpenClipboardThreadId = 0;
2248 BOOL fRc = OSLibWinCloseClipbrd(hab);
2249 DebugAssert(fRc, ("WinCloseClipbrd failed!!! lasterr=%#x\n", OSLibWinGetLastError()));
2250 dprintf(("USER32: CloseClipboard: returning %s\n", fRc ? "TRUE" : "FALSE"));
2251 return fRc;
2252}
2253
2254
2255/**
2256 * Makes dummies for synthesized formats.
2257 *
2258 * This is called by CloseClipboard() and GetClipboardData(). The latter
2259 * because Odin32 might not have been the one to put data on the clipboard.
2260 */
2261void clipboardSynthesize(BOOL fHaveAddedText)
2262{
2263 dprintf2(("USER32: clipboardSynthesize: fHaveAddedText=%d\n", fHaveAddedText));
2264 /* text */
2265 BOOL fCF_OEMTEXT = clipboardIsAvailable(CF_OEMTEXT);
2266 BOOL fCF_UNICODETEXT = clipboardIsAvailable(CF_UNICODETEXT);
2267 BOOL fCF_TEXT = clipboardIsAvailable(CF_TEXT);
2268 if (fCF_TEXT || fCF_UNICODETEXT || fCF_OEMTEXT)
2269 {
2270 /*
2271 * Add the CF_LOCALE if we have modified the clipboard.
2272 */
2273 if (!clipboardIsAvailable(CF_LOCALE))
2274 {
2275 if (!fHaveAddedText)
2276 clipboardAddPMDummy(CF_LOCALE);
2277 else
2278 {
2279 LCID lcid = GetThreadLocale();
2280 clipboardAddPMHeader(CF_LOCALE, &lcid, sizeof(lcid));
2281 }
2282 }
2283
2284 /*
2285 * Add dummies.
2286 */
2287 if (!fCF_TEXT)
2288 {
2289 /* CT_TEXT must be synthesized so PM can see the text. */
2290 HANDLE hMem = clipboardSynthesizeText(CF_TEXT);
2291 if (hMem)
2292 {
2293 void *pv = GlobalLock(hMem);
2294 clipboardAddPM(CF_TEXT, pv, GlobalSize(hMem));
2295 GlobalUnlock(hMem);
2296 }
2297 }
2298 if (!fCF_UNICODETEXT)
2299 clipboardAddPMDummy(CF_UNICODETEXT);
2300 if (!fCF_OEMTEXT)
2301 clipboardAddPMDummy(CF_OEMTEXT);
2302 }
2303 else
2304 {
2305 /* DIBs */
2306 BOOL fCF_DIBV5 = clipboardIsAvailable(CF_DIBV5);
2307 BOOL fCF_DIB = clipboardIsAvailable(CF_DIB);
2308 BOOL fCF_BITMAP = clipboardIsAvailable(CF_BITMAP);
2309 if (fCF_BITMAP || fCF_DIB || fCF_DIBV5)
2310 {
2311 /*
2312 * Add dummies.
2313 */
2314 if (!fCF_BITMAP)
2315 { /* CT_BITMAP must be synthesized so PM can understand it. */
2316 HANDLE hbm = clipboardSynthesizeBitmap(CF_BITMAP);
2317 if (hbm)
2318 {
2319 if (!SetClipboardData(CF_BITMAP, hbm))
2320 DebugAssertFailed(("SetClipboardData for synthesized bitmap %#x failed!\n", hbm));
2321 }
2322 }
2323 if (!fCF_DIB)
2324 clipboardAddPMDummy(CF_DIB);
2325 if (!fCF_DIBV5)
2326 clipboardAddPMDummy(CF_DIBV5);
2327 }
2328 else
2329 {
2330 /** @todo metafiles and palettes */
2331 }
2332 }
2333
2334}
2335
2336
2337
2338/**
2339 * Checks whether or not a given format will be synthesized by GetClipboardData
2340 * in the current clipboard state.
2341 *
2342 * @returns TRUE if it will be synthesized, FALSE if not.
2343 * @param uFormat Odin format number
2344 */
2345BOOL clipboardShouldBeSynthesized(UINT uFormat)
2346{
2347 /* Should be, that means to be done in GetClipboardData. */
2348 if (clipboardIsAvailable(uFormat))
2349 return FALSE;
2350
2351 switch (uFormat)
2352 {
2353 case CF_TEXT:
2354 return clipboardIsAvailable(CF_OEMTEXT)
2355 || clipboardIsAvailable(CF_UNICODETEXT);
2356 case CF_OEMTEXT:
2357 return clipboardIsAvailable(CF_TEXT)
2358 || clipboardIsAvailable(CF_UNICODETEXT);
2359 case CF_UNICODETEXT:
2360 return clipboardIsAvailable(CF_TEXT)
2361 || clipboardIsAvailable(CF_OEMTEXT);
2362
2363 case CF_LOCALE:
2364 return clipboardIsAvailable(CF_TEXT)
2365 || clipboardIsAvailable(CF_OEMTEXT)
2366 || clipboardIsAvailable(CF_UNICODETEXT);
2367
2368 case CF_BITMAP:
2369 return clipboardIsAvailable(CF_DIB)
2370 || clipboardIsAvailable(CF_DIBV5);
2371 case CF_DIB:
2372 return clipboardIsAvailable(CF_BITMAP)
2373 || clipboardIsAvailable(CF_DIBV5);
2374 case CF_DIBV5:
2375 return clipboardIsAvailable(CF_BITMAP)
2376 || clipboardIsAvailable(CF_DIB);
2377
2378 #if 0
2379 case CF_PALETTE:
2380 return clipboardIsAvailable(CF_BITMAP)
2381 || clipboardIsAvailable(CF_DIB)
2382 || clipboardIsAvailable(CF_DIBV5);
2383 /* metafiles */
2384 #endif
2385
2386 default:
2387 return FALSE;
2388 }
2389}
2390
2391
2392/**
2393 * Synthesizes the given text format from the available text format
2394 * on the clipboard.
2395 *
2396 * @returns Handle to global memory object containing the synthesized text.
2397 * @returns NULL on failure.
2398 * @param uFormat Format to synthesize.
2399 */
2400HANDLE clipboardSynthesizeText(UINT uFormat)
2401{
2402 dprintf2(("USER32: clipboardSynthesizeText: uFormat=%d (%s)\n", uFormat, dbgGetFormatName(uFormat)));
2403 DebugAssert(uFormat == CF_TEXT || uFormat == CF_OEMTEXT || uFormat == CF_UNICODETEXT,
2404 ("invalid format %d\n", uFormat));
2405
2406 /*
2407 * Check what's available.
2408 */
2409 BOOL fCF_TEXT = clipboardIsAvailableReal(CF_TEXT);
2410 BOOL fCF_UNICODETEXT= clipboardIsAvailableReal(CF_UNICODETEXT);
2411 BOOL fCF_OEMTEXT = clipboardIsAvailableReal(CF_OEMTEXT);
2412 DebugAssert(fCF_TEXT || fCF_UNICODETEXT || fCF_OEMTEXT, ("no text is available!!!"));
2413
2414 /*
2415 * Figure out format to convert from.
2416 */
2417 UINT uSrcFormat;
2418 switch (uFormat)
2419 {
2420 case CF_TEXT:
2421 uSrcFormat = fCF_UNICODETEXT ? CF_UNICODETEXT : fCF_OEMTEXT ? CF_OEMTEXT : 0;
2422 break;
2423 case CF_OEMTEXT:
2424 uSrcFormat = fCF_UNICODETEXT ? CF_UNICODETEXT : fCF_TEXT ? CF_TEXT : 0;
2425 break;
2426 case CF_UNICODETEXT:
2427 uSrcFormat = fCF_TEXT ? CF_TEXT : fCF_OEMTEXT ? CF_OEMTEXT : 0;
2428 break;
2429 }
2430 dprintf2(("USER32: clipboardSynthesizeText: uSrcFormat=%d (%s)\n", uSrcFormat, dbgGetFormatName(uSrcFormat)));
2431
2432 /*
2433 * Get the data.
2434 */
2435 HANDLE hRet = NULL;
2436 HANDLE hMem = GetClipboardData(uSrcFormat);
2437 if (hMem)
2438 {
2439 const void *pv = GlobalLock(hMem);
2440 if (pv)
2441 {
2442 DWORD cb = GlobalSize(hMem);
2443
2444 /*
2445 * determin size of converted text
2446 */
2447 unsigned cbRet;
2448 unsigned uCp;
2449 switch (uSrcFormat)
2450 {
2451 case CF_TEXT:
2452 case CF_OEMTEXT:
2453 cbRet = strlen((char*)pv) + 1; /* OEM better not bet multibyte/dbcs. */
2454 if (uFormat == CF_UNICODETEXT)
2455 cbRet *= sizeof(WCHAR);
2456 break;
2457 case CF_UNICODETEXT:
2458 uCp = clipboardGetCodepage(uFormat == CF_TEXT ? LOCALE_IDEFAULTANSICODEPAGE : LOCALE_IDEFAULTCODEPAGE);
2459 cbRet = WideCharToMultiByte(uCp, 0, (LPCWSTR)pv, cb / sizeof(WCHAR), NULL, 0, NULL, NULL);
2460 break;
2461 }
2462
2463 /*
2464 * Allocate memory.
2465 */
2466 PCLIPLOCALDATA pLocalClip;
2467 hRet = clipboardCacheAllocGlobalAlloc(uFormat, cbRet, &pLocalClip);
2468 if (hRet)
2469 {
2470 void * pvRet = GlobalLock(hRet);
2471
2472 /*
2473 * Do the convertion.
2474 */
2475 switch (uFormat)
2476 {
2477 case CF_TEXT:
2478 switch (uSrcFormat)
2479 {
2480 case CF_OEMTEXT:
2481 OemToCharBuffA((LPCSTR)pv, (LPSTR)pvRet, cbRet);
2482 break;
2483 case CF_UNICODETEXT:
2484 WideCharToMultiByte(uCp, 0, (LPCWSTR)pv, cb / sizeof(WCHAR), (LPSTR)pvRet, cb, NULL, NULL);
2485 break;
2486 }
2487 break;
2488
2489 case CF_OEMTEXT:
2490 switch (uSrcFormat)
2491 {
2492 case CF_TEXT:
2493 CharToOemBuffA((LPCSTR)pv, (LPSTR)pvRet, cbRet);
2494 break;
2495 case CF_UNICODETEXT:
2496 WideCharToMultiByte(uCp, 0, (LPCWSTR)pv, cb / sizeof(WCHAR), (LPSTR)pvRet, cb, NULL, NULL);
2497 break;
2498 }
2499 break;
2500
2501 case CF_UNICODETEXT:
2502 uCp = clipboardGetCodepage(uFormat == CF_TEXT ? LOCALE_IDEFAULTANSICODEPAGE : LOCALE_IDEFAULTCODEPAGE);
2503 MultiByteToWideChar(uCp, MB_PRECOMPOSED, (LPCSTR)pv, cb, (LPWSTR)pvRet, cbRet / sizeof(WCHAR));
2504 break;
2505 }
2506 GlobalUnlock(hRet);
2507
2508 hRet = clipboardCacheInsertNode(pLocalClip);
2509 }
2510 GlobalUnlock(hMem);
2511 }
2512 else
2513 DebugAssertFailed(("Failed to lock object %#x format %d!!!\n", hMem, uSrcFormat));
2514 }
2515 else
2516 DebugAssertFailed(("now why isn't %d on the clipboard????\n", uSrcFormat));
2517
2518 return hRet;
2519}
2520
2521
2522/**
2523 * Synthesizes a locale structure.
2524 *
2525 * @returns Handle to global memory object containing the synthesized locale.
2526 * @returns NULL on failure.
2527 * @param uFormat Format to synthesize.
2528 */
2529HANDLE clipboardSynthesizeLocale(UINT uFormat)
2530{
2531 dprintf2(("USER32: clipboardSynthesizeLocale: uFormat=%d (%s)\n", uFormat, dbgGetFormatName(uFormat)));
2532 DebugAssert(uFormat == CF_LOCALE, ("invalid format %d\n", uFormat));
2533
2534 /*
2535 * Guess an appropriate Locale.
2536 */
2537 LCID lcid = GetSystemDefaultLCID();
2538
2539 /*
2540 * Allocate a block in the 'cache'.
2541 */
2542 PCLIPLOCALDATA pLocalClip;
2543 HANDLE hMem = clipboardCacheAllocGlobalDup(uFormat, &lcid, sizeof(LCID), &pLocalClip);
2544 if (!hMem)
2545 return NULL;
2546
2547 /* insert */
2548 hMem = clipboardCacheInsertNode(pLocalClip);
2549
2550 dprintf2(("USER32: clipboardSynthesizeLocale: returning %#x (lcid=%#x)\n", hMem, lcid));
2551 return hMem;
2552}
2553
2554
2555/**
2556 * Synthesizes a bitmap from the avilable DIB format on the clipboard
2557 *
2558 * @returns Handle to GDI bitmap.
2559 * @returns NULL on failure.
2560 * @param uFormat Format to synthesize. (CF_BITMAP)
2561 */
2562HANDLE clipboardSynthesizeBitmap(UINT uFormat)
2563{
2564 dprintf2(("USER32: clipboardSynthesizeBitmap: uFormat=%d (%s)\n", uFormat, dbgGetFormatName(uFormat)));
2565 DebugAssert(uFormat == CF_BITMAP, ("invalid format %d\n", uFormat));
2566
2567 /*
2568 * Find DIB format to convert from.
2569 */
2570 UINT uSrcFormat = CF_DIB;
2571 if (!clipboardIsAvailableReal(uSrcFormat))
2572 {
2573 uSrcFormat = CF_DIBV5;
2574 if (!clipboardIsAvailableReal(uSrcFormat))
2575 {
2576 DebugAssertFailed(("no DIB data avilable!\n"));
2577 return NULL;
2578 }
2579 }
2580 dprintf2(("USER32: clipboardSynthesizeBitmap: uSrcFormat=%d (%s)\n", uSrcFormat, dbgGetFormatName(uSrcFormat)));
2581
2582 /*
2583 * Get the data.
2584 */
2585 PCLIPHEADER pClip = (PCLIPHEADER)OSLibWinQueryClipbrdData(GetThreadHAB(), clipboardOdinToPMFormat(uSrcFormat));
2586 if ( !pClip
2587 || pClip == (PCLIPHEADER)DUMMY_HANDLE
2588 || memcmp(pClip->achMagic, CLIPHEADER_MAGIC, sizeof(CLIPHEADER_MAGIC)))
2589 {
2590 DebugAssertFailed(("invalid clipboard data for format %d\n", uSrcFormat));
2591 return NULL;
2592 }
2593
2594 /*
2595 * Check the content a little bit.
2596 */
2597 union u
2598 {
2599 PVOID pv;
2600 char * pch;
2601 LPBITMAPINFOHEADER pHdr;
2602 LPBITMAPV5HEADER pHdrV5;
2603 } u = { (void*)(pClip + 1) };
2604 if (u.pHdr->biSize < sizeof(BITMAPCOREHEADER) || u.pHdr->biSize > sizeof(BITMAPV5HEADER))
2605 {
2606 DebugAssertFailed(("invalid clipboard DIB data: biSize=%d\n", u.pHdr->biSize));
2607 return NULL;
2608 }
2609 switch (u.pHdr->biBitCount)
2610 {
2611 case 1:
2612 case 2:
2613 case 4:
2614 case 8:
2615 case 16:
2616 case 24:
2617 case 32:
2618 break;
2619 default:
2620 DebugAssertFailed(("invalid clipboard DIB data: biBitCount=%d\n", u.pHdr->biBitCount));
2621 return NULL;
2622 }
2623 if ( u.pHdrV5->bV5Size == sizeof(BITMAPV5HEADER)
2624 && u.pHdrV5->bV5CSType != LCS_sRGB)
2625 {
2626 DebugAssertFailed(("unexpected clipboard DIBV5 data: bV5CSType=%#x\n", u.pHdrV5->bV5CSType));
2627 return NULL;
2628 }
2629 /* todo more checking. */
2630
2631 /*
2632 * Calc start of bits.
2633 */
2634 void *pvBits = (char*)u.pv + u.pHdr->biSize;
2635 if (u.pHdr->biBitCount <= 8)
2636 pvBits = (char*)pvBits + sizeof(RGBQUAD) * (1 << u.pHdr->biBitCount);
2637
2638 /*
2639 * Create the bitmap.
2640 */
2641 HBITMAP hbm;
2642 HDC hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
2643 if (hdc)
2644 {
2645 hbm = CreateDIBitmap(hdc, u.pHdr, CBM_INIT, pvBits, (PBITMAPINFO)u.pHdr, DIB_RGB_COLORS);
2646 if (hbm)
2647 {
2648 /* allocate and insert it into the cache. */
2649 PCLIPLOCALDATA pLocalClip;
2650 if (clipboardCacheAllocGDI(uFormat, hbm, &pLocalClip))
2651 hbm = clipboardCacheInsertNode(pLocalClip);
2652 dprintf(("synthesized bitmap %#x\n", hbm));
2653 }
2654 else
2655 DebugAssertFailed(("CreateBitmapIndirect failed\n"));
2656 DeleteDC(hdc);
2657 }
2658
2659 return hbm;
2660}
2661
2662/**
2663 * Synthesizes the given DIB format from the available DIB or bitmap
2664 * on the clipboard.
2665 *
2666 * @returns Handle to global memory object containing the synthesized DIB.
2667 * @returns NULL on failure.
2668 * @param uFormat Format to synthesize. (CF_BITMAP)
2669 */
2670HANDLE clipboardSynthesizeDIB(UINT uFormat)
2671{
2672 dprintf2(("USER32: clipboardSynthesizeDIB: uFormat=%d (%s)\n", uFormat, dbgGetFormatName(uFormat)));
2673 OSLIB_BITMAPINFOHEADER2 bih2;
2674 DebugAssert(uFormat == CF_DIB || uFormat == CF_DIBV5, ("invalid format %d\n", uFormat));
2675
2676 /*
2677 * Find convert format and calculate the size of the converted bitmap.
2678 */
2679 UINT uSrcFormat = CF_DIB;
2680 if (!clipboardIsAvailableReal(uSrcFormat))
2681 {
2682 uSrcFormat = CF_DIBV5;
2683 if (!clipboardIsAvailableReal(uSrcFormat))
2684 {
2685 uSrcFormat = CF_BITMAP;
2686 if (!clipboardIsAvailableReal(uSrcFormat))
2687 {
2688 DebugAssertFailed(("no bitmap or DIB available on the clipboard\n"));
2689 return NULL;
2690 }
2691 }
2692 }
2693 dprintf2(("USER32: clipboardSynthesizeDIB: uSrcFormat=%d (%s)\n", uSrcFormat, dbgGetFormatName(uSrcFormat)));
2694
2695 /*
2696 * Get the data.
2697 */
2698 void *pv = (void*)OSLibWinQueryClipbrdData(GetThreadHAB(), clipboardOdinToPMFormat(uSrcFormat));
2699 if ( !pv
2700 || pv == (void*)DUMMY_HANDLE
2701 || ( uSrcFormat != CF_BITMAP
2702 && memcmp(pv, CLIPHEADER_MAGIC, sizeof(CLIPHEADER_MAGIC))
2703 )
2704 )
2705 {
2706 DebugAssertFailed(("invalid clipboard data for format %d\n", uSrcFormat));
2707 return NULL;
2708 }
2709
2710
2711 /*
2712 * Do the conversion.
2713 */
2714 switch (uSrcFormat)
2715 {
2716 /*
2717 * Convert an OS/2 bitmap to a DIB or DIBV5.
2718 */
2719 case CF_BITMAP:
2720 {
2721 /* We're letting GPI do the major bit of the work actually. */
2722 HBITMAP hbm = O32_CreateBitmapFromPMHandle((HBITMAP)pv);
2723 if (!hbm)
2724 {
2725 DebugAssertFailed(("invalid OS/2 hbitmap %#x on clipboard\n", (unsigned)pv));
2726 return NULL;
2727 }
2728
2729 HANDLE hMem = NULL;
2730 HDC hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
2731 if (hdc)
2732 {
2733 SelectObject(hdc, hbm);
2734
2735 /*
2736 * Figure out the sizes.
2737 */
2738 unsigned cbTrgHeader = uFormat == CF_DIB ? sizeof(BITMAPINFOHEADER) : sizeof(BITMAPV5HEADER);
2739 BITMAPINFOHEADER hdr = {sizeof(BITMAPINFOHEADER), 0};
2740 if (GetDIBits(hdc, hbm, 0, 0, NULL, (PBITMAPINFO)&hdr, DIB_RGB_COLORS))
2741 { /* we've got the header now */
2742 unsigned cbTrgColorTable = 0;
2743 switch (hdr.biBitCount)
2744 {
2745 case 1:
2746 case 2:
2747 case 4:
2748 case 8:
2749 cbTrgColorTable = (1 << hdr.biBitCount) * sizeof(RGBQUAD);
2750 break;
2751 }
2752
2753 unsigned cbTrgBits = hdr.biSizeImage;
2754 if (!cbTrgBits)
2755 {
2756 cbTrgBits = ((hdr.biWidth * hdr.biBitCount + 31) >> 5) << 2;
2757 cbTrgBits *= abs(hdr.biHeight);
2758 }
2759
2760 unsigned cbTotal = cbTrgHeader + cbTrgColorTable + cbTrgBits;
2761
2762 /*
2763 * Allocate a cache object.
2764 */
2765 PCLIPLOCALDATA pLocalClip;
2766 hMem = clipboardCacheAllocGlobalAlloc(uFormat, cbTotal, &pLocalClip);
2767 if (hMem)
2768 {
2769 union u
2770 {
2771 PVOID pv;
2772 char * pch;
2773 LPBITMAPINFOHEADER pHdr;
2774 LPBITMAPV5HEADER pHdrV5;
2775 } uTrg;
2776 uTrg.pv = GlobalLock(hMem);
2777
2778 /*
2779 * Get the bitmap bits and pieces.
2780 */
2781 memcpy(uTrg.pv, &hdr, sizeof(hdr));
2782 if (GetDIBits(hdc, hbm, 0, hdr.biHeight,
2783 uTrg.pch + cbTrgHeader + cbTrgColorTable,
2784 (PBITMAPINFO)uTrg.pv,
2785 DIB_RGB_COLORS))
2786 {
2787 /* adjust the header+color table for CF_DIBV5 */
2788 #ifdef USE_DIBV5
2789 if (uFormat == CF_DIBV5)
2790 {
2791 if (cbTrgColorTable)
2792 memmove(uTrg.pch + sizeof(BITMAPV5HEADER), uTrg.pch + sizeof(hdr), cbTrgColorTable);
2793 memset(uTrg.pch + sizeof(hdr), 0, sizeof(BITMAPV5HEADER) - sizeof(hdr));
2794 uTrg.pHdrV5->bV5Size = sizeof(BITMAPV5HEADER);
2795 uTrg.pHdrV5->bV5CSType = LCS_sRGB;
2796 }
2797 #endif
2798 if (!uTrg.pHdr->biClrImportant)
2799 uTrg.pHdr->biClrImportant = uTrg.pHdr->biClrUsed;
2800
2801 DeleteDC(hdc);
2802 HANDLE hRet = clipboardCacheInsertNode(pLocalClip);
2803 dprintf2(("USER32: clipboardSynthesizeDIB: returning %#x\n", hRet));
2804 return hRet;
2805 }
2806 else
2807 DebugAssertFailed(("GetDIBits failed lasterr=%d\n", GetLastError()));
2808
2809 /* failure */
2810 clipboardCacheDeleteNode(pLocalClip);
2811 }
2812 else
2813 DebugAssertFailed(("GlobalAlloc failed lasterr=%d\n", GetLastError()));
2814 }
2815 else
2816 DebugAssertFailed(("GetDIBits (header) failed lasterr=%d\n", GetLastError()));
2817 DeleteDC(hdc);
2818 }
2819 else
2820 DebugAssertFailed(("CreateDCA failed lasterr=%d\n", GetLastError()));
2821 return NULL;
2822 }
2823
2824 /*
2825 * DIB <-> DIBV5: basically only header adjustments
2826 * (We do not yet support advanced DIBV5 formats.)
2827 */
2828 case CF_DIB:
2829 case CF_DIBV5:
2830 {
2831 union u
2832 {
2833 PVOID pv;
2834 char * pch;
2835 LPBITMAPINFOHEADER pHdr;
2836 LPBITMAPV5HEADER pHdrV5;
2837 } uSrc, uTrg;
2838 uSrc.pv = (char*)pv + sizeof(CLIPHEADER);
2839 unsigned cbSrc = ((PCLIPHEADER)pv)->cbData;
2840
2841 /*
2842 * Validate the bitmap data a little bit.
2843 */
2844 if (uSrc.pHdr->biSize < sizeof(BITMAPCOREHEADER) || uSrc.pHdr->biSize > sizeof(BITMAPV5HEADER))
2845 {
2846 DebugAssertFailed(("Unknown header size %d\n", uSrc.pHdr->biSize));
2847 return NULL;
2848 }
2849 switch (uSrc.pHdr->biBitCount)
2850 {
2851 case 1:
2852 case 2:
2853 case 4:
2854 case 8:
2855 case 16:
2856 case 24:
2857 case 32:
2858 break;
2859 default:
2860 DebugAssertFailed(("invalid clipboard DIB data: biBitCount=%d\n", uSrc.pHdr->biBitCount));
2861 return NULL;
2862 }
2863 if ( uSrc.pHdrV5->bV5Size == sizeof(BITMAPV5HEADER)
2864 && uSrc.pHdrV5->bV5CSType != LCS_sRGB)
2865 {
2866 DebugAssertFailed(("unexpected clipboard DIBV5 data: bV5CSType=%#x\n", uSrc.pHdrV5->bV5CSType));
2867 return NULL;
2868 }
2869
2870 /*
2871 * Figure out the size of the target bitmap and allocate memory for this.
2872 */
2873 unsigned cbTrgHeader = uFormat == CF_DIB ? sizeof(BITMAPINFOHEADER) : sizeof(BITMAPV5HEADER);
2874 unsigned cbTotal = cbSrc + (cbTrgHeader - uSrc.pHdr->biSize);
2875 PCLIPLOCALDATA pLocalClip;
2876 HANDLE hMem = clipboardCacheAllocGlobalAlloc(uFormat, cbTotal, &pLocalClip);
2877 if (!hMem)
2878 return NULL;
2879 uTrg.pv = GlobalLock(hMem);
2880
2881 /*
2882 * Convert the bitmap data.
2883 * Note that the source and target DIB data might be in the same format.
2884 */
2885 if (cbTrgHeader != uTrg.pHdr->biSize)
2886 {
2887 /** @todo Only a subset of DIB V5 bitmaps are supported, implement it fully all around Odin32. */
2888 switch (uFormat)
2889 {
2890 case CF_DIBV5:
2891 #ifdef USE_DIBV5
2892 memcpy(uTrg.pv, uSrc.pv, uSrc.pHdr->biSize);
2893 memset(uTrg.pch + uSrc.pHdr->biSize, 0, sizeof(BITMAPV5HEADER) - uSrc.pHdr->biSize);
2894 uTrg.pHdrV5->bV5Size = sizeof(BITMAPV5HEADER);
2895 uTrg.pHdrV5->bV5CSType = LCS_sRGB;
2896 memcpy(uTrg.pch + sizeof(BITMAPV5HEADER), uSrc.pch + uSrc.pHdr->biSize, cbSrc - uSrc.pHdr->biSize);
2897 break;
2898 #else
2899 //fallthru
2900 #endif
2901 case CF_DIB:
2902 memcpy(uTrg.pv, uSrc.pv, min(uSrc.pHdr->biSize, sizeof(BITMAPINFOHEADER)));
2903 if (uSrc.pHdr->biSize < sizeof(BITMAPINFOHEADER))
2904 memset(uTrg.pch + uSrc.pHdr->biSize, 0, sizeof(BITMAPINFOHEADER) - uSrc.pHdr->biSize);
2905 memcpy(uTrg.pch + sizeof(BITMAPINFOHEADER), uSrc.pch + uSrc.pHdr->biSize, cbSrc - uSrc.pHdr->biSize);
2906 break;
2907 }
2908 }
2909 GlobalUnlock(hMem);
2910 /* done */
2911 return hMem;
2912 }
2913 }
2914
2915 return NULL;
2916}
2917
2918#if 0 // not implemented yet
2919HANDLE clipboardSynthesizePalette(UINT uFormat)
2920{
2921 return NULL;
2922}
2923
2924HANDLE clipboardSynthesizeMetaFile(UINT uFormat)
2925{
2926 return NULL;
2927}
2928
2929HANDLE clipboardSynthesizeEnhMetaFile(UINT uFormat)
2930{
2931 return NULL;
2932}
2933#endif
2934
2935
2936/**
2937 * Get the length of a text on the clipboard.
2938 *
2939 * @returns up to cb.
2940 * @param pvData Data pointer.
2941 * @param cb Data size.
2942 */
2943unsigned clipboardTextCalcSize(void *pvData, unsigned cb)
2944{
2945 const char *psz = (const char*)pvData;
2946 const char *pszEnd = psz + cb;
2947 while (psz + 1 < pszEnd)
2948 {
2949 if (!*psz && !psz[1]) /* Check for two '\0' to keep out of dbcs trouble. */
2950 return psz - (char*)pvData + 1;
2951 psz++;
2952 }
2953 return cb;
2954}
2955
2956
2957/**
2958 * Gets the clipboad code page using the CF_LOCALE entry if present, if not
2959 * present the system default is used.
2960 *
2961 * @returns Codepage corresponding to uType.
2962 * @param uType Code page type.
2963 */
2964unsigned clipboardGetCodepage(UINT uType)
2965{
2966 /*
2967 * Find the LCID to use.
2968 */
2969 HANDLE hMem = GetClipboardData(CF_LOCALE);
2970 LCID lcid;
2971 LCID *plcid;
2972 if (hMem && (plcid = (LCID *)GlobalLock(hMem)) != NULL)
2973 {
2974 lcid = *plcid;
2975 GlobalUnlock(hMem);
2976 }
2977 else
2978 lcid = GetSystemDefaultLCID();
2979
2980 char szCp[6];
2981 if (GetLocaleInfoA(lcid, uType, szCp, sizeof(szCp)))
2982 return atoi(szCp);
2983
2984 switch (uType)
2985 {
2986 case LOCALE_IDEFAULTCODEPAGE : return CP_OEMCP;
2987 case LOCALE_IDEFAULTANSICODEPAGE: return CP_ACP;
2988 default : return CP_MACCP;
2989 }
2990}
2991
2992
2993/**
2994 * GlobalAllocs a block of memory for the cache initializing it from the
2995 * the memory block specified pv.
2996 *
2997 * @returns Handle to 'global' memory object.
2998 * @returns NULL on failure.
2999 * @param uFormat Odin format number.
3000 * @param pv Pointer to memory block to duplicate.
3001 * @param cb Number of bytes to allocate and duplicate.
3002 * @param ppLocalClip Where to put the cache structure.
3003 */
3004HANDLE clipboardCacheAllocGlobalDup(UINT uFormat, const void *pv, unsigned cb, PCLIPLOCALDATA *ppClip)
3005{
3006 dprintf2(("USER32: clipboardCacheAllocGlobalDup: uFormat=%d (%s) pv=%p cb=%d\n",
3007 uFormat, dbgGetFormatName(uFormat), pv, cb));
3008
3009 /*
3010 * Allocate cache block and copy data.
3011 */
3012 HANDLE hMem = clipboardCacheAllocGlobalAlloc(uFormat, cb, ppClip);
3013 if (hMem)
3014 {
3015 PVOID pvMem = GlobalLock(hMem);
3016 memcpy(pvMem, pv, cb);
3017 GlobalUnlock(hMem);
3018 }
3019
3020 return hMem;
3021}
3022
3023
3024
3025/**
3026 * GlobalAllocs a block of memory for the cache.
3027 *
3028 * @returns Handle to 'global' memory object.
3029 * @returns NULL on failure.
3030 * @param uFormat Odin format number.
3031 * @param cb Number of bytes to allocate.
3032 * @param ppLocalClip Where to put the cache structure.
3033 */
3034HANDLE clipboardCacheAllocGlobalAlloc(UINT uFormat, unsigned cb, PCLIPLOCALDATA *ppLocalClip)
3035{
3036 dprintf2(("USER32: clipboardCacheAllocGlobalAlloc: uFormat=%d (%s) cb=%d\n",
3037 uFormat, dbgGetFormatName(uFormat), cb));
3038 /*
3039 * Allocate object.
3040 */
3041 HANDLE hMem = GlobalAlloc(GMEM_MOVEABLE, cb);
3042 if (!hMem)
3043 {
3044 dprintf(("USER32: GetClipboardData: returns NULL (GlobalAlloc(,%d) failed)\n", cb));
3045 return NULL;
3046 }
3047
3048 /*
3049 * Allocate and initialize cache node.
3050 */
3051 if (clipboardCacheAllocGlobalMem(uFormat, hMem, ppLocalClip))
3052 return hMem;
3053
3054 /* failed */
3055 GlobalFree(hMem);
3056 return NULL;
3057}
3058
3059
3060/**
3061 * Allocates a cache node for a global memory handle.
3062 *
3063 * @returns Handle to 'global' memory object.
3064 * @returns NULL on failure.
3065 * @param uFormat Odin format number.
3066 * @param cb Number of bytes to allocate.
3067 * @param ppLocalClip Where to put the cache structure.
3068 */
3069BOOL clipboardCacheAllocGlobalMem(UINT uFormat, HANDLE hMem, PCLIPLOCALDATA *ppLocalClip)
3070{
3071 dprintf2(("USER32: clipboardCacheAllocGlobalMem: uFormat=%d (%s) hMem=%#x\n",
3072 uFormat, dbgGetFormatName(uFormat), hMem));
3073
3074 /*
3075 * Allocate and initialize cache node.
3076 */
3077 PCLIPLOCALDATA pLocalClip = (PCLIPLOCALDATA)malloc(sizeof(*pLocalClip));
3078 *ppLocalClip = pLocalClip;
3079 if (!pLocalClip)
3080 return FALSE;
3081
3082 pLocalClip->enmType = CLIPLOCALDATA::enmGlobalMem;
3083 pLocalClip->h = hMem;
3084 pLocalClip->uFormat = uFormat;
3085 pLocalClip->pNext = NULL;
3086
3087 return TRUE;
3088}
3089
3090
3091/**
3092 * Allocates a cache node for a GDI handle.
3093 *
3094 * @returns hGDI on success.
3095 * @returns NULL on failure.
3096 * @param uFormat Clipboard format number.
3097 * @param hGDI GDI handle.
3098 * @param ppLocalClip Where to store the pointer to the allocated cache node.
3099 */
3100BOOL clipboardCacheAllocGDI(UINT uFormat, HANDLE hGDI, PCLIPLOCALDATA *ppLocalClip)
3101{
3102 dprintf2(("USER32: clipboardCacheAllocGDI: uFormat=%d (%s) hGdi=%#x\n",
3103 uFormat, dbgGetFormatName(uFormat), hGDI));
3104 /*
3105 * Allocate and initialize cache node.
3106 */
3107 PCLIPLOCALDATA pLocalClip = (PCLIPLOCALDATA)malloc(sizeof(*pLocalClip));
3108 *ppLocalClip = pLocalClip;
3109 if (!pLocalClip)
3110 return FALSE;
3111
3112 pLocalClip->enmType = CLIPLOCALDATA::enmGDI;
3113 pLocalClip->h = hGDI;
3114 pLocalClip->uFormat = uFormat;
3115 pLocalClip->pNext = NULL;
3116
3117 return TRUE;
3118}
3119
3120
3121/**
3122 * Inserts a previously allocated local cache node.
3123 *
3124 * Since this is a cache, pNew might be rejected because of the data
3125 * already existing in the cache. Therefor always use the returned handle.
3126 *
3127 * @returns The handle in the cached node.
3128 * @param pNew Node to insert.
3129 */
3130HANDLE clipboardCacheInsertNode(PCLIPLOCALDATA pNew)
3131{
3132 dprintf2(("USER32: clipboardCacheInsertNode: pNew=%p format=%d (%s) h=%#x\n",
3133 pNew, pNew->uFormat, dbgGetFormatName(pNew->uFormat), pNew->h));
3134 /*
3135 * Find the previous node with the same format.
3136 */
3137 PCLIPLOCALDATA p = gpLocalData;
3138 PCLIPLOCALDATA pPrev = NULL;
3139 while (p && p->uFormat != pNew->uFormat)
3140 p = p->pNext;
3141 if (p)
3142 {
3143 /*
3144 * If the old and new cache nodes are idendical we'll keep the old one.
3145 */
3146 if (p->enmType == pNew->enmType)
3147 {
3148 switch (p->enmType)
3149 {
3150 case CLIPLOCALDATA::enmGlobalMem:
3151 {
3152 DWORD cb = GlobalSize(p->h);
3153 if (cb == GlobalSize(pNew->h))
3154 {
3155 PVOID pv = GlobalLock(p->h);
3156 PVOID pvNew = GlobalLock(pNew->h);
3157 int diff = -1;
3158 if (pv && pvNew)
3159 diff = memcmp(pv, pvNew, cb);
3160 GlobalUnlock(pNew->h);
3161 GlobalUnlock(p->h);
3162 if (!diff)
3163 {
3164 clipboardCacheDeleteNode(pNew);
3165 dprintf2(("USER32: clipboardCacheInsertNode: returning existing node %#x (cache hit)\n", p->h));
3166 return p->h;
3167 }
3168 }
3169 break;
3170 }
3171
3172 case CLIPLOCALDATA::enmGDI:
3173 /** @todo */
3174 break;
3175
3176 case CLIPLOCALDATA::enmPrivate:
3177 default:
3178 DebugAssertFailed(("Don't know how to handle this type\n"));
3179 break;
3180 }
3181
3182 }
3183
3184 /*
3185 * Remove and delete the old node.
3186 */
3187 dprintf2(("USER32: clipboardCacheInsertNode: removing old node %p h=%#x\n", p, p->h));
3188 if (pPrev)
3189 pPrev->pNext = p->pNext;
3190 else
3191 gpLocalData = p->pNext;
3192 clipboardCacheDeleteNode(p);
3193 }
3194
3195 /*
3196 * Insert the new node.
3197 */
3198 pNew->pNext = gpLocalData;
3199 gpLocalData = pNew;
3200
3201 return pNew->h;
3202}
3203
3204
3205/**
3206 * Delete Odin resources associated with a cache node.
3207 *
3208 * The node must be unlinked from the cache before this function is called.
3209 *
3210 * @param p Node to delete.
3211 */
3212void clipboardCacheDeleteNode(PCLIPLOCALDATA p)
3213{
3214 dprintf2(("USER32: clipboardCacheDeleteNode: p=%p format=%d (%s) h=%#x\n",
3215 p, p->uFormat, dbgGetFormatName(p->uFormat), p->h));
3216 switch (p->enmType)
3217 {
3218 case CLIPLOCALDATA::enmGlobalMem:
3219 if (GlobalFree(p->h))
3220 DebugAssertFailed(("GlobalFree failed freeing %#x (format %d). lasterr=%d\n",
3221 p->h, p->uFormat, GetLastError()));
3222 p->h = NULL;
3223 break;
3224
3225 case CLIPLOCALDATA::enmGDI:
3226 if (!DeleteObject(p->h))
3227 DebugAssertFailed(("DeleteObject failed freeing %#x (format %d). lasterr=%d\n",
3228 p->h, p->uFormat, GetLastError()));
3229 p->h = NULL;
3230 break;
3231
3232 case CLIPLOCALDATA::enmPrivate:
3233 DebugAssertFailed(("shit! don't know how to handle this cache type!"));
3234 break;
3235 default:
3236 DebugAssertFailed(("!cache corrupted! invalid type %d", p->enmType));
3237 break;
3238 }
3239 free(p);
3240}
3241
Note: See TracBrowser for help on using the repository browser.