[CRT] Massively improve performance of rand_s
[reactos.git] / win32ss / printing / base / winspool / utils.c
1 /*
2 * PROJECT: ReactOS Spooler API
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Utility Functions related to Print Processors
5 * COPYRIGHT: Copyright 2020 Doug Lyons (douglyons@douglyons.com)
6 */
7
8 #include "precomp.h"
9 #include <shlobj.h>
10 #include <undocshell.h>
11
12 #define MAX_GETPRINTER_SIZE 4096 - MAX_PATH
13 typedef void (WINAPI *PPfpSHChangeNotify)(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID dwItem2);
14
15 static HMODULE hShell32 = (HMODULE)-1;
16
17
18 /*
19 * Converts an incoming Unicode string to an ANSI string.
20 * It is only useful for "in-place" conversions where the ANSI string goes
21 * back into the same place where the Unicode string came into this function.
22 *
23 * It returns an error code.
24 */
25 // TODO: It seems that many of the functions involving printing could use this.
26 DWORD UnicodeToAnsiInPlace(PWSTR pwszField)
27 {
28 PSTR pszTemp;
29 DWORD cch;
30
31 /*
32 * Map the incoming Unicode pwszField string to an ANSI one here so that we can do
33 * in-place conversion. We read the Unicode input and then we write back the ANSI
34 * conversion into the same buffer for use with our GetPrinterDriverA function
35 */
36 PSTR pszField = (PSTR)pwszField;
37
38 if (!pwszField)
39 {
40 return ERROR_SUCCESS;
41 }
42
43 cch = wcslen(pwszField);
44 if (cch == 0)
45 {
46 return ERROR_SUCCESS;
47 }
48
49 pszTemp = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
50 if (!pszTemp)
51 {
52 ERR("HeapAlloc failed!\n");
53 return ERROR_NOT_ENOUGH_MEMORY;
54 }
55
56 WideCharToMultiByte(CP_ACP, 0, pwszField, -1, pszTemp, cch + 1, NULL, NULL);
57 StringCchCopyA(pszField, cch + 1, pszTemp);
58
59 HeapFree(hProcessHeap, 0, pszTemp);
60
61 return ERROR_SUCCESS;
62 }
63
64 static int multi_sz_lenW(const WCHAR *str)
65 {
66 const WCHAR *ptr = str;
67 if (!str) return 0;
68 do
69 {
70 ptr += lstrlenW(ptr) + 1;
71 } while (*ptr);
72
73 return (ptr - str + 1);// * sizeof(WCHAR); wine does this.
74 }
75
76 DWORD UnicodeToAnsiZZInPlace(PWSTR pwszzField)
77 {
78 PSTR pszTemp;
79 INT len, lenW;
80 PSTR pszField = (PSTR)pwszzField;
81
82 lenW = multi_sz_lenW(pwszzField);
83 if (lenW == 0)
84 {
85 return ERROR_SUCCESS;
86 }
87
88 len = WideCharToMultiByte(CP_ACP, 0, pwszzField, lenW, NULL, 0, NULL, NULL);
89
90 pszTemp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
91
92 WideCharToMultiByte(CP_ACP, 0, pwszzField, lenW, pszTemp, len, NULL, NULL);
93
94 StringCchCopyA(pszField, len, pszTemp);
95
96 HeapFree(hProcessHeap, 0, pszTemp);
97
98 return ERROR_SUCCESS;
99 }
100
101 //
102 // Implement and simplify later.
103 //
104 LONG WINAPI
105 IntProtectHandle( HANDLE hSpooler, BOOL Close )
106 {
107 BOOL Bad = TRUE;
108 LONG Ret;
109 PSPOOLER_HANDLE pHandle;
110
111 EnterCriticalSection(&rtlCritSec);
112
113 _SEH2_TRY
114 {
115 pHandle = (PSPOOLER_HANDLE)hSpooler;
116 if ( pHandle && pHandle->Sig == SPOOLER_HANDLE_SIG )
117 {
118 Bad = FALSE; // Not bad.
119 }
120 }
121 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
122 {
123 }
124 _SEH2_END;
125
126 Ret = Bad; // Set return Level to 1 if we are BAD.
127
128 if ( Bad )
129 {
130 SetLastError(ERROR_INVALID_HANDLE);
131 ERR("IPH : Printer Handle failed!\n");
132 }
133 else
134 {
135 if ( Close )
136 {
137 if ( pHandle->bShared || pHandle->cCount != 0 )
138 {
139 pHandle->bShared = TRUE;
140 Ret = 2; // Return a high level and we are shared.
141 FIXME("IPH Close : We are shared\n");
142 }
143 else
144 {
145 pHandle->bClosed = TRUE;
146 FIXME("IPH Close : closing.\n");
147 }
148 }
149 }
150
151 if ( !Ret ) // Need to be Level 0.
152 {
153 pHandle->cCount++;
154 FIXME("IPH : Count %d\n",pHandle->cCount);
155 }
156
157 LeaveCriticalSection(&rtlCritSec);
158
159 // Return Level:
160 // 2 : Close and/or shared
161 // 1 : Failed Handle
162 // 0 : In use.
163 return Ret;
164 }
165 //
166 // This one too.
167 //
168 BOOL WINAPI
169 IntUnprotectHandle( HANDLE hSpooler )
170 {
171 BOOL Ret = FALSE;
172 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hSpooler;
173 EnterCriticalSection(&rtlCritSec);
174 if ( pHandle->bShared && --pHandle->cCount == 0 )
175 {
176 pHandle->bClosed = TRUE;
177 pHandle->bShared = FALSE;
178 Ret = TRUE;
179 }
180 LeaveCriticalSection(&rtlCritSec);
181 FIXME("IUH : Count %d\n",pHandle->cCount);
182 if ( Ret )
183 {
184 // ClosePrinterWorker( pHandle );
185 }
186 return Ret;
187 }
188
189 /**
190 * @name AllocSplStr
191 *
192 * Allocates memory for a Unicode string and copies the input string into it.
193 * Equivalent of wcsdup, but the returned buffer is allocated from the spooler heap and must be freed with DllFreeSplStr.
194 *
195 * @param pwszInput
196 * The input string to copy
197 *
198 * @return
199 * Pointer to the copied string or NULL if no memory could be allocated.
200 */
201 PWSTR WINAPI
202 AllocSplStr(PCWSTR pwszInput)
203 {
204 DWORD cbInput;
205 PWSTR pwszOutput;
206
207 // Sanity check
208 if (!pwszInput)
209 return NULL;
210
211 // Get the length of the input string.
212 cbInput = (wcslen(pwszInput) + 1) * sizeof(WCHAR);
213
214 // Allocate it. We don't use DllAllocSplMem here, because it unnecessarily zeroes the memory.
215 pwszOutput = HeapAlloc(hProcessHeap, 0, cbInput);
216 if (!pwszOutput)
217 {
218 ERR("HeapAlloc failed!\n");
219 return NULL;
220 }
221
222 // Copy the string and return it.
223 CopyMemory(pwszOutput, pwszInput, cbInput);
224 return pwszOutput;
225 }
226
227 /**
228 * @name DllAllocSplMem
229 *
230 * Allocate a block of zeroed memory.
231 * Windows allocates from a separate spooler heap here while we just use the process heap.
232 *
233 * @param dwBytes
234 * Number of bytes to allocate.
235 *
236 * @return
237 * A pointer to the allocated memory or NULL in case of an error.
238 * You have to free this memory using DllFreeSplMem.
239 */
240 PVOID WINAPI
241 DllAllocSplMem(DWORD dwBytes)
242 {
243 return HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, dwBytes);
244 }
245
246 /**
247 * @name DllFreeSplMem
248 *
249 * Frees the memory allocated with DllAllocSplMem.
250 *
251 * @param pMem
252 * Pointer to the allocated memory.
253 *
254 * @return
255 * TRUE in case of success, FALSE otherwise.
256 */
257 BOOL WINAPI
258 DllFreeSplMem(PVOID pMem)
259 {
260 if ( !pMem ) return TRUE;
261 return HeapFree(hProcessHeap, 0, pMem);
262 }
263
264 /**
265 * @name DllFreeSplStr
266 *
267 * Frees the string allocated with AllocSplStr.
268 *
269 * @param pwszString
270 * Pointer to the allocated string.
271 *
272 * @return
273 * TRUE in case of success, FALSE otherwise.
274 */
275 BOOL WINAPI
276 DllFreeSplStr(PWSTR pwszString)
277 {
278 if ( pwszString )
279 return HeapFree(hProcessHeap, 0, pwszString);
280 return FALSE;
281 }
282
283 SECURITY_DESCRIPTOR * get_sd( SECURITY_DESCRIPTOR *sd, DWORD *size )
284 {
285 PSID sid_group, sid_owner;
286 ACL *sacl, *dacl;
287 BOOL bSet = FALSE, bSetd = FALSE, bSets = FALSE;
288 PSECURITY_DESCRIPTOR absolute_sd, retsd;
289
290 if ( !IsValidSecurityDescriptor( sd ) )
291 {
292 return NULL;
293 }
294
295 InitializeSecurityDescriptor( &absolute_sd, SECURITY_DESCRIPTOR_REVISION );
296
297 if ( !GetSecurityDescriptorOwner( sd, &sid_owner, &bSet ) )
298 {
299 return NULL;
300 }
301
302 SetSecurityDescriptorOwner( &absolute_sd, sid_owner, bSet );
303
304 if ( !GetSecurityDescriptorGroup( sd, &sid_group, &bSet ) )
305 {
306 return NULL;
307 }
308
309 SetSecurityDescriptorGroup( &absolute_sd, sid_group, bSet );
310
311 if ( !GetSecurityDescriptorDacl( sd, &bSetd, &dacl, &bSet ) )
312 {
313 return NULL;
314 }
315
316 SetSecurityDescriptorDacl( &absolute_sd, bSetd, dacl, bSet );
317
318 if ( !GetSecurityDescriptorSacl( sd, &bSets, &sacl, &bSet ) )
319 {
320 return(NULL);
321 }
322
323 SetSecurityDescriptorSacl( &absolute_sd, bSets, sacl, bSet );
324
325 *size = GetSecurityDescriptorLength( &absolute_sd );
326
327 retsd = HeapAlloc( GetProcessHeap(), 0, *size );
328
329 if ( retsd )
330 {
331 if ( !MakeSelfRelativeSD( &absolute_sd, retsd, size ) )
332 {
333 HeapFree( GetProcessHeap(), 0, retsd );
334 retsd = NULL;
335 }
336 }
337
338 return retsd;
339 }
340
341 VOID
342 UpdateTrayIcon( HANDLE hPrinter, DWORD JobId )
343 {
344 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
345 SHCNF_PRINTJOB_INFO spji;
346 PRINTER_INFO_1W pi1w[MAX_GETPRINTER_SIZE] = {0};
347 DWORD cbNeeded;
348 PPfpSHChangeNotify fpFunction;
349
350 pHandle->bTrayIcon = TRUE;
351
352 spji.JobId = JobId;
353
354 if (!GetPrinterW( hPrinter, 1, (PBYTE)&pi1w, MAX_GETPRINTER_SIZE, &cbNeeded) )
355 {
356 ERR("UpdateTrayIcon : GetPrinterW cbNeeded %d\n");
357 return;
358 }
359
360 if ( hShell32 == (HMODULE)-1 )
361 {
362 hShell32 = LoadLibraryW(L"shell32.dll");
363 }
364
365 if ( hShell32 )
366 {
367 fpFunction = (PPfpSHChangeNotify)GetProcAddress( hShell32, "SHChangeNotify" );
368
369 if ( fpFunction )
370 {
371 fpFunction( SHCNE_CREATE, (SHCNF_FLUSHNOWAIT|SHCNF_FLUSH|SHCNF_PRINTJOBW), pi1w->pName , &spji );
372 }
373 }
374 else
375 {
376 ERR("UpdateTrayIcon : No Shell32!\n");
377 }
378 }