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