source: trunk/src/user32/clipboard.cpp

Last change on this file was 21916, checked in by dmik, 14 years ago

Merge branch gcc-kmk to trunk.

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