1 /*
2  * PROJECT:         ReactOS user32.dll
3  * FILE:            win32ss/user/user32/windows/clipboard.c
4  * PURPOSE:         Input
5  * PROGRAMMER:      Casper S. Hornstrup (chorns@users.sourceforge.net)
6  *                  Pablo Borobia <pborobia@gmail.com>
7  * UPDATE HISTORY:
8  *      09-05-2001  CSH  Created
9  *
10  */
11 
12 #include <user32.h>
13 
14 #define NDEBUG
15 
16 WINE_DEFAULT_DEBUG_CHANNEL(user32);
17 
18 HANDLE WINAPI GdiConvertMetaFilePict(HANDLE);
19 HANDLE WINAPI GdiConvertEnhMetaFile(HANDLE);
20 HANDLE WINAPI GdiCreateLocalEnhMetaFile(HANDLE);
21 HANDLE WINAPI GdiCreateLocalMetaFilePict(HANDLE);
22 
23 
24 /*
25  * @implemented
26  */
27 BOOL
28 WINAPI
OpenClipboard(HWND hWndNewOwner)29 OpenClipboard(HWND hWndNewOwner)
30 {
31     return NtUserOpenClipboard(hWndNewOwner, 0);
32 }
33 
34 /*
35  * @implemented
36  */
37 UINT
38 WINAPI
EnumClipboardFormats(UINT format)39 EnumClipboardFormats(UINT format)
40 {
41     SetLastError(NO_ERROR);
42     return NtUserxEnumClipboardFormats(format);
43 }
44 
45 /*
46  * @implemented
47  */
48 INT
49 WINAPI
GetClipboardFormatNameA(UINT format,LPSTR lpszFormatName,int cchMaxCount)50 GetClipboardFormatNameA(UINT format,
51                         LPSTR lpszFormatName,
52                         int cchMaxCount)
53 {
54     LPWSTR lpBuffer;
55     INT Length;
56 
57     lpBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, cchMaxCount * sizeof(WCHAR));
58     if (!lpBuffer)
59     {
60         SetLastError(ERROR_OUTOFMEMORY);
61         return 0;
62     }
63 
64     /* we need a UNICODE string */
65     Length = NtUserGetClipboardFormatName(format, lpBuffer, cchMaxCount);
66 
67     if (Length != 0)
68     {
69         if (!WideCharToMultiByte(CP_ACP, 0, lpBuffer, Length, lpszFormatName, cchMaxCount, NULL, NULL))
70         {
71             /* clear result string */
72             Length = 0;
73         }
74         lpszFormatName[Length] = ANSI_NULL;
75     }
76 
77     RtlFreeHeap(RtlGetProcessHeap(), 0, lpBuffer);
78     return Length;
79 }
80 
81 /*
82  * @implemented
83  */
84 INT
85 WINAPI
GetClipboardFormatNameW(UINT uFormat,LPWSTR lpszFormatName,INT cchMaxCount)86 GetClipboardFormatNameW(UINT uFormat,
87                         LPWSTR lpszFormatName,
88                         INT cchMaxCount)
89 {
90     return NtUserGetClipboardFormatName(uFormat, lpszFormatName, cchMaxCount);
91 }
92 
93 /*
94  * @implemented
95  */
96 UINT
97 WINAPI
RegisterClipboardFormatA(LPCSTR lpszFormat)98 RegisterClipboardFormatA(LPCSTR lpszFormat)
99 {
100     UINT ret;
101     UNICODE_STRING usFormat = {0};
102 
103     if (lpszFormat == NULL)
104     {
105         SetLastError(ERROR_INVALID_PARAMETER);
106         return 0;
107     }
108 
109     if (*lpszFormat == ANSI_NULL)
110     {
111         SetLastError(ERROR_INVALID_NAME);
112         return 0;
113     }
114 
115     if (!RtlCreateUnicodeStringFromAsciiz(&usFormat, lpszFormat))
116     {
117         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
118         return 0;
119     }
120 
121     ret = NtUserRegisterWindowMessage(&usFormat); //(LPCWSTR)
122 
123     RtlFreeUnicodeString(&usFormat);
124 
125     return ret;
126 }
127 
128 /*
129  * @implemented
130  */
131 UINT
132 WINAPI
RegisterClipboardFormatW(LPCWSTR lpszFormat)133 RegisterClipboardFormatW(LPCWSTR lpszFormat)
134 {
135     UNICODE_STRING usFormat = {0};
136 
137     if (lpszFormat == NULL)
138     {
139         SetLastError(ERROR_INVALID_PARAMETER);
140         return 0;
141     }
142 
143     if (*lpszFormat == UNICODE_NULL)
144     {
145         SetLastError(ERROR_INVALID_NAME);
146         return 0;
147     }
148 
149     RtlInitUnicodeString(&usFormat, lpszFormat);
150     return NtUserRegisterWindowMessage(&usFormat);
151 }
152 
153 static PVOID WINAPI
IntSynthesizeMultiByte(PVOID pwStr,DWORD cbStr,BOOL bOem)154 IntSynthesizeMultiByte(PVOID pwStr, DWORD cbStr, BOOL bOem)
155 {
156     HANDLE hGlobal;
157     PVOID pGlobal;
158     INT cbGlobal;
159 
160     cbGlobal = WideCharToMultiByte(bOem ? CP_OEMCP : CP_ACP,
161                                 0, pwStr, cbStr / sizeof(WCHAR),
162                                 NULL, 0, NULL, NULL);
163     hGlobal = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, cbGlobal);
164     if (!hGlobal)
165         return NULL;
166 
167     pGlobal = GlobalLock(hGlobal);
168     WideCharToMultiByte(bOem ? CP_OEMCP : CP_ACP,
169                         0, pwStr, cbStr / sizeof(WCHAR),
170                         pGlobal, cbGlobal, NULL, NULL);
171     return pGlobal;
172 }
173 
174 static PVOID WINAPI
IntSynthesizeWideChar(PVOID pwStr,DWORD cbStr,BOOL bOem)175 IntSynthesizeWideChar(PVOID pwStr, DWORD cbStr, BOOL bOem)
176 {
177     HANDLE hGlobal;
178     PVOID pGlobal;
179     INT cbGlobal;
180 
181     cbGlobal = MultiByteToWideChar(bOem ? CP_OEMCP : CP_ACP,
182                                    0, pwStr, cbStr, NULL, 0) * sizeof(WCHAR);
183     hGlobal = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, cbGlobal);
184     if (!hGlobal)
185         return NULL;
186 
187     pGlobal = GlobalLock(hGlobal);
188     MultiByteToWideChar(bOem ? CP_OEMCP : CP_ACP,
189                         0, pwStr, cbStr, pGlobal, cbGlobal);
190     return pGlobal;
191 }
192 
193 /*
194  * @implemented
195  */
196 HANDLE
197 WINAPI
GetClipboardData(UINT uFormat)198 GetClipboardData(UINT uFormat)
199 {
200     HANDLE hData = NULL;
201     PVOID pData = NULL;
202     DWORD cbData = 0;
203     GETCLIPBDATA gcd;
204 
205     hData = NtUserGetClipboardData(uFormat, &gcd);
206     if (!hData)
207         return NULL;
208 
209     switch (uFormat)
210     {
211         case CF_DSPMETAFILEPICT:
212         case CF_METAFILEPICT:
213             return GdiCreateLocalMetaFilePict(hData);
214         case CF_DSPENHMETAFILE:
215         case CF_ENHMETAFILE:
216             return GdiCreateLocalEnhMetaFile(hData);
217     }
218 
219     if (gcd.fGlobalHandle)
220     {
221         HANDLE hGlobal;
222 
223         NtUserCreateLocalMemHandle(hData, NULL, 0, &cbData);
224         hGlobal = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, cbData);
225         pData = GlobalLock(hGlobal);
226         NtUserCreateLocalMemHandle(hData, pData, cbData, NULL);
227         hData = hGlobal;
228     }
229 
230     if (gcd.uFmtRet != uFormat)
231     {
232         SETCLIPBDATA scd = {FALSE, FALSE};
233         HANDLE hNewData = NULL;
234         PVOID pNewData = NULL;
235 
236         /* Synthesize requested format */
237         switch (uFormat)
238         {
239             case CF_TEXT:
240                 if (gcd.uFmtRet == CF_UNICODETEXT)
241                     pNewData = IntSynthesizeMultiByte(pData, cbData, uFormat == CF_OEMTEXT);
242                 else // CF_OEMTEXT
243                     OemToCharBuffA(pData, pData, cbData);
244                 break;
245             case CF_OEMTEXT:
246                 if (gcd.uFmtRet == CF_UNICODETEXT)
247                     pNewData = IntSynthesizeMultiByte(pData, cbData, uFormat == CF_OEMTEXT);
248                 else
249                     CharToOemBuffA(pData, pData, cbData);
250                 break;
251             case CF_UNICODETEXT:
252                 pNewData = IntSynthesizeWideChar(pData, cbData, gcd.uFmtRet == CF_OEMTEXT);
253                 break;
254             default:
255                 FIXME("Format: %u != %u\n", uFormat, gcd.uFmtRet);
256         }
257 
258         /* Is it a global handle? */
259         if (pNewData)
260             hNewData = GlobalHandle(pNewData);
261 
262         if (hNewData)
263         {
264             /* Free old data */
265             if (pData)
266             {
267                 GlobalUnlock(hData);
268                 GlobalFree(hData);
269             }
270             hData = hNewData;
271             pData = pNewData;
272         }
273 
274         /* Save synthesized format in clipboard */
275         if (pData)
276         {
277             HANDLE hMem;
278 
279             scd.fGlobalHandle = TRUE;
280             hMem = NtUserConvertMemHandle(pData, GlobalSize(hData));
281             NtUserSetClipboardData(uFormat, hMem, &scd);
282         }
283         else if (hData)
284             NtUserSetClipboardData(uFormat, hData, &scd);
285     }
286 
287     /* Unlock global handle */
288     if (pData)
289         GlobalUnlock(hData);
290 
291     return hData;
292 }
293 
294 /*
295  * @implemented
296  */
297 HANDLE
298 WINAPI
SetClipboardData(UINT uFormat,HANDLE hMem)299 SetClipboardData(UINT uFormat, HANDLE hMem)
300 {
301     DWORD dwSize;
302     HANDLE hGlobal;
303     LPVOID pMem;
304     HANDLE hRet = NULL, hTemp;
305     SETCLIPBDATA scd = {FALSE, FALSE};
306 
307     /* Check if this is a delayed rendering */
308     if (hMem == NULL)
309         return NtUserSetClipboardData(uFormat, NULL, &scd);
310 
311     if (hMem <= (HANDLE)4)
312         SetLastError(ERROR_INVALID_PARAMETER);
313     /* Bitmaps and palette does not use global handles */
314     else if (uFormat == CF_BITMAP || uFormat == CF_DSPBITMAP || uFormat == CF_PALETTE)
315         hRet = NtUserSetClipboardData(uFormat, hMem, &scd);
316     /* Meta files are probably checked for validity */
317     else if (uFormat == CF_DSPMETAFILEPICT || uFormat == CF_METAFILEPICT )
318     {
319         hTemp = GdiConvertMetaFilePict( hMem );
320         hRet = NtUserSetClipboardData(uFormat, hTemp, &scd); // Note : LOL, it returns a BOOL not a HANDLE!!!!
321         if (hRet == hTemp) hRet = hMem;                      // If successful "TRUE", return the original handle.
322     }
323     else if (uFormat == CF_DSPENHMETAFILE || uFormat == CF_ENHMETAFILE)
324     {
325         hTemp = GdiConvertEnhMetaFile( hMem );
326         hRet = NtUserSetClipboardData(uFormat, hTemp, &scd);
327         if (hRet == hTemp) hRet = hMem;
328     }
329     else
330     {
331         /* Some formats accept only global handles, other accept global handles or integer values */
332         pMem = GlobalLock(hMem);
333         dwSize = GlobalSize(hMem);
334 
335         if (pMem || uFormat == CF_DIB || uFormat == CF_DIBV5 ||
336             uFormat == CF_DSPTEXT || uFormat == CF_LOCALE ||
337             uFormat == CF_OEMTEXT || uFormat == CF_TEXT ||
338             uFormat == CF_UNICODETEXT)
339         {
340             if (pMem)
341             {
342                 /* This is a local memory. Make global memory object */
343                 hGlobal = NtUserConvertMemHandle(pMem, dwSize);
344 
345                 /* Unlock memory */
346                 GlobalUnlock(hMem);
347                 /* FIXME: free hMem when CloseClipboard is called */
348 
349                 if (hGlobal)
350                 {
351                     /* Save data */
352                     scd.fGlobalHandle = TRUE;
353                     hRet = NtUserSetClipboardData(uFormat, hGlobal, &scd);
354                 }
355 
356                 /* On success NtUserSetClipboardData returns pMem
357                    however caller expects us to return hMem */
358                 if (hRet == hGlobal)
359                     hRet = hMem;
360             }
361             else
362                 SetLastError(ERROR_INVALID_HANDLE);
363         }
364         else
365         {
366             /* Save a number */
367             hRet = NtUserSetClipboardData(uFormat, hMem, &scd);
368         }
369     }
370 
371     if (!hRet)
372         ERR("SetClipboardData(%u, %p) failed\n", uFormat, hMem);
373 
374     return hRet;
375 }
376 
377 /*
378  * @unimplemented
379  */
380 BOOL
381 WINAPI
AddClipboardFormatListener(HWND hwnd)382 AddClipboardFormatListener(HWND hwnd)
383 {
384     UNIMPLEMENTED;
385     return FALSE;
386 }
387 /*
388  * @unimplemented
389  */
390 BOOL
391 WINAPI
RemoveClipboardFormatListener(HWND hwnd)392 RemoveClipboardFormatListener(HWND hwnd)
393 {
394     UNIMPLEMENTED;
395     return FALSE;
396 }
397 
398 /*
399  * @unimplemented
400  */
401 BOOL
402 WINAPI
GetUpdatedClipboardFormats(PUINT lpuiFormats,UINT cFormats,PUINT pcFormatsOut)403 GetUpdatedClipboardFormats(PUINT lpuiFormats,
404                            UINT cFormats,
405                            PUINT pcFormatsOut)
406 {
407     UNIMPLEMENTED;
408     return FALSE;
409 }
410