Ignore:
Timestamp:
Apr 13, 2004, 4:17:01 PM (21 years ago)
Author:
sandervl
Message:

KSO: clipboard rewrite

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/user32/clipboard.cpp

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