2 * PROJECT: ReactOS Local Port Monitor
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Implementation of Xcv* and support functions
5 * COPYRIGHT: Copyright 2015 Colin Finck (colin@reactos.org)
11 _HandleAddPort(PLOCALMON_XCV pXcv
, PBYTE pInputData
, PDWORD pcbOutputNeeded
)
13 return ERROR_CALL_NOT_IMPLEMENTED
;
17 * @name _HandleConfigureLPTPortCommandOK
19 * Writes the value for "TransmissionRetryTimeout" to the registry. Checks for granted SERVER_ACCESS_ADMINISTER access.
20 * Actually the opposite of _HandleGetTransmissionRetryTimeout, but name kept for compatibility.
23 * Pointer to the LOCALMON_XCV structure of the currently opened Xcv port.
26 * Pointer to a Unicode string containing the value to be written to the registry.
28 * @param pcbOutputNeeded
29 * Pointer to a DWORD that will be zeroed on return.
32 * An error code indicating success or failure.
35 _HandleConfigureLPTPortCommandOK(PLOCALMON_XCV pXcv
, PBYTE pInputData
, PDWORD pcbOutputNeeded
)
43 if (!pXcv
|| !pInputData
|| !pcbOutputNeeded
)
45 dwErrorCode
= ERROR_INVALID_PARAMETER
;
51 // This action can only happen at SERVER_ACCESS_ADMINISTER access level.
52 if (!(pXcv
->GrantedAccess
& SERVER_ACCESS_ADMINISTER
))
54 dwErrorCode
= ERROR_ACCESS_DENIED
;
58 // Switch to the SYSTEM context for modifying the registry.
59 hToken
= RevertToPrinterSelf();
62 dwErrorCode
= GetLastError();
63 ERR("RevertToPrinterSelf failed with error %lu!\n", dwErrorCode
);
67 // Open the key where our value is stored.
68 dwErrorCode
= (DWORD
)RegOpenKeyExW(HKEY_LOCAL_MACHINE
, L
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows", 0, KEY_SET_VALUE
, &hKey
);
69 if (dwErrorCode
!= ERROR_SUCCESS
)
71 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode
);
75 // We don't use cbInputData here, because the buffer pInputData could be bigger than the data it contains.
76 cbBuffer
= (wcslen((PWSTR
)pInputData
) + 1) * sizeof(WCHAR
);
78 // Write the value to the registry.
79 dwErrorCode
= (DWORD
)RegSetValueExW(hKey
, L
"TransmissionRetryTimeout", 0, REG_SZ
, pInputData
, cbBuffer
);
80 if (dwErrorCode
!= ERROR_SUCCESS
)
82 ERR("RegSetValueExW failed with status %lu!\n", dwErrorCode
);
91 ImpersonatePrinterClient(hToken
);
97 _HandleDeletePort(PLOCALMON_XCV pXcv
, PBYTE pInputData
, PDWORD pcbOutputNeeded
)
99 return ERROR_CALL_NOT_IMPLEMENTED
;
103 * @name _HandleGetDefaultCommConfig
105 * Gets the default configuration of a legacy port.
106 * The opposite function is _HandleSetDefaultCommConfig.
109 * The port name (without colon!) whose default configuration you want to get.
112 * Pointer to a COMMCONFIG structure that will receive the configuration information.
114 * @param cbOutputData
115 * Size of the variable pointed to by pOutputData.
117 * @param pcbOutputNeeded
118 * Pointer to a DWORD that contains the required size for pOutputData on return.
121 * An error code indicating success or failure.
124 _HandleGetDefaultCommConfig(PBYTE pInputData
, PBYTE pOutputData
, DWORD cbOutputData
, PDWORD pcbOutputNeeded
)
127 if (!pInputData
|| !pcbOutputNeeded
)
128 return ERROR_INVALID_PARAMETER
;
130 *pcbOutputNeeded
= sizeof(COMMCONFIG
);
132 // Check if the supplied buffer is large enough.
133 if (cbOutputData
< *pcbOutputNeeded
)
134 return ERROR_INSUFFICIENT_BUFFER
;
136 // Finally get the port configuration.
137 if (!GetDefaultCommConfigW((PCWSTR
)pInputData
, (LPCOMMCONFIG
)pOutputData
, pcbOutputNeeded
))
138 return GetLastError();
140 return ERROR_SUCCESS
;
144 * @name _HandleGetTransmissionRetryTimeout
146 * Reads the value for "TransmissionRetryTimeout" from the registry and converts it to a DWORD.
147 * The opposite function is _HandleConfigureLPTPortCommandOK.
150 * Pointer to a DWORD that will receive the timeout value.
152 * @param cbOutputData
153 * Size of the variable pointed to by pOutputData.
155 * @param pcbOutputNeeded
156 * Pointer to a DWORD that contains the required size for pOutputData on return.
159 * An error code indicating success or failure.
162 _HandleGetTransmissionRetryTimeout(PBYTE pOutputData
, DWORD cbOutputData
, PDWORD pcbOutputNeeded
)
167 if (!pOutputData
|| !pcbOutputNeeded
)
168 return ERROR_INVALID_PARAMETER
;
170 *pcbOutputNeeded
= sizeof(DWORD
);
172 // Check if the supplied buffer is large enough.
173 if (cbOutputData
< *pcbOutputNeeded
)
174 return ERROR_INSUFFICIENT_BUFFER
;
176 // Retrieve and copy the number.
177 dwTimeout
= GetLPTTransmissionRetryTimeout();
178 CopyMemory(pOutputData
, &dwTimeout
, sizeof(DWORD
));
179 return ERROR_SUCCESS
;
183 * @name _HandleMonitorUI
185 * Returns the filename of the associated UI DLL for this Port Monitor.
188 * Pointer to a Unicode string that will receive the DLL filename.
190 * @param cbOutputData
191 * Size of the variable pointed to by pOutputData.
193 * @param pcbOutputNeeded
194 * Pointer to a DWORD that contains the required size for pOutputData on return.
197 * An error code indicating success or failure.
200 _HandleMonitorUI(PBYTE pOutputData
, DWORD cbOutputData
, PDWORD pcbOutputNeeded
)
202 const WCHAR wszMonitorUI
[] = L
"LocalUI.dll";
205 if (!pOutputData
|| !pcbOutputNeeded
)
206 return ERROR_INVALID_PARAMETER
;
208 *pcbOutputNeeded
= sizeof(wszMonitorUI
);
210 // Check if the supplied buffer is large enough.
211 if (cbOutputData
< *pcbOutputNeeded
)
212 return ERROR_INSUFFICIENT_BUFFER
;
215 CopyMemory(pOutputData
, wszMonitorUI
, sizeof(wszMonitorUI
));
216 return ERROR_SUCCESS
;
220 * @name _HandlePortExists
222 * Checks all Port Monitors installed on the local system to find out if a given port already exists.
225 * Pointer to a Unicode string specifying the port name to check.
228 * Pointer to a BOOL that receives the result of the check.
230 * @param cbOutputData
231 * Size of the variable pointed to by pOutputData.
233 * @param pcbOutputNeeded
234 * Pointer to a DWORD that contains the required size for pOutputData on return.
237 * An error code indicating success or failure.
240 _HandlePortExists(PBYTE pInputData
, PBYTE pOutputData
, DWORD cbOutputData
, PDWORD pcbOutputNeeded
)
243 if (!pInputData
|| !pOutputData
|| !pcbOutputNeeded
)
244 return ERROR_INVALID_PARAMETER
;
246 *pcbOutputNeeded
= sizeof(BOOL
);
248 // Check if the supplied buffer is large enough.
249 if (cbOutputData
< *pcbOutputNeeded
)
250 return ERROR_INSUFFICIENT_BUFFER
;
252 // Return the check result and error code.
253 *(PBOOL
)pOutputData
= DoesPortExist((PCWSTR
)pInputData
);
254 return GetLastError();
258 _HandlePortIsValid(PBYTE pInputData
, PBYTE pOutputData
, DWORD cbOutputData
, PDWORD pcbOutputNeeded
)
260 return ERROR_CALL_NOT_IMPLEMENTED
;
264 * @name _HandleSetDefaultCommConfig
266 * Sets the default configuration of a legacy port. Checks for granted SERVER_ACCESS_ADMINISTER access.
267 * You have to supply the port name (with colon!) in XcvOpenPort.
268 * The opposite function is _HandleGetDefaultCommConfig.
271 * Pointer to the LOCALMON_XCV structure of the currently opened Xcv port.
274 * Pointer to the COMMCONFIG structure that shall be passed to SetDefaultCommConfigW.
276 * @param pcbOutputNeeded
277 * Pointer to a DWORD that will be zeroed on return.
280 * An error code indicating success or failure.
283 _HandleSetDefaultCommConfig(PLOCALMON_XCV pXcv
, PBYTE pInputData
, PDWORD pcbOutputNeeded
)
286 HANDLE hToken
= NULL
;
287 LPCOMMCONFIG pCommConfig
;
288 PWSTR pwszPortNameWithoutColon
= NULL
;
291 // pwszObject needs to be at least 2 characters long to be a port name with a trailing colon.
292 if (!pXcv
|| !pXcv
->pwszObject
|| !pXcv
->pwszObject
[0] || !pXcv
->pwszObject
[1] || !pInputData
|| !pcbOutputNeeded
)
294 dwErrorCode
= ERROR_INVALID_PARAMETER
;
298 *pcbOutputNeeded
= 0;
300 // This action can only happen at SERVER_ACCESS_ADMINISTER access level.
301 if (!(pXcv
->GrantedAccess
& SERVER_ACCESS_ADMINISTER
))
303 dwErrorCode
= ERROR_ACCESS_DENIED
;
307 // SetDefaultCommConfigW needs the port name without colon.
308 dwErrorCode
= GetPortNameWithoutColon(pXcv
->pwszObject
, &pwszPortNameWithoutColon
);
309 if (dwErrorCode
!= ERROR_SUCCESS
)
312 // Switch to the SYSTEM context for setting the port configuration.
313 hToken
= RevertToPrinterSelf();
316 dwErrorCode
= GetLastError();
317 ERR("RevertToPrinterSelf failed with error %lu!\n", dwErrorCode
);
321 // Finally pass the parameters to SetDefaultCommConfigW.
322 pCommConfig
= (LPCOMMCONFIG
)pInputData
;
323 if (!SetDefaultCommConfigW(pwszPortNameWithoutColon
, pCommConfig
, pCommConfig
->dwSize
))
325 dwErrorCode
= GetLastError();
326 ERR("SetDefaultCommConfigW failed with error %lu!\n", dwErrorCode
);
330 dwErrorCode
= ERROR_SUCCESS
;
334 ImpersonatePrinterClient(hToken
);
336 if (pwszPortNameWithoutColon
)
337 DllFreeSplMem(pwszPortNameWithoutColon
);
343 LocalmonXcvClosePort(HANDLE hXcv
)
345 PLOCALMON_XCV pXcv
= (PLOCALMON_XCV
)hXcv
;
347 TRACE("LocalmonXcvClosePort(%p)\n", hXcv
);
352 SetLastError(ERROR_INVALID_PARAMETER
);
356 // Remove it from the list and free the memory.
357 RemoveEntryList(&pXcv
->Entry
);
360 SetLastError(ERROR_SUCCESS
);
365 LocalmonXcvDataPort(HANDLE hXcv
, PCWSTR pszDataName
, PBYTE pInputData
, DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
, PDWORD pcbOutputNeeded
)
367 TRACE("LocalmonXcvDataPort(%p, %S, %p, %lu, %p, %lu, %p)\n", hXcv
, pszDataName
, pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
371 return ERROR_INVALID_PARAMETER
;
373 // Call the appropriate handler for the requested data name.
374 if (wcscmp(pszDataName
, L
"AddPort") == 0)
375 return _HandleAddPort((PLOCALMON_XCV
)hXcv
, pInputData
, pcbOutputNeeded
);
377 if (wcscmp(pszDataName
, L
"ConfigureLPTPortCommandOK") == 0)
378 return _HandleConfigureLPTPortCommandOK((PLOCALMON_XCV
)hXcv
, pInputData
, pcbOutputNeeded
);
380 if (wcscmp(pszDataName
, L
"DeletePort") == 0)
381 return _HandleDeletePort((PLOCALMON_XCV
)hXcv
, pInputData
, pcbOutputNeeded
);
383 if (wcscmp(pszDataName
, L
"GetDefaultCommConfig") == 0)
384 return _HandleGetDefaultCommConfig(pInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
386 if (wcscmp(pszDataName
, L
"GetTransmissionRetryTimeout") == 0)
387 return _HandleGetTransmissionRetryTimeout(pOutputData
, cbOutputData
, pcbOutputNeeded
);
389 if (wcscmp(pszDataName
, L
"MonitorUI") == 0)
390 return _HandleMonitorUI(pOutputData
, cbOutputData
, pcbOutputNeeded
);
392 if (wcscmp(pszDataName
, L
"PortExists") == 0)
393 return _HandlePortExists(pInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
395 if (wcscmp(pszDataName
, L
"PortIsValid") == 0)
396 return _HandlePortIsValid(pInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
398 if (wcscmp(pszDataName
, L
"SetDefaultCommConfig") == 0)
399 return _HandleSetDefaultCommConfig((PLOCALMON_XCV
)hXcv
, pInputData
, pcbOutputNeeded
);
401 return ERROR_INVALID_PARAMETER
;
405 LocalmonXcvOpenPort(HANDLE hMonitor
, PCWSTR pwszObject
, ACCESS_MASK GrantedAccess
, PHANDLE phXcv
)
409 PLOCALMON_HANDLE pLocalmon
= (PLOCALMON_HANDLE
)hMonitor
;
412 TRACE("LocalmonXcvOpenPort(%p, %S, %lu, %p)\n", hMonitor
, pwszObject
, GrantedAccess
, phXcv
);
415 if (!pLocalmon
|| !phXcv
)
417 dwErrorCode
= ERROR_INVALID_PARAMETER
;
422 cbObject
= (wcslen(pwszObject
) + 1) * sizeof(WCHAR
);
424 // Create a new LOCALMON_XCV structure and fill the relevant fields.
425 pXcv
= DllAllocSplMem(sizeof(LOCALMON_XCV
) + cbObject
);
428 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
429 ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
433 pXcv
->pLocalmon
= pLocalmon
;
434 pXcv
->GrantedAccess
= GrantedAccess
;
438 pXcv
->pwszObject
= (PWSTR
)((PBYTE
)pXcv
+ sizeof(LOCALMON_XCV
));
439 CopyMemory(pXcv
->pwszObject
, pwszObject
, cbObject
);
442 InsertTailList(&pLocalmon
->XcvHandles
, &pXcv
->Entry
);
444 // Return it as the Xcv handle.
445 *phXcv
= (HANDLE
)pXcv
;
446 dwErrorCode
= ERROR_SUCCESS
;
449 SetLastError(dwErrorCode
);
450 return (dwErrorCode
== ERROR_SUCCESS
);