[Printing] Update and Add Functions
[reactos.git] / win32ss / printing / base / winspool / ports.c
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 }