1 /* 2 * PROJECT: ReactOS Spooler API 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Functions related to Ports 5 * COPYRIGHT: Copyright 2015-2018 Colin Finck (colin@reactos.org) 6 */ 7 8 #include "precomp.h" 9 #include <marshalling/ports.h> 10 11 typedef struct _MONITORUIDATA 12 { 13 HMODULE hLibrary; 14 HANDLE hActCtx; 15 ULONG_PTR ulpCookie; 16 PWSTR pModuleName; 17 BOOL Activeated; 18 } MONITORUIDATA, *PMONITORUIDATA; 19 20 typedef DWORD (*PPfpFunction)(LPWSTR, ULONG_PTR, LPWSTR); 21 22 typedef struct _PORTTHREADINFO 23 { 24 LPWSTR pName; 25 ULONG_PTR hWnd; 26 LPWSTR pPortName; 27 PPfpFunction fpFunction; 28 DWORD dwErrorCode; 29 HANDLE hEvent; 30 } PORTTHREADINFO, *PPORTTHREADINFO; 31 32 VOID WINAPI 33 IntPortThread( PPORTTHREADINFO pPortThreadInfo ) 34 { 35 FIXME("IPT : %s\n",debugstr_w( pPortThreadInfo->pPortName )); 36 // Do the RPC call 37 RpcTryExcept 38 { 39 pPortThreadInfo->dwErrorCode = pPortThreadInfo->fpFunction( pPortThreadInfo->pName, pPortThreadInfo->hWnd, pPortThreadInfo->pPortName ); 40 } 41 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 42 { 43 pPortThreadInfo->dwErrorCode = RpcExceptionCode(); 44 ERR("IPT : _RpcXyzPort failed with exception code %lu!\n", pPortThreadInfo->dwErrorCode); 45 } 46 RpcEndExcept; 47 48 SetEvent( pPortThreadInfo->hEvent ); 49 } 50 51 // 52 // Start a thread to wait on a printer port. 53 // 54 BOOL WINAPI 55 StartPortThread( LPWSTR pName, HWND hWnd, LPWSTR pPortName, PPfpFunction fpFunction ) 56 { 57 PORTTHREADINFO PortThreadInfo; 58 HANDLE htHandle; 59 MSG Msg; 60 DWORD tid; 61 62 if ( hWnd ) EnableWindow( hWnd, FALSE ); 63 64 PortThreadInfo.pName = pName; 65 PortThreadInfo.hWnd = (ULONG_PTR)hWnd; 66 PortThreadInfo.pPortName = pPortName; 67 PortThreadInfo.fpFunction = fpFunction; 68 PortThreadInfo.dwErrorCode = ERROR_SUCCESS; 69 PortThreadInfo.hEvent = CreateEventW( NULL, TRUE, FALSE, NULL ); 70 71 htHandle = CreateThread( NULL, 72 32*1024, 73 (LPTHREAD_START_ROUTINE)IntPortThread, 74 &PortThreadInfo, 75 0, 76 &tid ); 77 78 CloseHandle( htHandle ); 79 80 while ( MsgWaitForMultipleObjects( 1, &PortThreadInfo.hEvent, FALSE, INFINITE, QS_SENDMESSAGE|QS_ALLEVENTS ) == 1 ) 81 { 82 while ( PeekMessageW( &Msg, NULL, 0, 0, PM_REMOVE ) ) 83 { 84 TranslateMessage( &Msg ); 85 DispatchMessageW( &Msg ); 86 } 87 } 88 89 CloseHandle( PortThreadInfo.hEvent ); 90 91 if ( hWnd ) 92 { 93 EnableWindow(hWnd, TRUE); 94 SetForegroundWindow(hWnd); 95 SetFocus(hWnd); 96 } 97 98 SetLastError(PortThreadInfo.dwErrorCode); 99 return (PortThreadInfo.dwErrorCode == ERROR_SUCCESS); 100 } 101 102 BOOL WINAPI 103 GetMonitorUIFullName( PWSTR pDeviceName, PWSTR *pModuleName ) 104 { 105 STRSAFE_LPWSTR SysDir; 106 UINT length; 107 HRESULT hr; 108 109 *pModuleName = NULL; 110 111 SysDir = HeapAlloc(hProcessHeap, 0, MAX_PATH*sizeof(WCHAR)); 112 113 if ( SysDir ) 114 { 115 memset( SysDir, 0, MAX_PATH*sizeof(WCHAR) ); 116 117 length = GetSystemDirectoryW( SysDir, MAX_PATH*sizeof(WCHAR) ); 118 119 if ( length > 0 ) 120 { 121 StringCbCatW(SysDir, MAX_PATH*sizeof(WCHAR), L"\\"); 122 123 hr = StringCchCatW( SysDir, MAX_PATH*sizeof(WCHAR), pDeviceName ); 124 if ( !FAILED(hr) ) 125 { 126 *pModuleName = SysDir; 127 return TRUE; 128 } 129 SetLastError(HRESULT_CODE(hr)); 130 } 131 132 HeapFree(hProcessHeap, 0, SysDir); 133 } 134 return FALSE; 135 } 136 137 BOOL WINAPI 138 GetMonitorUIActivationContext( PWSTR pDeviceName, PMONITORUIDATA pmuid ) 139 { 140 // ACTCTXW actctx; 141 // HANDLE handle; 142 BOOL Ret = FALSE; 143 144 FIXME("GMUIAC : Module pDeviceName %S\n",pDeviceName); 145 146 if ( !GetMonitorUIFullName( pDeviceName, &pmuid->pModuleName ) ) 147 { 148 ERR("GetMonitorUIFullName Failed\n"); 149 return Ret; 150 } 151 /* OMG! SxS again? 152 memset(&actctx, 0, sizeof(ACTCTXW)); 153 actctx.cbSize = sizeof(ACTCTXW); 154 actctx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID; 155 actctx.lpResourceName = MAKEINTRESOURCEW(123); This might be the reason.... 156 actctx.lpSource = pmuid->pModuleName; 157 158 handle = CreateActCtxW(&actctx); 159 160 if ( handle != INVALID_HANDLE_VALUE ) 161 { 162 pmuid->hActCtx = handle; 163 if ( ActivateActCtx( handle, &pmuid->ulpCookie ) ) 164 { 165 pmuid->Activeated = TRUE; 166 Ret = TRUE; 167 } 168 else 169 { 170 pmuid->Activeated = FALSE; 171 } 172 } 173 else 174 { 175 ERR("GetMonitorUIActivationContext Failed %S\n",pmuid->pModuleName); 176 }*/ 177 pmuid->hActCtx = INVALID_HANDLE_VALUE; 178 Ret = TRUE; 179 return Ret; 180 } 181 182 VOID FASTCALL 183 FreeMonitorUI( PMONITORUIDATA pmuid ) 184 { 185 if ( pmuid ) 186 { 187 if ( pmuid->hLibrary ) 188 { 189 FreeLibrary( pmuid->hLibrary ); 190 } 191 if ( pmuid->Activeated ) 192 { 193 DeactivateActCtx( 0, pmuid->ulpCookie ); 194 } 195 if ( pmuid->hActCtx != INVALID_HANDLE_VALUE ) 196 { 197 ReleaseActCtx( pmuid->hActCtx ); 198 } 199 if ( pmuid->pModuleName ) 200 { 201 DllFreeSplMem( pmuid->pModuleName ); 202 } 203 DllFreeSplMem( pmuid ); 204 } 205 } 206 207 BOOL FASTCALL 208 StrNCatBuff( PWSTR ptr, size_t Size, PWSTR args, ...) 209 { 210 va_list Args; 211 PWSTR pwstr; 212 HRESULT hr; 213 BOOL Ret = TRUE; 214 215 va_start(Args, args ); 216 217 for ( pwstr = args ; pwstr ; pwstr = va_arg( Args, PWSTR ) ) 218 { 219 hr = StringCchCatNW( ptr, Size, pwstr, wcslen(pwstr) ); 220 if ( FAILED(hr) ) 221 { 222 SetLastError(HRESULT_CODE(hr)); 223 Ret = FALSE; 224 break; 225 } 226 } 227 228 va_end(Args); 229 230 return Ret; 231 } 232 233 PWSTR WINAPI 234 ConstructXcvName( PWSTR pName, PWSTR pMonitorPortName, PWSTR pXcvName ) 235 { 236 BOOL Ret = FALSE; 237 PWSTR pwstr = NULL; 238 size_t sXcv, smpn = 0, Size = 0; 239 240 if ( pName ) 241 { 242 Size = wcslen( pName ) + 1; 243 } 244 245 sXcv = wcslen( pXcvName ) + Size; 246 247 if ( pMonitorPortName ) 248 { 249 smpn = wcslen( pMonitorPortName ); 250 } 251 252 Size = sXcv + smpn + 3; 253 254 pwstr = DllAllocSplMem( Size * sizeof(WCHAR) ); 255 256 memset( pwstr, 0, Size ); 257 258 if ( pwstr ) 259 { 260 // The caller wants an Xcv handle and provided a string like: 261 // ", XcvMonitor Local Port" 262 // "\\COMPUTERNAME\, XcvMonitor Local Port" 263 // ", XcvPort LPT1:" 264 // "\\COMPUTERNAME\, XcvPort LPT1:" 265 // 266 // This produces; !pName ",XcvMonitor " or pName "\\COMPUTERNAME\XcvMonitor " 267 // 268 Ret = StrNCatBuff( pwstr, 269 Size, 270 pName ? pName : L"", 271 pName ? L"\\" : L",", 272 pXcvName, 273 L" ", 274 pMonitorPortName ? pMonitorPortName : L"", 275 NULL ); 276 } 277 278 if ( !Ret ) 279 { 280 DllFreeSplMem( pwstr ); 281 pwstr = NULL; 282 } 283 284 return pwstr; 285 } 286 287 DWORD WINAPI 288 GetMonitorUI( PWSTR pName, PWSTR pMonitorPortName, PWSTR pXcvName, PMONITORUI *pmui, PMONITORUIDATA *ppmuid ) 289 { 290 DWORD dwErrorCode = ERROR_SUCCESS, cbOutputNeeded, dwStatus; 291 HANDLE hPrinter = NULL; 292 HMODULE hModule; 293 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 294 PWSTR pDevice = NULL, pOutputString = NULL; 295 PMONITORUIDATA pmuid = NULL; 296 PRINTER_DEFAULTSW wDefault = { 0, 0, PRINTER_ATTRIBUTE_QUEUED }; 297 BYTE OutputData[1024], InputData[4]; 298 299 *pmui = NULL; 300 *ppmuid = NULL; 301 302 pDevice = ConstructXcvName( pName, pMonitorPortName, pXcvName ); 303 304 if ( !pDevice ) 305 { 306 return GetLastError(); 307 } 308 309 FIXME("GMUI : XcvName : %S\n",pDevice); 310 311 if ( OpenPrinterW( (LPWSTR)pDevice, &hPrinter, &wDefault ) ) 312 { 313 pHandle = (PSPOOLER_HANDLE)hPrinter; 314 315 // Do the RPC call 316 RpcTryExcept 317 { 318 dwErrorCode = _RpcXcvData( pHandle->hPrinter, 319 L"MonitorUI", 320 (PBYTE)&InputData, 321 0, 322 (PBYTE)&OutputData, 323 1024, 324 &cbOutputNeeded, 325 &dwStatus ); 326 } 327 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 328 { 329 dwErrorCode = RpcExceptionCode(); 330 ERR("GMUI : _RpcXcvData failed with exception code %lu!\n", dwErrorCode); 331 } 332 RpcEndExcept; 333 334 if ( dwErrorCode == ERROR_INSUFFICIENT_BUFFER ) 335 { 336 pOutputString = DllAllocSplMem( cbOutputNeeded ); 337 338 // Do the RPC call 339 RpcTryExcept 340 { 341 dwErrorCode = _RpcXcvData( pHandle->hPrinter, 342 L"MonitorUI", 343 (PBYTE)&InputData, 344 0, 345 (PBYTE)pOutputString, 346 cbOutputNeeded, 347 &cbOutputNeeded, 348 &dwStatus ); 349 } 350 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 351 { 352 dwErrorCode = RpcExceptionCode(); 353 ERR("GMUI : _RpcXcvData failed with exception code %lu!\n", dwErrorCode); 354 } 355 RpcEndExcept; 356 } 357 358 if ( dwErrorCode != ERROR_SUCCESS || dwStatus != ERROR_SUCCESS ) 359 { 360 goto Cleanup; 361 } 362 363 pmuid = DllAllocSplMem( sizeof(MONITORUIDATA) ); 364 if ( pmuid ) 365 { 366 memset( pmuid, 0, sizeof(MONITORUIDATA) ); 367 pmuid->hActCtx = INVALID_HANDLE_VALUE; 368 } 369 else 370 { 371 ERR("GMUI : Memory error\n"); 372 dwErrorCode = GetLastError(); 373 goto Cleanup; 374 } 375 376 if ( GetMonitorUIActivationContext( pOutputString ? pOutputString : (PWSTR)&OutputData, pmuid ) ) 377 { 378 FIXME("GMUI : MonitorUI Path : %S\n",pmuid->pModuleName); 379 380 hModule = LoadLibraryW( pmuid->pModuleName ); 381 if ( hModule ) 382 { 383 FARPROC fpInitializePrintMonitorUI = (PVOID) GetProcAddress( hModule, "InitializePrintMonitorUI" ); 384 if ( fpInitializePrintMonitorUI ) 385 { 386 pmuid->hLibrary = hModule; 387 *pmui = (PMONITORUI)(*fpInitializePrintMonitorUI)(); 388 *ppmuid = pmuid; 389 } 390 else 391 { 392 ERR("GMUI : Failed to get MUI %S\n",pmuid->pModuleName); 393 FreeMonitorUI( pmuid ); 394 } 395 } 396 else 397 { 398 ERR("GMUI : Failed to load library %S\n",pmuid->pModuleName); 399 } 400 } 401 } 402 else 403 { 404 ERR("GMUI : Failed to open printer handle\n"); 405 } 406 407 dwErrorCode = GetLastError(); 408 409 Cleanup: 410 if ( hPrinter ) ClosePrinter( hPrinter ); 411 if ( pOutputString ) DllFreeSplMem( pOutputString ); 412 if ( pDevice ) DllFreeSplMem( pDevice ); 413 414 FIXME("GMUI : Error Code Exit %d\n",dwErrorCode); 415 416 return dwErrorCode; 417 } 418 419 BOOL WINAPI 420 AddPortA(PSTR pName, HWND hWnd, PSTR pMonitorName) 421 { 422 LPWSTR nameW = NULL; 423 LPWSTR monitorW = NULL; 424 DWORD len; 425 BOOL res; 426 427 TRACE("AddPortA(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName)); 428 429 if (pName) 430 { 431 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0); 432 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 433 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len); 434 } 435 436 if (pMonitorName) 437 { 438 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0); 439 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 440 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len); 441 } 442 443 res = AddPortW(nameW, hWnd, monitorW); 444 445 if (nameW) HeapFree(GetProcessHeap(), 0, nameW); 446 if (monitorW) HeapFree(GetProcessHeap(), 0, monitorW); 447 448 return res; 449 } 450 451 BOOL WINAPI 452 AddPortExW(PWSTR pName, DWORD Level, PBYTE lpBuffer, PWSTR lpMonitorName) 453 { 454 DWORD dwErrorCode; 455 WINSPOOL_PORT_CONTAINER PortInfoContainer; 456 WINSPOOL_PORT_VAR_CONTAINER PortVarContainer; 457 WINSPOOL_PORT_INFO_FF *pPortInfoFF; 458 459 FIXME("AddPortExW(%S, %lu, %p, %S)\n", pName, Level, lpBuffer, lpMonitorName); 460 461 switch (Level) 462 { 463 case 1: 464 // FIXME!!!! Only Level 1 is supported? See note in wine winspool test info.c : line 575. It's just not supported here. 465 PortInfoContainer.PortInfo.pPortInfo1 = (WINSPOOL_PORT_INFO_1*)lpBuffer; 466 PortInfoContainer.Level = Level; 467 PortVarContainer.cbMonitorData = 0; 468 PortVarContainer.pMonitorData = NULL; 469 break; 470 471 case 0xFFFFFFFF: 472 pPortInfoFF = (WINSPOOL_PORT_INFO_FF*)lpBuffer; 473 PortInfoContainer.PortInfo.pPortInfoFF = pPortInfoFF; 474 PortInfoContainer.Level = Level; 475 PortVarContainer.cbMonitorData = pPortInfoFF->cbMonitorData; 476 PortVarContainer.pMonitorData = pPortInfoFF->pMonitorData; 477 break; 478 479 default: 480 ERR("Level = %d, unsupported!\n", Level); 481 SetLastError(ERROR_INVALID_LEVEL); 482 return FALSE; 483 } 484 485 // Do the RPC call 486 RpcTryExcept 487 { 488 dwErrorCode = _RpcAddPortEx(pName, &PortInfoContainer, &PortVarContainer, lpMonitorName); 489 } 490 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 491 { 492 dwErrorCode = RpcExceptionCode(); 493 } 494 RpcEndExcept; 495 496 SetLastError(dwErrorCode); 497 return (dwErrorCode == ERROR_SUCCESS); 498 } 499 500 BOOL WINAPI 501 AddPortExA(PSTR pName, DWORD Level, PBYTE lpBuffer, PSTR lpMonitorName) 502 { 503 PORT_INFO_1W pi1W; 504 PORT_INFO_1A * pi1A; 505 LPWSTR nameW = NULL; 506 LPWSTR monitorW = NULL; 507 DWORD len; 508 BOOL res = FALSE; 509 WINSPOOL_PORT_INFO_FF *pPortInfoFF, PortInfoFF; 510 511 pi1A = (PORT_INFO_1A *)lpBuffer; 512 pPortInfoFF = (WINSPOOL_PORT_INFO_FF*)lpBuffer; 513 514 FIXME("AddPortExA(%s, %d, %p, %s): %s\n", debugstr_a(pName), Level, lpBuffer, debugstr_a(lpMonitorName), debugstr_a(pi1A ? pi1A->pName : NULL)); 515 516 if ( !lpBuffer || !lpMonitorName ) 517 { 518 SetLastError(ERROR_INVALID_PARAMETER); 519 return FALSE; 520 } 521 522 if (pName) 523 { 524 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0); 525 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 526 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len); 527 } 528 529 if (lpMonitorName) 530 { 531 len = MultiByteToWideChar(CP_ACP, 0, lpMonitorName, -1, NULL, 0); 532 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 533 MultiByteToWideChar(CP_ACP, 0, lpMonitorName, -1, monitorW, len); 534 } 535 536 pi1W.pName = NULL; 537 ZeroMemory( &PortInfoFF, sizeof(WINSPOOL_PORT_INFO_FF)); 538 539 switch ( Level ) 540 { 541 case 1: 542 if ( pi1A->pName ) 543 { 544 len = MultiByteToWideChar(CP_ACP, 0, pi1A->pName, -1, NULL, 0); 545 pi1W.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 546 MultiByteToWideChar(CP_ACP, 0, pi1A->pName, -1, pi1W.pName, len); 547 } 548 break; 549 550 case 0xFFFFFFFF: 551 // 552 // Remember the calling parameter is Ansi. 553 // 554 if ( !pPortInfoFF->pPortName || !(PCHAR)pPortInfoFF->pPortName ) 555 { 556 SetLastError(ERROR_INVALID_PARAMETER); 557 goto Cleanup; 558 } 559 560 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pPortInfoFF->pPortName, -1, NULL, 0); 561 PortInfoFF.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 562 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pPortInfoFF->pPortName, -1, (LPWSTR)PortInfoFF.pPortName, len); 563 564 PortInfoFF.cbMonitorData = pPortInfoFF->cbMonitorData; 565 PortInfoFF.pMonitorData = pPortInfoFF->pMonitorData; 566 break; 567 568 default: 569 ERR("Level = %d, unsupported!\n", Level); 570 SetLastError(ERROR_INVALID_LEVEL); 571 goto Cleanup; 572 } 573 574 res = AddPortExW( nameW, Level, Level == 1 ? (PBYTE)&pi1W : (PBYTE)&PortInfoFF, monitorW ); 575 576 Cleanup: 577 if (nameW) HeapFree(GetProcessHeap(), 0, nameW); 578 if (monitorW) HeapFree(GetProcessHeap(), 0, monitorW); 579 if (pi1W.pName) HeapFree(GetProcessHeap(), 0, pi1W.pName); 580 if (PortInfoFF.pPortName) HeapFree(GetProcessHeap(), 0, PortInfoFF.pPortName); 581 582 return res; 583 } 584 585 BOOL WINAPI 586 AddPortW(PWSTR pName, HWND hWnd, PWSTR pMonitorName) 587 { 588 DWORD SessionId, dwErrorCode = 0; 589 PMONITORUIDATA pmuid; 590 PMONITORUI pmui = NULL; 591 BOOL Ret = FALSE; 592 593 FIXME("AddPortW(%S, %p, %S)\n", pName, hWnd, pMonitorName); 594 595 dwErrorCode = GetMonitorUI( pName, pMonitorName, L"XcvMonitor", &pmui, &pmuid ); 596 FIXME("AddPortW Error %d\n",dwErrorCode); 597 if (dwErrorCode != ERROR_SUCCESS ) 598 { 599 if ( dwErrorCode == ERROR_NOT_SUPPORTED || 600 dwErrorCode == ERROR_MOD_NOT_FOUND || 601 dwErrorCode == ERROR_INVALID_PRINT_MONITOR || 602 dwErrorCode == ERROR_UNKNOWN_PORT || 603 dwErrorCode == ERROR_INVALID_PRINTER_NAME ) 604 { 605 if ( ProcessIdToSessionId( GetCurrentProcessId(), &SessionId ) && SessionId ) // Looking if this is remote. 606 { 607 dwErrorCode = ERROR_NOT_SUPPORTED; 608 } 609 else 610 { 611 Ret = StartPortThread( pName, hWnd, pMonitorName, (PPfpFunction)_RpcAddPort ); 612 FIXME("AddPortW return StartPortThread\n"); 613 dwErrorCode = GetLastError(); 614 } 615 } 616 } 617 else 618 { 619 Ret = (*pmui->pfnAddPortUI)( pName, hWnd, pMonitorName, NULL ); 620 } 621 622 SetLastError(dwErrorCode); 623 FreeMonitorUI( pmuid ); 624 625 return Ret; 626 } 627 628 BOOL WINAPI 629 ConfigurePortA(PSTR pName, HWND hWnd, PSTR pPortName) 630 { 631 LPWSTR nameW = NULL; 632 LPWSTR portW = NULL; 633 INT len; 634 DWORD res; 635 636 TRACE("ConfigurePortA(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName)); 637 638 /* convert servername to unicode */ 639 if (pName) 640 { 641 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0); 642 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 643 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len); 644 } 645 646 /* convert portname to unicode */ 647 if (pPortName) 648 { 649 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0); 650 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 651 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len); 652 } 653 654 res = ConfigurePortW(nameW, hWnd, portW); 655 656 if (nameW) HeapFree(GetProcessHeap(), 0, nameW); 657 if (portW) HeapFree(GetProcessHeap(), 0, portW); 658 659 return res; 660 } 661 662 BOOL WINAPI 663 ConfigurePortW(PWSTR pName, HWND hWnd, PWSTR pPortName) 664 { 665 DWORD SessionId, dwErrorCode = 0; 666 PMONITORUIDATA pmuid; 667 PMONITORUI pmui = NULL; 668 BOOL Ret = FALSE; 669 670 FIXME("ConfigurePortW(%S, %p, %S)\n", pName, hWnd, pPortName); 671 672 dwErrorCode = GetMonitorUI( pName, pPortName, L"XcvPort", &pmui, &pmuid ); 673 674 if (dwErrorCode != ERROR_SUCCESS ) 675 { 676 if ( dwErrorCode == ERROR_NOT_SUPPORTED || 677 dwErrorCode == ERROR_MOD_NOT_FOUND || 678 dwErrorCode == ERROR_INVALID_PRINT_MONITOR || 679 dwErrorCode == ERROR_UNKNOWN_PORT || 680 dwErrorCode == ERROR_INVALID_PRINTER_NAME ) 681 { 682 if ( ProcessIdToSessionId( GetCurrentProcessId(), &SessionId ) && SessionId ) // Looking if this is remote. 683 { 684 dwErrorCode = ERROR_NOT_SUPPORTED; 685 } 686 else 687 { 688 Ret = StartPortThread(pName, hWnd, pPortName, (PPfpFunction)_RpcConfigurePort ); 689 dwErrorCode = GetLastError(); 690 } 691 } 692 } 693 else 694 { 695 Ret = (*pmui->pfnConfigurePortUI)( pName, hWnd, pPortName ); 696 } 697 698 SetLastError(dwErrorCode); 699 FreeMonitorUI( pmuid ); 700 701 return Ret; 702 } 703 704 BOOL WINAPI 705 DeletePortA(PSTR pName, HWND hWnd, PSTR pPortName) 706 { 707 LPWSTR nameW = NULL; 708 LPWSTR portW = NULL; 709 INT len; 710 DWORD res; 711 712 FIXME("DeletePortA(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName)); 713 714 /* convert servername to unicode */ 715 if (pName) 716 { 717 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0); 718 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 719 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len); 720 } 721 722 /* convert portname to unicode */ 723 if (pPortName) 724 { 725 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0); 726 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 727 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len); 728 } 729 730 res = DeletePortW(nameW, hWnd, portW); 731 732 if (nameW) HeapFree(GetProcessHeap(), 0, nameW); 733 if (portW) HeapFree(GetProcessHeap(), 0, portW); 734 735 return res; 736 } 737 738 BOOL WINAPI 739 DeletePortW(PWSTR pName, HWND hWnd, PWSTR pPortName) 740 { 741 DWORD dwErrorCode = 0; 742 PMONITORUIDATA pmuid; 743 PMONITORUI pmui = NULL; 744 BOOL Ret = FALSE; 745 746 FIXME("DeletePortW(%S, %p, %S)\n", pName, hWnd, pPortName); 747 748 dwErrorCode = GetMonitorUI( pName, pPortName, L"XcvPort", &pmui, &pmuid ); 749 FIXME("DeletePortW Error %d\n",dwErrorCode); 750 if (dwErrorCode != ERROR_SUCCESS ) 751 { 752 if ( dwErrorCode == ERROR_NOT_SUPPORTED || 753 dwErrorCode == ERROR_MOD_NOT_FOUND || 754 dwErrorCode == ERROR_INVALID_PRINT_MONITOR || 755 dwErrorCode == ERROR_UNKNOWN_PORT || 756 dwErrorCode == ERROR_INVALID_PRINTER_NAME ) 757 { 758 Ret = StartPortThread(pName, hWnd, pPortName, (PPfpFunction)_RpcDeletePort ); 759 dwErrorCode = GetLastError(); 760 } 761 } 762 else 763 { 764 Ret = (*pmui->pfnDeletePortUI)( pName, hWnd, pPortName ); 765 } 766 767 SetLastError(dwErrorCode); 768 FreeMonitorUI( pmuid ); 769 770 return Ret; 771 } 772 773 BOOL WINAPI 774 EnumPortsA(PSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned) 775 { 776 BOOL res; 777 LPBYTE bufferW = NULL; 778 LPWSTR nameW = NULL; 779 DWORD needed = 0; 780 DWORD numentries = 0; 781 INT len; 782 783 TRACE("EnumPortsA(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts, cbBuf, pcbNeeded, pcReturned); 784 785 if ((Level < 1) || (Level > 2)) 786 { 787 ERR("Level = %d, unsupported!\n", Level); 788 SetLastError(ERROR_INVALID_LEVEL); 789 return FALSE; 790 } 791 792 /* convert servername to unicode */ 793 if (pName) 794 { 795 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0); 796 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 797 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len); 798 } 799 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */ 800 needed = cbBuf * sizeof(WCHAR); 801 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed); 802 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned); 803 804 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) 805 { 806 if (pcbNeeded) needed = *pcbNeeded; 807 /* HeapReAlloc return NULL, when bufferW was NULL */ 808 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) : 809 HeapAlloc(GetProcessHeap(), 0, needed); 810 811 /* Try again with the large Buffer */ 812 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned); 813 } 814 needed = pcbNeeded ? *pcbNeeded : 0; 815 numentries = pcReturned ? *pcReturned : 0; 816 817 /* 818 W2k require the buffersize from EnumPortsW also for EnumPortsA. 819 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps. 820 */ 821 if (res) 822 { 823 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */ 824 DWORD entrysize = 0; 825 DWORD index; 826 LPSTR ptr; 827 LPPORT_INFO_2W pi2w; 828 LPPORT_INFO_2A pi2a; 829 830 needed = 0; 831 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A); 832 833 /* First pass: calculate the size for all Entries */ 834 pi2w = (LPPORT_INFO_2W) bufferW; 835 pi2a = (LPPORT_INFO_2A) pPorts; 836 index = 0; 837 while (index < numentries) 838 { 839 index++; 840 needed += entrysize; /* PORT_INFO_?A */ 841 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName)); 842 843 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1, 844 NULL, 0, NULL, NULL); 845 if (Level > 1) 846 { 847 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1, 848 NULL, 0, NULL, NULL); 849 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1, 850 NULL, 0, NULL, NULL); 851 } 852 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */ 853 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize); 854 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize); 855 } 856 857 /* check for errors and quit on failure */ 858 if (cbBuf < needed) 859 { 860 SetLastError(ERROR_INSUFFICIENT_BUFFER); 861 res = FALSE; 862 goto cleanup; 863 } 864 len = entrysize * numentries; /* room for all PORT_INFO_?A */ 865 ptr = (LPSTR) &pPorts[len]; /* room for strings */ 866 cbBuf -= len ; /* free Bytes in the user-Buffer */ 867 pi2w = (LPPORT_INFO_2W) bufferW; 868 pi2a = (LPPORT_INFO_2A) pPorts; 869 index = 0; 870 /* Second Pass: Fill the User Buffer (if we have one) */ 871 while ((index < numentries) && pPorts) 872 { 873 index++; 874 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index); 875 pi2a->pPortName = ptr; 876 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1, 877 ptr, cbBuf , NULL, NULL); 878 ptr += len; 879 cbBuf -= len; 880 if (Level > 1) 881 { 882 pi2a->pMonitorName = ptr; 883 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1, 884 ptr, cbBuf, NULL, NULL); 885 ptr += len; 886 cbBuf -= len; 887 888 pi2a->pDescription = ptr; 889 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1, 890 ptr, cbBuf, NULL, NULL); 891 ptr += len; 892 cbBuf -= len; 893 894 pi2a->fPortType = pi2w->fPortType; 895 pi2a->Reserved = 0; /* documented: "must be zero" */ 896 897 } 898 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */ 899 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize); 900 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize); 901 } 902 } 903 904 cleanup: 905 if (pcbNeeded) *pcbNeeded = needed; 906 if (pcReturned) *pcReturned = (res) ? numentries : 0; 907 908 if (nameW) HeapFree(GetProcessHeap(), 0, nameW); 909 if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW); 910 911 TRACE("returning %d with %d (%d byte for %d of %d entries)\n", 912 (res), GetLastError(), needed, (res)? numentries : 0, numentries); 913 914 return (res); 915 } 916 917 BOOL WINAPI 918 EnumPortsW(PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned) 919 { 920 DWORD dwErrorCode; 921 922 TRACE("EnumPortsW(%S, %lu, %p, %lu, %p, %p)\n", pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned); 923 924 if ((Level < 1) || (Level > 2)) 925 { 926 ERR("Level = %d, unsupported!\n", Level); 927 SetLastError(ERROR_INVALID_LEVEL); 928 return FALSE; 929 } 930 931 // Do the RPC call 932 RpcTryExcept 933 { 934 dwErrorCode = _RpcEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned); 935 } 936 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 937 { 938 dwErrorCode = RpcExceptionCode(); 939 ERR("_RpcEnumPorts failed with exception code %lu!\n", dwErrorCode); 940 } 941 RpcEndExcept; 942 943 if (dwErrorCode == ERROR_SUCCESS) 944 { 945 // Replace relative offset addresses in the output by absolute pointers. 946 ASSERT(Level >= 1 && Level <= 2); 947 MarshallUpStructuresArray(cbBuf, pPorts, *pcReturned, pPortInfoMarshalling[Level]->pInfo, pPortInfoMarshalling[Level]->cbStructureSize, TRUE); 948 } 949 950 SetLastError(dwErrorCode); 951 return (dwErrorCode == ERROR_SUCCESS); 952 } 953 954 BOOL WINAPI 955 SetPortA(PSTR pName, PSTR pPortName, DWORD dwLevel, PBYTE pPortInfo) 956 { 957 LPWSTR NameW = NULL; 958 LPWSTR PortNameW = NULL; 959 PORT_INFO_3W pi3W; 960 PORT_INFO_3A *pi3A; 961 DWORD len; 962 BOOL res; 963 964 pi3A = (PORT_INFO_3A*)pPortInfo; 965 966 TRACE("SetPortA(%s, %s, %lu, %p)\n", pName, pPortName, dwLevel, pPortInfo); 967 968 if ( dwLevel != 3 ) 969 { 970 ERR("Level = %d, unsupported!\n", dwLevel); 971 SetLastError(ERROR_INVALID_LEVEL); 972 return FALSE; 973 } 974 975 if (pName) 976 { 977 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0); 978 NameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 979 MultiByteToWideChar(CP_ACP, 0, pName, -1, NameW, len); 980 } 981 982 if (pPortName) 983 { 984 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0); 985 PortNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 986 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, PortNameW, len); 987 } 988 989 if (pi3A->pszStatus) 990 { 991 len = MultiByteToWideChar(CP_ACP, 0, pi3A->pszStatus, -1, NULL, 0); 992 pi3W.pszStatus = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 993 MultiByteToWideChar(CP_ACP, 0, pi3A->pszStatus, -1, pi3W.pszStatus, len); 994 } 995 996 pi3W.dwStatus = pi3A->dwStatus; 997 pi3W.dwSeverity = pi3A->dwSeverity; 998 999 res = SetPortW( NameW, PortNameW, dwLevel, (PBYTE)&pi3W ); 1000 1001 if (NameW) HeapFree(GetProcessHeap(), 0, NameW); 1002 if (PortNameW) HeapFree(GetProcessHeap(), 0, PortNameW); 1003 if (pi3W.pszStatus) HeapFree(GetProcessHeap(), 0, pi3W.pszStatus); 1004 1005 return res; 1006 } 1007 1008 BOOL WINAPI 1009 SetPortW(PWSTR pName, PWSTR pPortName, DWORD dwLevel, PBYTE pPortInfo) 1010 { 1011 DWORD dwErrorCode; 1012 WINSPOOL_PORT_CONTAINER PortInfoContainer; 1013 1014 TRACE("SetPortW(%S, %S, %lu, %p)\n", pName, pPortName, dwLevel, pPortInfo); 1015 1016 if ( dwLevel != 3 ) 1017 { 1018 ERR("Level = %d, unsupported!\n", dwLevel); 1019 SetLastError(ERROR_INVALID_LEVEL); 1020 return FALSE; 1021 } 1022 1023 PortInfoContainer.PortInfo.pPortInfo3 = (WINSPOOL_PORT_INFO_3*)pPortInfo; 1024 PortInfoContainer.Level = dwLevel; 1025 1026 // Do the RPC call 1027 RpcTryExcept 1028 { 1029 dwErrorCode = _RpcSetPort(pName, pPortName, &PortInfoContainer); 1030 } 1031 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 1032 { 1033 dwErrorCode = RpcExceptionCode(); 1034 } 1035 RpcEndExcept; 1036 1037 SetLastError(dwErrorCode); 1038 return (dwErrorCode == ERROR_SUCCESS); 1039 } 1040