xref: /reactos/win32ss/printing/base/winspool/utils.c (revision e1605243)
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 }
379