aboutsummaryrefslogtreecommitdiff
path: root/raylib/src/external/win32_clipboard.h
diff options
context:
space:
mode:
Diffstat (limited to 'raylib/src/external/win32_clipboard.h')
-rw-r--r--raylib/src/external/win32_clipboard.h374
1 files changed, 374 insertions, 0 deletions
diff --git a/raylib/src/external/win32_clipboard.h b/raylib/src/external/win32_clipboard.h
new file mode 100644
index 0000000..8328564
--- /dev/null
+++ b/raylib/src/external/win32_clipboard.h
@@ -0,0 +1,374 @@
1#if !defined(_WIN32)
2# error "This module is only made for Windows OS"
3#endif
4
5#ifndef WIN32_CLIPBOARD_
6#define WIN32_CLIPBOARD_
7unsigned char* Win32GetClipboardImageData(int* width, int* height, unsigned long long int *dataSize);
8#endif // WIN32_CLIPBOARD_
9
10#ifdef WIN32_CLIPBOARD_IMPLEMENTATION
11#include <stdio.h>
12#include <stdbool.h>
13#include <stdlib.h>
14#include <assert.h>
15
16// NOTE: These search for architecture is taken from "Windows.h", and it's necessary if we really don't wanna import windows.h
17// and still make it compile on msvc, because import indirectly importing "winnt.h" (e.g. <minwindef.h>) can cause problems is these are not defined.
18#if !defined(_X86_) && !defined(_68K_) && !defined(_MPPC_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_IX86)
19#define _X86_
20#if !defined(_CHPE_X86_ARM64_) && defined(_M_HYBRID)
21#define _CHPE_X86_ARM64_
22#endif
23#endif
24
25#if !defined(_AMD64_) && !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) && (defined(_M_AMD64) || defined(_M_ARM64EC))
26#define _AMD64_
27#endif
28
29#if !defined(_ARM_) && !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_ARM)
30#define _ARM_
31#endif
32
33#if !defined(_ARM64_) && !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64EC_) && defined(_M_ARM64)
34#define _ARM64_
35#endif
36
37#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_ARM_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_ARM64EC)
38#define _ARM64EC_
39#endif
40
41#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_M68K)
42#define _68K_
43#endif
44
45#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_MPPC)
46#define _MPPC_
47#endif
48
49#if !defined(_IA64_) && !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_M_IX86) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_IA64)
50#define _IA64_
51#endif
52
53
54#define WIN32_LEAN_AND_MEAN
55// #include <sdkddkver.h>
56// #include <windows.h>
57// #include <winuser.h>
58#include <minwindef.h>
59// #include <minwinbase.h>
60
61#ifndef WINAPI
62#if defined(_ARM_)
63#define WINAPI
64#else
65#define WINAPI __stdcall
66#endif
67#endif
68
69#ifndef WINAPI
70#if defined(_ARM_)
71#define WINAPI
72#else
73#define WINAPI __stdcall
74#endif
75#endif
76
77#ifndef WINBASEAPI
78#ifndef _KERNEL32_
79#define WINBASEAPI DECLSPEC_IMPORT
80#else
81#define WINBASEAPI
82#endif
83#endif
84
85#ifndef WINUSERAPI
86#ifndef _USER32_
87#define WINUSERAPI __declspec (dllimport)
88#else
89#define WINUSERAPI
90#endif
91#endif
92
93typedef int WINBOOL;
94
95
96
97// typedef HANDLE HGLOBAL;
98
99#ifndef HWND
100#define HWND void*
101#endif
102
103
104#if !defined(_WINUSER_) || !defined(WINUSER_ALREADY_INCLUDED)
105WINUSERAPI WINBOOL WINAPI OpenClipboard(HWND hWndNewOwner);
106WINUSERAPI WINBOOL WINAPI CloseClipboard(VOID);
107WINUSERAPI DWORD WINAPI GetClipboardSequenceNumber(VOID);
108WINUSERAPI HWND WINAPI GetClipboardOwner(VOID);
109WINUSERAPI HWND WINAPI SetClipboardViewer(HWND hWndNewViewer);
110WINUSERAPI HWND WINAPI GetClipboardViewer(VOID);
111WINUSERAPI WINBOOL WINAPI ChangeClipboardChain(HWND hWndRemove, HWND hWndNewNext);
112WINUSERAPI HANDLE WINAPI SetClipboardData(UINT uFormat, HANDLE hMem);
113WINUSERAPI HANDLE WINAPI GetClipboardData(UINT uFormat);
114WINUSERAPI UINT WINAPI RegisterClipboardFormatA(LPCSTR lpszFormat);
115WINUSERAPI UINT WINAPI RegisterClipboardFormatW(LPCWSTR lpszFormat);
116WINUSERAPI int WINAPI CountClipboardFormats(VOID);
117WINUSERAPI UINT WINAPI EnumClipboardFormats(UINT format);
118WINUSERAPI int WINAPI GetClipboardFormatNameA(UINT format, LPSTR lpszFormatName, int cchMaxCount);
119WINUSERAPI int WINAPI GetClipboardFormatNameW(UINT format, LPWSTR lpszFormatName, int cchMaxCount);
120WINUSERAPI WINBOOL WINAPI EmptyClipboard(VOID);
121WINUSERAPI WINBOOL WINAPI IsClipboardFormatAvailable(UINT format);
122WINUSERAPI int WINAPI GetPriorityClipboardFormat(UINT *paFormatPriorityList, int cFormats);
123WINUSERAPI HWND WINAPI GetOpenClipboardWindow(VOID);
124#endif
125
126#ifndef HGLOBAL
127#define HGLOBAL void*
128#endif
129
130#if !defined(_WINBASE_) || !defined(WINBASE_ALREADY_INCLUDED)
131WINBASEAPI SIZE_T WINAPI GlobalSize (HGLOBAL hMem);
132WINBASEAPI LPVOID WINAPI GlobalLock (HGLOBAL hMem);
133WINBASEAPI WINBOOL WINAPI GlobalUnlock (HGLOBAL hMem);
134#endif
135
136
137#if !defined(_WINGDI_) || !defined(WINGDI_ALREADY_INCLUDED)
138#ifndef BITMAPINFOHEADER_ALREADY_DEFINED
139#define BITMAPINFOHEADER_ALREADY_DEFINED
140// Does this header need to be packed ? by the windowps header it doesnt seem to be
141#pragma pack(push, 1)
142typedef struct tagBITMAPINFOHEADER {
143 DWORD biSize;
144 LONG biWidth;
145 LONG biHeight;
146 WORD biPlanes;
147 WORD biBitCount;
148 DWORD biCompression;
149 DWORD biSizeImage;
150 LONG biXPelsPerMeter;
151 LONG biYPelsPerMeter;
152 DWORD biClrUsed;
153 DWORD biClrImportant;
154} BITMAPINFOHEADER,*LPBITMAPINFOHEADER,*PBITMAPINFOHEADER;
155#pragma pack(pop)
156#endif
157
158#ifndef BITMAPFILEHEADER_ALREADY_DEFINED
159#define BITMAPFILEHEADER_ALREADY_DEFINED
160#pragma pack(push, 1)
161typedef struct tagBITMAPFILEHEADER {
162 WORD bfType;
163 DWORD bfSize;
164 WORD bfReserved1;
165 WORD bfReserved2;
166 DWORD bfOffBits;
167} BITMAPFILEHEADER,*LPBITMAPFILEHEADER,*PBITMAPFILEHEADER;
168#pragma pack(pop)
169#endif
170
171#ifndef RGBQUAD_ALREADY_DEFINED
172#define RGBQUAD_ALREADY_DEFINED
173typedef struct tagRGBQUAD {
174 BYTE rgbBlue;
175 BYTE rgbGreen;
176 BYTE rgbRed;
177 BYTE rgbReserved;
178} RGBQUAD, *LPRGBQUAD;
179#endif
180
181
182// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wmf/4e588f70-bd92-4a6f-b77f-35d0feaf7a57
183#define BI_RGB 0x0000
184#define BI_RLE8 0x0001
185#define BI_RLE4 0x0002
186#define BI_BITFIELDS 0x0003
187#define BI_JPEG 0x0004
188#define BI_PNG 0x0005
189#define BI_CMYK 0x000B
190#define BI_CMYKRLE8 0x000C
191#define BI_CMYKRLE4 0x000D
192
193#endif
194
195// https://learn.microsoft.com/en-us/windows/win32/dataxchg/standard-clipboard-formats
196#define CF_DIB 8
197
198// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setsystemcursor
199// #define OCR_NORMAL 32512 // Normal select
200// #define OCR_IBEAM 32513 // Text select
201// #define OCR_WAIT 32514 // Busy
202// #define OCR_CROSS 32515 // Precision select
203// #define OCR_UP 32516 // Alternate select
204// #define OCR_SIZENWSE 32642 // Diagonal resize 1
205// #define OCR_SIZENESW 32643 // Diagonal resize 2
206// #define OCR_SIZEWE 32644 // Horizontal resize
207// #define OCR_SIZENS 32645 // Vertical resize
208// #define OCR_SIZEALL 32646 // Move
209// #define OCR_NO 32648 // Unavailable
210// #define OCR_HAND 32649 // Link select
211// #define OCR_APPSTARTING 32650 //
212
213
214//----------------------------------------------------------------------------------
215// Module Internal Functions Declaration
216//----------------------------------------------------------------------------------
217
218
219static BOOL OpenClipboardRetrying(HWND handle); // Open clipboard with a number of retries
220static int GetPixelDataOffset(BITMAPINFOHEADER bih);
221
222unsigned char* Win32GetClipboardImageData(int* width, int* height, unsigned long long int *dataSize)
223{
224 HWND win = NULL; // Get from somewhere but is doesnt seem to matter
225 const char* msgString = "";
226 int severity = LOG_INFO;
227 BYTE* bmpData = NULL;
228 if (!OpenClipboardRetrying(win)) {
229 severity = LOG_ERROR;
230 msgString = "Couldn't open clipboard";
231 goto end;
232 }
233
234 HGLOBAL clipHandle = (HGLOBAL)GetClipboardData(CF_DIB);
235 if (!clipHandle) {
236 severity = LOG_ERROR;
237 msgString = "Clipboard data is not an Image";
238 goto close;
239 }
240
241 BITMAPINFOHEADER *bmpInfoHeader = (BITMAPINFOHEADER *)GlobalLock(clipHandle);
242 if (!bmpInfoHeader) {
243 // Mapping from HGLOBAL to our local *address space* failed
244 severity = LOG_ERROR;
245 msgString = "Clipboard data failed to be locked";
246 goto unlock;
247 }
248
249 *width = bmpInfoHeader->biWidth;
250 *height = bmpInfoHeader->biHeight;
251
252 SIZE_T clipDataSize = GlobalSize(clipHandle);
253 if (clipDataSize < sizeof(BITMAPINFOHEADER)) {
254 // Format CF_DIB needs space for BITMAPINFOHEADER struct.
255 msgString = "Clipboard has Malformed data";
256 severity = LOG_ERROR;
257 goto unlock;
258 }
259
260 // Denotes where the pixel data starts from the bmpInfoHeader pointer
261 int pixelOffset = GetPixelDataOffset(*bmpInfoHeader);
262
263 //--------------------------------------------------------------------------------//
264 //
265 // The rest of the section is about create the bytes for a correct BMP file
266 // Then we copy the data and to a pointer
267 //
268 //--------------------------------------------------------------------------------//
269
270 BITMAPFILEHEADER bmpFileHeader = {0};
271 SIZE_T bmpFileSize = sizeof(bmpFileHeader) + clipDataSize;
272 *dataSize = bmpFileSize;
273
274 bmpFileHeader.bfType = 0x4D42; //https://stackoverflow.com/questions/601430/multibyte-character-constants-and-bitmap-file-header-type-constants#601536
275
276 bmpFileHeader.bfSize = (DWORD)bmpFileSize; // Up to 4GB works fine
277 bmpFileHeader.bfOffBits = sizeof(bmpFileHeader) + pixelOffset;
278
279 //
280 // Each process has a default heap provided by the system
281 // Memory objects allocated by GlobalAlloc and LocalAlloc are in private,
282 // committed pages with read/write access that cannot be accessed by other processes.
283 //
284 // This may be wrong since we might be allocating in a DLL and freeing from another module, the main application
285 // that may cause heap corruption. We could create a FreeImage function
286 //
287 bmpData = malloc(sizeof(bmpFileHeader) + clipDataSize);
288 // First we add the header for a bmp file
289 memcpy(bmpData, &bmpFileHeader, sizeof(bmpFileHeader));
290 // Then we add the header for the bmp itself + the pixel data
291 memcpy(bmpData + sizeof(bmpFileHeader), bmpInfoHeader, clipDataSize);
292 msgString = "Clipboad image acquired successfully";
293
294
295unlock:
296 GlobalUnlock(clipHandle);
297close:
298 CloseClipboard();
299end:
300
301 TRACELOG(severity, msgString);
302 return bmpData;
303}
304
305static BOOL OpenClipboardRetrying(HWND hWnd)
306{
307 static const int maxTries = 20;
308 static const int sleepTimeMS = 60;
309 for (int _ = 0; _ < maxTries; ++_)
310 {
311 // Might be being hold by another process
312 // Or yourself forgot to CloseClipboard
313 if (OpenClipboard(hWnd)) {
314 return true;
315 }
316 Sleep(sleepTimeMS);
317 }
318 return false;
319}
320
321// Based off of researching microsoft docs and reponses from this question https://stackoverflow.com/questions/30552255/how-to-read-a-bitmap-from-the-windows-clipboard#30552856
322// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader
323// Get the byte offset where does the pixels data start (from a packed DIB)
324static int GetPixelDataOffset(BITMAPINFOHEADER bih)
325{
326 int offset = 0;
327 const unsigned int rgbaSize = sizeof(RGBQUAD);
328
329 // biSize Specifies the number of bytes required by the structure
330 // We expect to always be 40 because it should be packed
331 if (40 == bih.biSize && 40 == sizeof(BITMAPINFOHEADER))
332 {
333 //
334 // biBitCount Specifies the number of bits per pixel.
335 // Might exist some bit masks *after* the header and *before* the pixel offset
336 // we're looking, but only if we have more than
337 // 8 bits per pixel, so we need to ajust for that
338 //
339 if (bih.biBitCount > 8)
340 {
341 // if bih.biCompression is RBG we should NOT offset more
342
343 if (bih.biCompression == BI_BITFIELDS)
344 {
345 offset += 3 * rgbaSize;
346 } else if (bih.biCompression == 6 /* BI_ALPHABITFIELDS */)
347 {
348 // Not widely supported, but valid.
349 offset += 4 * rgbaSize;
350 }
351 }
352 }
353
354 //
355 // biClrUsed Specifies the number of color indices in the color table that are actually used by the bitmap.
356 // If this value is zero, the bitmap uses the maximum number of colors
357 // corresponding to the value of the biBitCount member for the compression mode specified by biCompression.
358 // If biClrUsed is nonzero and the biBitCount member is less than 16
359 // the biClrUsed member specifies the actual number of colors
360 //
361 if (bih.biClrUsed > 0) {
362 offset += bih.biClrUsed * rgbaSize;
363 } else {
364 if (bih.biBitCount < 16)
365 {
366 offset = offset + (rgbaSize << bih.biBitCount);
367 }
368 }
369
370 return bih.biSize + offset;
371}
372#endif // WIN32_CLIPBOARD_IMPLEMENTATION
373// EOF
374

Generated with cgit - Back to sebastiano.tronto.net