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