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