xref: /reactos/base/applications/cmdutils/clip/clip.c (revision c2c66aff)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Clip Command
4  * FILE:            base/applications/cmdutils/clip/clip.c
5  * PURPOSE:         Provides clipboard management for command-line programs.
6  * PROGRAMMERS:     Ricardo Hanke
7  */
8 
9 #include <stdio.h>
10 
11 #include <windef.h>
12 #include <winbase.h>
13 #include <winuser.h>
14 
15 #include <conutils.h>
16 
17 #include "resource.h"
18 
PrintError(DWORD dwError)19 VOID PrintError(DWORD dwError)
20 {
21     if (dwError == ERROR_SUCCESS)
22         return;
23 
24     ConMsgPuts(StdErr, FORMAT_MESSAGE_FROM_SYSTEM,
25                NULL, dwError, LANG_USER_DEFAULT);
26 }
27 
IsDataUnicode(HGLOBAL hGlobal)28 static BOOL IsDataUnicode(HGLOBAL hGlobal)
29 {
30     BOOL bReturn;
31     LPVOID lpBuffer;
32 
33     lpBuffer = GlobalLock(hGlobal);
34     bReturn = IsTextUnicode(lpBuffer, GlobalSize(hGlobal), NULL);
35     GlobalUnlock(hGlobal);
36 
37     return bReturn;
38 }
39 
wmain(int argc,wchar_t ** argv)40 int wmain(int argc, wchar_t** argv)
41 {
42     HANDLE hInput;
43     DWORD dwBytesRead;
44     BOOL bStatus;
45     HGLOBAL hBuffer;
46     HGLOBAL hTemp;
47     LPBYTE lpBuffer;
48     SIZE_T dwSize = 0;
49 
50     /* Initialize the Console Standard Streams */
51     hInput = GetStdHandle(STD_INPUT_HANDLE);
52     ConInitStdStreams();
53 
54     /* Check for usage */
55     if (argc > 1 && wcsncmp(argv[1], L"/?", 2) == 0)
56     {
57         ConResPuts(StdOut, IDS_HELP);
58         return 0;
59     }
60 
61     if (GetFileType(hInput) == FILE_TYPE_CHAR)
62     {
63         ConResPuts(StdOut, IDS_USAGE);
64         return 0;
65     }
66 
67     /* Initialize a growable buffer for holding clipboard data */
68     hBuffer = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, 4096);
69     if (!hBuffer)
70         goto Failure;
71 
72     /*
73      * Read data from the input stream by chunks of 4096 bytes
74      * and resize the buffer each time when needed.
75      */
76     do
77     {
78         lpBuffer = GlobalLock(hBuffer);
79         if (!lpBuffer)
80             goto Failure;
81 
82         bStatus = ReadFile(hInput, lpBuffer + dwSize, 4096, &dwBytesRead, NULL);
83         dwSize += dwBytesRead;
84         GlobalUnlock(hBuffer);
85 
86         hTemp = GlobalReAlloc(hBuffer, GlobalSize(hBuffer) + 4096, GMEM_ZEROINIT);
87         if (!hTemp)
88             goto Failure;
89 
90         hBuffer = hTemp;
91     }
92     while (bStatus && dwBytesRead > 0);
93 
94     /*
95      * Resize the buffer to the total size of data read.
96      * Note that, if the call fails, we still have the old buffer valid.
97      * The old buffer would be larger than the actual size of data it contains,
98      * but this is not a problem for us.
99      */
100     hTemp = GlobalReAlloc(hBuffer, dwSize + sizeof(WCHAR), GMEM_ZEROINIT);
101     if (hTemp)
102         hBuffer = hTemp;
103 
104     /* Attempt to open the clipboard */
105     if (!OpenClipboard(NULL))
106         goto Failure;
107 
108     /* Empty it, copy our data, then close it */
109 
110     EmptyClipboard();
111 
112     if (IsDataUnicode(hBuffer))
113     {
114         SetClipboardData(CF_UNICODETEXT, hBuffer);
115     }
116     else
117     {
118         // TODO: Convert text from current console page to standard ANSI.
119         // Alternatively one can use CF_OEMTEXT as done here.
120         SetClipboardData(CF_OEMTEXT, hBuffer);
121     }
122 
123     CloseClipboard();
124     return 0;
125 
126 Failure:
127     if (hBuffer) GlobalFree(hBuffer);
128     PrintError(GetLastError());
129     return -1;
130 }
131