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