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