mirror of
https://github.com/reactos/reactos.git
synced 2025-02-24 17:34:57 +00:00
[LOCALMON]
Implement a Local Port Monitor for COM, FILE: and LPT ports, usable as a drop-in replacement for the Windows original. Fully implements opening, enumerating and closing ports, starting and ending documents as well as reading and writing to ports along with Xcv data transfer between Port Monitor and Port Monitor UI. Does not support IrDA printers unlike the Windows original, sorry guys :-P The Windows Local Port Monitor is partly documented in an ancient DDK sample. Additional information was gathered through API monitoring. TODO: - AddPort, DeletePort and PortIsValid Xcv functions need to be implemented. - A real privilege check needs to be added to LocalmonXcvOpenPort. - TESTING TESTING TESTING (under Windows) and fixing bugs. To test it under Windows: - Copy the compiled "localmon.dll" to the system32 directory. - Open regedit.exe and move to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Monitors\Local Port. - Replace "localspl.dll" by "localmon.dll" for the "Driver" value. [SPOOLSS] - Properly stub EnumPortsW to let localmon compile. svn path=/branches/colins-printing-for-freedom/; revision=68356
This commit is contained in:
parent
d2c73472d0
commit
75f2cf5f6f
13 changed files with 1916 additions and 10 deletions
|
@ -6,6 +6,7 @@ list(APPEND SOURCE
|
|||
jobs.c
|
||||
main.c
|
||||
memory.c
|
||||
ports.c
|
||||
precomp.h
|
||||
printers.c
|
||||
printprocessors.c
|
||||
|
|
14
reactos/win32ss/printing/base/spoolss/ports.c
Normal file
14
reactos/win32ss/printing/base/spoolss/ports.c
Normal file
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Spooler Router
|
||||
* LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
|
||||
* PURPOSE: Functions related to ports
|
||||
* COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
BOOL WINAPI
|
||||
EnumPortsW(PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
|
@ -62,7 +62,7 @@
|
|||
@ stdcall EnumJobsW(long long long long ptr long ptr ptr)
|
||||
@ stub EnumMonitorsW
|
||||
@ stub EnumPerMachineConnectionsW
|
||||
@ stub EnumPortsW
|
||||
@ stdcall EnumPortsW(ptr long ptr long ptr ptr)
|
||||
@ stub EnumPrinterDataExW
|
||||
@ stub EnumPrinterDataW
|
||||
@ stub EnumPrinterDriversW
|
||||
|
|
|
@ -1,20 +1,22 @@
|
|||
|
||||
add_subdirectory(ui)
|
||||
|
||||
spec2def(localmon localmon.spec ADD_IMPORTLIB)
|
||||
spec2def(localmon.dll localmon.spec ADD_IMPORTLIB)
|
||||
|
||||
list(APPEND SOURCE
|
||||
main.c
|
||||
precomp.h)
|
||||
ports.c
|
||||
precomp.h
|
||||
tools.c
|
||||
xcv.c)
|
||||
|
||||
add_library(localmon SHARED
|
||||
${SOURCE}
|
||||
localmon.rc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/localmon_stubs.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/localmon.def)
|
||||
|
||||
set_module_type(localmon win32dll UNICODE)
|
||||
target_link_libraries(localmon wine)
|
||||
add_importlibs(localmon kernel32 msvcrt ntdll)
|
||||
add_importlibs(localmon advapi32 spoolss user32 msvcrt kernel32 ntdll)
|
||||
add_pch(localmon precomp.h SOURCE)
|
||||
add_cd_file(TARGET localmon DESTINATION reactos/system32 FOR all)
|
||||
|
|
7
reactos/win32ss/printing/monitors/localmon/lang/de-DE.rc
Normal file
7
reactos/win32ss/printing/monitors/localmon/lang/de-DE.rc
Normal file
|
@ -0,0 +1,7 @@
|
|||
LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_LOCAL_PORT "Lokaler Anschluss"
|
||||
IDS_LOCAL_MONITOR "Lokaler Monitor"
|
||||
END
|
7
reactos/win32ss/printing/monitors/localmon/lang/en-US.rc
Normal file
7
reactos/win32ss/printing/monitors/localmon/lang/en-US.rc
Normal file
|
@ -0,0 +1,7 @@
|
|||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_LOCAL_PORT "Local Port"
|
||||
IDS_LOCAL_MONITOR "Local Monitor"
|
||||
END
|
|
@ -1,5 +1,26 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Local Port Monitor
|
||||
* LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
|
||||
* PURPOSE: Resource file
|
||||
* COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
|
||||
*/
|
||||
|
||||
#include <windef.h>
|
||||
#include "resource.h"
|
||||
|
||||
/* Version Information */
|
||||
#define REACTOS_VERSION_DLL
|
||||
#define REACTOS_STR_FILE_DESCRIPTION "ReactOS Local Spooler Port Monitor"
|
||||
#define REACTOS_STR_FILE_DESCRIPTION "ReactOS Local Port Monitor"
|
||||
#define REACTOS_STR_INTERNAL_NAME "localmon"
|
||||
#define REACTOS_STR_ORIGINAL_FILENAME "localmon.dll"
|
||||
#include <reactos/version.rc>
|
||||
|
||||
/* UTF-8 */
|
||||
#pragma code_page(65001)
|
||||
|
||||
#ifdef LANGUAGE_DE_DE
|
||||
#include "lang/de-DE.rc"
|
||||
#endif
|
||||
#ifdef LANGUAGE_EN_US
|
||||
#include "lang/en-US.rc"
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Local Spooler Port Monitor
|
||||
* PROJECT: ReactOS Local Port Monitor
|
||||
* LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
|
||||
* PURPOSE: Main functions
|
||||
* COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
|
||||
|
@ -7,8 +7,170 @@
|
|||
|
||||
#include "precomp.h"
|
||||
|
||||
LPMONITOR2 WINAPI
|
||||
// Global Variables
|
||||
DWORD cbLocalMonitor;
|
||||
DWORD cbLocalPort;
|
||||
PCWSTR pwszLocalMonitor;
|
||||
PCWSTR pwszLocalPort;
|
||||
|
||||
// Local Constants
|
||||
static MONITOR2 _MonitorFunctions = {
|
||||
sizeof(MONITOR2), // cbSize
|
||||
LocalmonEnumPorts, // pfnEnumPorts
|
||||
LocalmonOpenPort, // pfnOpenPort
|
||||
NULL, // pfnOpenPortEx
|
||||
LocalmonStartDocPort, // pfnStartDocPort
|
||||
LocalmonWritePort, // pfnWritePort
|
||||
LocalmonReadPort, // pfnReadPort
|
||||
LocalmonEndDocPort, // pfnEndDocPort
|
||||
LocalmonClosePort, // pfnClosePort
|
||||
NULL, // pfnAddPort
|
||||
NULL, // pfnAddPortEx
|
||||
NULL, // pfnConfigurePort
|
||||
NULL, // pfnDeletePort
|
||||
LocalmonGetPrinterDataFromPort, // pfnGetPrinterDataFromPort
|
||||
LocalmonSetPortTimeOuts, // pfnSetPortTimeOuts
|
||||
LocalmonXcvOpenPort, // pfnXcvOpenPort
|
||||
LocalmonXcvDataPort, // pfnXcvDataPort
|
||||
LocalmonXcvClosePort, // pfnXcvClosePort
|
||||
LocalmonShutdown, // pfnShutdown
|
||||
NULL, // pfnSendRecvBidiDataFromPort
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
_LoadResources(HINSTANCE hinstDLL)
|
||||
{
|
||||
LoadStringW(hinstDLL, IDS_LOCAL_MONITOR, (PWSTR)&pwszLocalMonitor, 0);
|
||||
cbLocalMonitor = (wcslen(pwszLocalMonitor) + 1) * sizeof(WCHAR);
|
||||
|
||||
LoadStringW(hinstDLL, IDS_LOCAL_PORT, (PWSTR)&pwszLocalPort, 0);
|
||||
cbLocalPort = (wcslen(pwszLocalPort) + 1) * sizeof(WCHAR);
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
{
|
||||
switch (fdwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
DisableThreadLibraryCalls(hinstDLL);
|
||||
_LoadResources(hinstDLL);
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void WINAPI
|
||||
LocalmonShutdown(HANDLE hMonitor)
|
||||
{
|
||||
PLOCALMON_HANDLE pLocalmon;
|
||||
PLOCALMON_PORT pPort;
|
||||
|
||||
pLocalmon = (PLOCALMON_HANDLE)hMonitor;
|
||||
|
||||
// Close all virtual file ports.
|
||||
while (!IsListEmpty(&pLocalmon->FilePorts))
|
||||
{
|
||||
pPort = CONTAINING_RECORD(&pLocalmon->FilePorts.Flink, LOCALMON_PORT, Entry);
|
||||
LocalmonClosePort((HANDLE)pPort);
|
||||
}
|
||||
|
||||
// Now close all regular ports and remove them from the list.
|
||||
while (!IsListEmpty(&pLocalmon->Ports))
|
||||
{
|
||||
pPort = CONTAINING_RECORD(&pLocalmon->Ports.Flink, LOCALMON_PORT, Entry);
|
||||
RemoveEntryList(&pPort->Entry);
|
||||
LocalmonClosePort((HANDLE)pPort);
|
||||
}
|
||||
|
||||
// Finally free the memory for the LOCALMON_HANDLE structure itself.
|
||||
DllFreeSplMem(pLocalmon);
|
||||
}
|
||||
|
||||
PMONITOR2 WINAPI
|
||||
InitializePrintMonitor2(PMONITORINIT pMonitorInit, PHANDLE phMonitor)
|
||||
{
|
||||
return NULL;
|
||||
DWORD cchMaxPortName;
|
||||
DWORD cchPortName;
|
||||
DWORD dwErrorCode;
|
||||
DWORD dwPortCount;
|
||||
DWORD i;
|
||||
HKEY hKey;
|
||||
PMONITOR2 pReturnValue = NULL;
|
||||
PLOCALMON_HANDLE pLocalmon;
|
||||
PLOCALMON_PORT pPort = NULL;
|
||||
|
||||
// Create a new LOCALMON_HANDLE structure.
|
||||
pLocalmon = DllAllocSplMem(sizeof(LOCALMON_HANDLE));
|
||||
InitializeListHead(&pLocalmon->FilePorts);
|
||||
InitializeListHead(&pLocalmon->Ports);
|
||||
|
||||
// The Local Spooler Port Monitor doesn't need to care about the given registry key and functions.
|
||||
// Instead it uses a well-known registry key for getting its information about local ports. Open this one.
|
||||
dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Ports", 0, KEY_READ, &hKey);
|
||||
if (dwErrorCode != ERROR_SUCCESS)
|
||||
{
|
||||
ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
// Get the number of ports and the length of the largest port name.
|
||||
dwErrorCode = (DWORD)RegQueryInfoKeyW(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &dwPortCount, &cchMaxPortName, NULL, NULL, NULL);
|
||||
if (dwErrorCode != ERROR_SUCCESS)
|
||||
{
|
||||
ERR("RegQueryInfoKeyW failed with status %lu!\n", dwErrorCode);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
// Loop through all ports.
|
||||
for (i = 0; i < dwPortCount; i++)
|
||||
{
|
||||
// Allocate memory for a new LOCALMON_PORT structure and its name.
|
||||
pPort = DllAllocSplMem(sizeof(LOCALMON_PORT) + (cchMaxPortName + 1) * sizeof(WCHAR));
|
||||
if (!pPort)
|
||||
{
|
||||
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
||||
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
pPort->hFile = INVALID_HANDLE_VALUE;
|
||||
pPort->pwszPortName = (PWSTR)((PBYTE)pPort + sizeof(LOCALMON_PORT));
|
||||
|
||||
// Get the port name.
|
||||
cchPortName = cchMaxPortName + 1;
|
||||
dwErrorCode = (DWORD)RegEnumValueW(hKey, i, pPort->pwszPortName, &cchPortName, NULL, NULL, NULL, NULL);
|
||||
if (dwErrorCode != ERROR_SUCCESS)
|
||||
{
|
||||
ERR("RegEnumValueW failed with status %lu!\n", dwErrorCode);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
// This Port Monitor supports COM, FILE and LPT ports. Skip all others.
|
||||
if (_wcsnicmp(pPort->pwszPortName, L"COM", 3) != 0 && _wcsicmp(pPort->pwszPortName, L"FILE:") != 0 && _wcsnicmp(pPort->pwszPortName, L"LPT", 3) != 0)
|
||||
{
|
||||
DllFreeSplMem(pPort);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add it to the list.
|
||||
InsertTailList(&pLocalmon->Ports, &pPort->Entry);
|
||||
|
||||
// Don't let the cleanup routine free this.
|
||||
pPort = NULL;
|
||||
}
|
||||
|
||||
// Return our handle and the Print Monitor functions.
|
||||
*phMonitor = (HANDLE)pLocalmon;
|
||||
pReturnValue = &_MonitorFunctions;
|
||||
dwErrorCode = ERROR_SUCCESS;
|
||||
|
||||
Cleanup:
|
||||
if (pPort)
|
||||
DllFreeSplMem(pPort);
|
||||
|
||||
SetLastError(dwErrorCode);
|
||||
return pReturnValue;
|
||||
}
|
||||
|
|
1004
reactos/win32ss/printing/monitors/localmon/ports.c
Normal file
1004
reactos/win32ss/printing/monitors/localmon/ports.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Local Spooler Port Monitor
|
||||
* PROJECT: ReactOS Local Port Monitor
|
||||
* LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
|
||||
* PURPOSE: Precompiled Header for all source files
|
||||
* COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
|
||||
|
@ -9,14 +9,96 @@
|
|||
#define _PRECOMP_H
|
||||
|
||||
#define WIN32_NO_STATUS
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <wingdi.h>
|
||||
#include <winreg.h>
|
||||
#include <winspool.h>
|
||||
#include <winsplp.h>
|
||||
#include <winuser.h>
|
||||
#include <ndk/rtlfuncs.h>
|
||||
|
||||
#include <spoolss.h>
|
||||
|
||||
#include <wine/debug.h>
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(localmon);
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
// Structures
|
||||
/**
|
||||
* Describes the port handle returned by LocalmonOpenPort.
|
||||
* Manages a legacy port (COM/LPT) or virtual FILE: port for printing as well as its associated printer and job.
|
||||
*/
|
||||
typedef struct _LOCALMON_PORT
|
||||
{
|
||||
LIST_ENTRY Entry;
|
||||
enum {
|
||||
PortType_FILE, /** A virtual port for redirecting the document into a file. */
|
||||
PortType_PhysicalCOM, /** A physical serial port (COM) */
|
||||
PortType_PhysicalLPT, /** A physical parallel port (LPT) */
|
||||
PortType_OtherLPT /** A non-physical parallel port (e.g. a redirected one over network using "net use LPT1 ...") */
|
||||
}
|
||||
PortType;
|
||||
BOOL bStartedDoc; /** Whether a document has been started with StartDocPort. */
|
||||
DWORD dwJobID; /** ID of the printing job we are processing (for later reporting progress using SetJobW). */
|
||||
HANDLE hFile; /** Handle to the opened port or INVALID_HANDLE_VALUE if it isn't currently opened. */
|
||||
HANDLE hPrinter; /** Handle to the printer for the job on this port (for using SetJobW). */
|
||||
PWSTR pwszMapping; /** The current mapping of the DOS Device corresponding to this port at the time _CreateNonspooledPort has been called. */
|
||||
PWSTR pwszPortName; /** The name of this port including the trailing colon. Empty for virtual file ports. */
|
||||
}
|
||||
LOCALMON_PORT, *PLOCALMON_PORT;
|
||||
|
||||
/**
|
||||
* Describes the monitor handle returned by InitializePrintMonitor2.
|
||||
* Manages all available ports in this instance.
|
||||
*/
|
||||
typedef struct _LOCALMON_HANDLE
|
||||
{
|
||||
LIST_ENTRY FilePorts; /** Virtual ports created for every document that's redirected to an output file. */
|
||||
LIST_ENTRY Ports; /** Ports found on the system (except for FILE:) */
|
||||
}
|
||||
LOCALMON_HANDLE, *PLOCALMON_HANDLE;
|
||||
|
||||
/**
|
||||
* Describes the Xcv handle returned by LocalmonXcvOpenPort.
|
||||
* Manages the required data for the Xcv* calls.
|
||||
*/
|
||||
typedef struct _LOCALMON_XCV
|
||||
{
|
||||
ACCESS_MASK GrantedAccess;
|
||||
PWSTR pwszObject;
|
||||
}
|
||||
LOCALMON_XCV, *PLOCALMON_XCV;
|
||||
|
||||
// main.c
|
||||
extern DWORD cbLocalMonitor;
|
||||
extern DWORD cbLocalPort;
|
||||
extern PCWSTR pwszLocalMonitor;
|
||||
extern PCWSTR pwszLocalPort;
|
||||
void WINAPI LocalmonShutdown(HANDLE hMonitor);
|
||||
|
||||
// ports.c
|
||||
BOOL WINAPI LocalmonClosePort(HANDLE hPort);
|
||||
BOOL WINAPI LocalmonEndDocPort(HANDLE hPort);
|
||||
BOOL WINAPI LocalmonEnumPorts(HANDLE hMonitor, PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned);
|
||||
BOOL WINAPI LocalmonGetPrinterDataFromPort(HANDLE hPort, DWORD ControlID, PWSTR pValueName, PWSTR lpInBuffer, DWORD cbInBuffer, PWSTR lpOutBuffer, DWORD cbOutBuffer, PDWORD lpcbReturned);
|
||||
BOOL WINAPI LocalmonOpenPort(HANDLE hMonitor, PWSTR pName, PHANDLE pHandle);
|
||||
BOOL WINAPI LocalmonReadPort(HANDLE hPort, PBYTE pBuffer, DWORD cbBuffer, PDWORD pcbRead);
|
||||
BOOL WINAPI LocalmonSetPortTimeOuts(HANDLE hPort, LPCOMMTIMEOUTS lpCTO, DWORD Reserved);
|
||||
BOOL WINAPI LocalmonStartDocPort(HANDLE hPort, PWSTR pPrinterName, DWORD JobId, DWORD Level, PBYTE pDocInfo);
|
||||
BOOL WINAPI LocalmonWritePort(HANDLE hPort, PBYTE pBuffer, DWORD cbBuf, PDWORD pcbWritten);
|
||||
|
||||
// tools.c
|
||||
BOOL DoesPortExist(PCWSTR pwszPortName);
|
||||
DWORD GetLPTTransmissionRetryTimeout();
|
||||
PWSTR GetPortNameWithoutColon(PCWSTR pwszPortName);
|
||||
|
||||
// xcv.c
|
||||
BOOL WINAPI LocalmonXcvClosePort(HANDLE hXcv);
|
||||
DWORD WINAPI LocalmonXcvDataPort(HANDLE hXcv, PCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded);
|
||||
BOOL WINAPI LocalmonXcvOpenPort(HANDLE hMonitor, PCWSTR pszObject, ACCESS_MASK GrantedAccess, PHANDLE phXcv);
|
||||
|
||||
#endif
|
||||
|
|
11
reactos/win32ss/printing/monitors/localmon/resource.h
Normal file
11
reactos/win32ss/printing/monitors/localmon/resource.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Local Port Monitor
|
||||
* LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
|
||||
* PURPOSE: Resource IDs
|
||||
* COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define IDS_LOCAL_PORT 500
|
||||
#define IDS_LOCAL_MONITOR 507
|
155
reactos/win32ss/printing/monitors/localmon/tools.c
Normal file
155
reactos/win32ss/printing/monitors/localmon/tools.c
Normal file
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Local Port Monitor
|
||||
* LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
|
||||
* PURPOSE: Various support functions shared by multiple files
|
||||
* COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
/**
|
||||
* @name DoesPortExist
|
||||
*
|
||||
* Checks all Port Monitors installed on the local system to find out if a given port already exists.
|
||||
*
|
||||
* @param pwszPortName
|
||||
* The port name to check.
|
||||
*
|
||||
* @return
|
||||
* TRUE if a port with that name already exists on the local system.
|
||||
* If the return value is FALSE, either the port doesn't exist or an error occurred.
|
||||
* Use GetLastError in this case to check the error case.
|
||||
*/
|
||||
BOOL
|
||||
DoesPortExist(PCWSTR pwszPortName)
|
||||
{
|
||||
BOOL bReturnValue = FALSE;
|
||||
DWORD cbNeeded;
|
||||
DWORD dwErrorCode;
|
||||
DWORD dwReturned;
|
||||
DWORD i;
|
||||
PPORT_INFO_1W p;
|
||||
PPORT_INFO_1W pPortInfo1 = NULL;
|
||||
|
||||
// Determine the required buffer size.
|
||||
EnumPortsW(NULL, 1, NULL, 0, &cbNeeded, &dwReturned);
|
||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
dwErrorCode = GetLastError();
|
||||
ERR("EnumPortsW failed with error %lu!\n", dwErrorCode);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
// Allocate a buffer large enough.
|
||||
pPortInfo1 = DllAllocSplMem(cbNeeded);
|
||||
if (!pPortInfo1)
|
||||
{
|
||||
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
||||
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
// Now get the actual port information.
|
||||
if (!EnumPortsW(NULL, 1, (PBYTE)pPortInfo1, cbNeeded, &cbNeeded, &dwReturned))
|
||||
{
|
||||
dwErrorCode = GetLastError();
|
||||
ERR("EnumPortsW failed with error %lu!\n", dwErrorCode);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
// We were successful! Loop through all returned ports.
|
||||
dwErrorCode = ERROR_SUCCESS;
|
||||
p = pPortInfo1;
|
||||
|
||||
for (i = 0; i < dwReturned; i++)
|
||||
{
|
||||
// Check if this existing port matches our queried one.
|
||||
if (wcsicmp(p->pName, pwszPortName) == 0)
|
||||
{
|
||||
bReturnValue = TRUE;
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
Cleanup:
|
||||
if (pPortInfo1)
|
||||
DllFreeSplMem(pPortInfo1);
|
||||
|
||||
SetLastError(dwErrorCode);
|
||||
return bReturnValue;
|
||||
}
|
||||
|
||||
DWORD
|
||||
GetLPTTransmissionRetryTimeout()
|
||||
{
|
||||
DWORD cbBuffer;
|
||||
DWORD dwReturnValue = 90; // Use 90 seconds as default if we fail to read from registry.
|
||||
HKEY hKey;
|
||||
LSTATUS lStatus;
|
||||
|
||||
// Six digits is the most you can enter in Windows' LocalUI.dll.
|
||||
// Larger values make it crash, so introduce a limit here.
|
||||
WCHAR wszBuffer[6 + 1];
|
||||
|
||||
// Open the key where our value is stored.
|
||||
lStatus = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows", 0, KEY_READ, &hKey);
|
||||
if (lStatus != ERROR_SUCCESS)
|
||||
{
|
||||
ERR("RegOpenKeyExW failed with status %ld!\n", lStatus);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
// Query the value.
|
||||
cbBuffer = sizeof(wszBuffer);
|
||||
lStatus = RegQueryValueExW(hKey, L"TransmissionRetryTimeout", NULL, NULL, (PBYTE)wszBuffer, &cbBuffer);
|
||||
if (lStatus != ERROR_SUCCESS)
|
||||
{
|
||||
ERR("RegQueryValueExW failed with status %ld!\n", lStatus);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
// Return it converted to a DWORD.
|
||||
dwReturnValue = wcstoul(wszBuffer, NULL, 10);
|
||||
|
||||
Cleanup:
|
||||
if (hKey)
|
||||
RegCloseKey(hKey);
|
||||
|
||||
return dwReturnValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name GetPortNameWithoutColon
|
||||
*
|
||||
* Most of the time, we operate on port names with a trailing colon. But some functions require the name without the trailing colon.
|
||||
* This function returns the port name without the colon. You have to free the returned buffer using DllFreeSplMem.
|
||||
*
|
||||
* @param pwszPortName
|
||||
* The port name with colon
|
||||
*
|
||||
* @return
|
||||
* Buffer containing the port name without a colon or NULL in case of failure.
|
||||
*/
|
||||
PWSTR
|
||||
GetPortNameWithoutColon(PCWSTR pwszPortName)
|
||||
{
|
||||
DWORD cchPortName;
|
||||
PWSTR pwszPortNameWithoutColon;
|
||||
|
||||
// Every port in our port list has a trailing colon, so we just need to remove the last character of the string.
|
||||
cchPortName = wcslen(pwszPortName) - 1;
|
||||
|
||||
pwszPortNameWithoutColon = DllAllocSplMem((cchPortName + 1) * sizeof(WCHAR));
|
||||
if (!pwszPortNameWithoutColon)
|
||||
{
|
||||
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CopyMemory(pwszPortNameWithoutColon, pwszPortName, cchPortName * sizeof(WCHAR));
|
||||
pwszPortNameWithoutColon[cchPortName] = 0;
|
||||
|
||||
return pwszPortNameWithoutColon;
|
||||
}
|
440
reactos/win32ss/printing/monitors/localmon/xcv.c
Normal file
440
reactos/win32ss/printing/monitors/localmon/xcv.c
Normal file
|
@ -0,0 +1,440 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Local Port Monitor
|
||||
* LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
|
||||
* PURPOSE: Implementation of Xcv* and support functions
|
||||
* COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
static DWORD
|
||||
_HandleAddPort(PLOCALMON_XCV pXcv, PBYTE pInputData, PDWORD pcbOutputNeeded)
|
||||
{
|
||||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name _HandleConfigureLPTPortCommandOK
|
||||
*
|
||||
* Writes the value for "TransmissionRetryTimeout" to the registry. Checks for granted SERVER_ACCESS_ADMINISTER access.
|
||||
* Actually the opposite of _HandleGetTransmissionRetryTimeout, but name kept for compatibility.
|
||||
*
|
||||
* @param pXcv
|
||||
* Pointer to the LOCALMON_XCV structure of the currently opened Xcv port.
|
||||
*
|
||||
* @param pInputData
|
||||
* Pointer to a Unicode string containing the value to be written to the registry.
|
||||
*
|
||||
* @param pcbOutputNeeded
|
||||
* Pointer to a DWORD that will be zeroed on return.
|
||||
*
|
||||
* @return
|
||||
* An error code indicating success or failure.
|
||||
*/
|
||||
static DWORD
|
||||
_HandleConfigureLPTPortCommandOK(PLOCALMON_XCV pXcv, PBYTE pInputData, PDWORD pcbOutputNeeded)
|
||||
{
|
||||
DWORD cbBuffer;
|
||||
DWORD dwErrorCode;
|
||||
HKEY hKey = NULL;
|
||||
HKEY hToken = NULL;
|
||||
|
||||
// Sanity checks
|
||||
if (!pXcv || !pInputData || !pcbOutputNeeded)
|
||||
{
|
||||
dwErrorCode = ERROR_INVALID_PARAMETER;
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
*pcbOutputNeeded = 0;
|
||||
|
||||
// This action can only happen at SERVER_ACCESS_ADMINISTER access level.
|
||||
if (!(pXcv->GrantedAccess & SERVER_ACCESS_ADMINISTER))
|
||||
{
|
||||
dwErrorCode = ERROR_ACCESS_DENIED;
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
// Switch to the SYSTEM context for modifying the registry.
|
||||
hToken = RevertToPrinterSelf();
|
||||
if (!hToken)
|
||||
{
|
||||
dwErrorCode = GetLastError();
|
||||
ERR("RevertToPrinterSelf failed with error %lu!\n", dwErrorCode);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
// Open the key where our value is stored.
|
||||
dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows", 0, KEY_SET_VALUE, &hKey);
|
||||
if (dwErrorCode != ERROR_SUCCESS)
|
||||
{
|
||||
ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
// We don't use cbInputData here, because the buffer pInputData could be bigger than the data it contains.
|
||||
cbBuffer = (wcslen((PWSTR)pInputData) + 1) * sizeof(WCHAR);
|
||||
|
||||
// Write the value to the registry.
|
||||
dwErrorCode = (DWORD)RegSetValueExW(hKey, L"TransmissionRetryTimeout", 0, REG_SZ, pInputData, cbBuffer);
|
||||
if (dwErrorCode != ERROR_SUCCESS)
|
||||
{
|
||||
ERR("RegSetValueExW failed with status %lu!\n", dwErrorCode);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
Cleanup:
|
||||
if (hKey)
|
||||
RegCloseKey(hKey);
|
||||
|
||||
if (hToken)
|
||||
ImpersonatePrinterClient(hToken);
|
||||
|
||||
return dwErrorCode;
|
||||
}
|
||||
|
||||
static DWORD
|
||||
_HandleDeletePort(PLOCALMON_XCV pXcv, PBYTE pInputData, PDWORD pcbOutputNeeded)
|
||||
{
|
||||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name _HandleGetDefaultCommConfig
|
||||
*
|
||||
* Gets the default configuration of a legacy port.
|
||||
* The opposite function is _HandleSetDefaultCommConfig.
|
||||
*
|
||||
* @param pInputData
|
||||
* The port name (without colon!) whose default configuration you want to get.
|
||||
*
|
||||
* @param pOutputData
|
||||
* Pointer to a COMMCONFIG structure that will receive the configuration information.
|
||||
*
|
||||
* @param cbOutputData
|
||||
* Size of the variable pointed to by pOutputData.
|
||||
*
|
||||
* @param pcbOutputNeeded
|
||||
* Pointer to a DWORD that contains the required size for pOutputData on return.
|
||||
*
|
||||
* @return
|
||||
* An error code indicating success or failure.
|
||||
*/
|
||||
static DWORD
|
||||
_HandleGetDefaultCommConfig(PBYTE pInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded)
|
||||
{
|
||||
// Sanity checks
|
||||
if (!pInputData || !pcbOutputNeeded)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
*pcbOutputNeeded = sizeof(COMMCONFIG);
|
||||
|
||||
// Check if the supplied buffer is large enough.
|
||||
if (cbOutputData < *pcbOutputNeeded)
|
||||
return ERROR_INSUFFICIENT_BUFFER;
|
||||
|
||||
// Finally get the port configuration.
|
||||
if (!GetDefaultCommConfigW((PCWSTR)pInputData, (LPCOMMCONFIG)pOutputData, pcbOutputNeeded))
|
||||
return GetLastError();
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name _HandleGetTransmissionRetryTimeout
|
||||
*
|
||||
* Reads the value for "TransmissionRetryTimeout" from the registry and converts it to a DWORD.
|
||||
* The opposite function is _HandleConfigureLPTPortCommandOK.
|
||||
*
|
||||
* @param pOutputData
|
||||
* Pointer to a DWORD that will receive the timeout value.
|
||||
*
|
||||
* @param cbOutputData
|
||||
* Size of the variable pointed to by pOutputData.
|
||||
*
|
||||
* @param pcbOutputNeeded
|
||||
* Pointer to a DWORD that contains the required size for pOutputData on return.
|
||||
*
|
||||
* @return
|
||||
* An error code indicating success or failure.
|
||||
*/
|
||||
static DWORD
|
||||
_HandleGetTransmissionRetryTimeout(PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded)
|
||||
{
|
||||
DWORD dwTimeout;
|
||||
|
||||
// Sanity checks
|
||||
if (!pOutputData || !pcbOutputNeeded)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
*pcbOutputNeeded = sizeof(DWORD);
|
||||
|
||||
// Check if the supplied buffer is large enough.
|
||||
if (cbOutputData < *pcbOutputNeeded)
|
||||
return ERROR_INSUFFICIENT_BUFFER;
|
||||
|
||||
// Retrieve and copy the number.
|
||||
dwTimeout = GetLPTTransmissionRetryTimeout();
|
||||
CopyMemory(pOutputData, &dwTimeout, sizeof(DWORD));
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name _HandleMonitorUI
|
||||
*
|
||||
* Returns the filename of the associated UI DLL for this Port Monitor.
|
||||
*
|
||||
* @param pOutputData
|
||||
* Pointer to a Unicode string that will receive the DLL filename.
|
||||
*
|
||||
* @param cbOutputData
|
||||
* Size of the variable pointed to by pOutputData.
|
||||
*
|
||||
* @param pcbOutputNeeded
|
||||
* Pointer to a DWORD that contains the required size for pOutputData on return.
|
||||
*
|
||||
* @return
|
||||
* An error code indicating success or failure.
|
||||
*/
|
||||
static DWORD
|
||||
_HandleMonitorUI(PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded)
|
||||
{
|
||||
const WCHAR wszMonitorUI[] = L"LocalUI.dll";
|
||||
|
||||
// Sanity checks
|
||||
if (!pOutputData || !pcbOutputNeeded)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
*pcbOutputNeeded = sizeof(wszMonitorUI);
|
||||
|
||||
// Check if the supplied buffer is large enough.
|
||||
if (cbOutputData < *pcbOutputNeeded)
|
||||
return ERROR_INSUFFICIENT_BUFFER;
|
||||
|
||||
// Copy the string.
|
||||
CopyMemory(pOutputData, wszMonitorUI, sizeof(wszMonitorUI));
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name _HandlePortExists
|
||||
*
|
||||
* Checks all Port Monitors installed on the local system to find out if a given port already exists.
|
||||
*
|
||||
* @param pInputData
|
||||
* Pointer to a Unicode string specifying the port name to check.
|
||||
*
|
||||
* @param pOutputData
|
||||
* Pointer to a BOOL that receives the result of the check.
|
||||
*
|
||||
* @param cbOutputData
|
||||
* Size of the variable pointed to by pOutputData.
|
||||
*
|
||||
* @param pcbOutputNeeded
|
||||
* Pointer to a DWORD that contains the required size for pOutputData on return.
|
||||
*
|
||||
* @return
|
||||
* An error code indicating success or failure.
|
||||
*/
|
||||
static DWORD
|
||||
_HandlePortExists(PBYTE pInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded)
|
||||
{
|
||||
// Sanity checks
|
||||
if (!pInputData || !pOutputData || !pcbOutputNeeded)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
*pcbOutputNeeded = sizeof(BOOL);
|
||||
|
||||
// Check if the supplied buffer is large enough.
|
||||
if (cbOutputData < *pcbOutputNeeded)
|
||||
return ERROR_INSUFFICIENT_BUFFER;
|
||||
|
||||
// Return the check result and error code.
|
||||
*(PBOOL)pOutputData = DoesPortExist((PCWSTR)pInputData);
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
static DWORD
|
||||
_HandlePortIsValid(PBYTE pInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded)
|
||||
{
|
||||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name _HandleSetDefaultCommConfig
|
||||
*
|
||||
* Sets the default configuration of a legacy port. Checks for granted SERVER_ACCESS_ADMINISTER access.
|
||||
* You have to supply the port name (with colon!) in XcvOpenPort.
|
||||
* The opposite function is _HandleGetDefaultCommConfig.
|
||||
*
|
||||
* @param pXcv
|
||||
* Pointer to the LOCALMON_XCV structure of the currently opened Xcv port.
|
||||
*
|
||||
* @param pInputData
|
||||
* Pointer to the COMMCONFIG structure that shall be passed to SetDefaultCommConfigW.
|
||||
*
|
||||
* @param pcbOutputNeeded
|
||||
* Pointer to a DWORD that will be zeroed on return.
|
||||
*
|
||||
* @return
|
||||
* An error code indicating success or failure.
|
||||
*/
|
||||
static DWORD
|
||||
_HandleSetDefaultCommConfig(PLOCALMON_XCV pXcv, PBYTE pInputData, PDWORD pcbOutputNeeded)
|
||||
{
|
||||
DWORD dwErrorCode;
|
||||
HANDLE hToken = NULL;
|
||||
LPCOMMCONFIG pCommConfig;
|
||||
PWSTR pwszPortNameWithoutColon = NULL;
|
||||
|
||||
// Sanity checks
|
||||
// pwszObject needs to be at least 2 characters long to be a port name with a trailing colon.
|
||||
if (!pXcv || !pXcv->pwszObject || !pXcv->pwszObject[0] || !pXcv->pwszObject[1] || !pInputData || !pcbOutputNeeded)
|
||||
{
|
||||
dwErrorCode = ERROR_INVALID_PARAMETER;
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
*pcbOutputNeeded = 0;
|
||||
|
||||
// This action can only happen at SERVER_ACCESS_ADMINISTER access level.
|
||||
if (!(pXcv->GrantedAccess & SERVER_ACCESS_ADMINISTER))
|
||||
{
|
||||
dwErrorCode = ERROR_ACCESS_DENIED;
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
// SetDefaultCommConfigW needs the port name without colon.
|
||||
pwszPortNameWithoutColon = GetPortNameWithoutColon(pXcv->pwszObject);
|
||||
if (!pwszPortNameWithoutColon)
|
||||
{
|
||||
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
// Switch to the SYSTEM context for setting the port configuration.
|
||||
hToken = RevertToPrinterSelf();
|
||||
if (!hToken)
|
||||
{
|
||||
dwErrorCode = GetLastError();
|
||||
ERR("RevertToPrinterSelf failed with error %lu!\n", dwErrorCode);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
// Finally pass the parameters to SetDefaultCommConfigW.
|
||||
pCommConfig = (LPCOMMCONFIG)pInputData;
|
||||
if (!SetDefaultCommConfigW(pwszPortNameWithoutColon, pCommConfig, pCommConfig->dwSize))
|
||||
{
|
||||
dwErrorCode = GetLastError();
|
||||
ERR("SetDefaultCommConfigW failed with error %lu!\n", dwErrorCode);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
dwErrorCode = ERROR_SUCCESS;
|
||||
|
||||
Cleanup:
|
||||
if (hToken)
|
||||
ImpersonatePrinterClient(hToken);
|
||||
|
||||
if (pwszPortNameWithoutColon)
|
||||
DllFreeSplMem(pwszPortNameWithoutColon);
|
||||
|
||||
return dwErrorCode;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
LocalmonXcvClosePort(HANDLE hXcv)
|
||||
{
|
||||
// Sanity checks
|
||||
if (!hXcv)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Free the memory.
|
||||
DllFreeSplMem(hXcv);
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
DWORD WINAPI
|
||||
LocalmonXcvDataPort(HANDLE hXcv, PCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded)
|
||||
{
|
||||
// Sanity checks
|
||||
if (!pszDataName)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
// Call the appropriate handler for the requested data name.
|
||||
if (wcscmp(pszDataName, L"AddPort") == 0)
|
||||
return _HandleAddPort((PLOCALMON_XCV)hXcv, pInputData, pcbOutputNeeded);
|
||||
|
||||
if (wcscmp(pszDataName, L"ConfigureLPTPortCommandOK") == 0)
|
||||
return _HandleConfigureLPTPortCommandOK((PLOCALMON_XCV)hXcv, pInputData, pcbOutputNeeded);
|
||||
|
||||
if (wcscmp(pszDataName, L"DeletePort") == 0)
|
||||
return _HandleDeletePort((PLOCALMON_XCV)hXcv, pInputData, pcbOutputNeeded);
|
||||
|
||||
if (wcscmp(pszDataName, L"GetDefaultCommConfig") == 0)
|
||||
return _HandleGetDefaultCommConfig(pInputData, pOutputData, cbOutputData, pcbOutputNeeded);
|
||||
|
||||
if (wcscmp(pszDataName, L"GetTransmissionRetryTimeout") == 0)
|
||||
return _HandleGetTransmissionRetryTimeout(pOutputData, cbOutputData, pcbOutputNeeded);
|
||||
|
||||
if (wcscmp(pszDataName, L"MonitorUI") == 0)
|
||||
return _HandleMonitorUI(pOutputData, cbOutputData, pcbOutputNeeded);
|
||||
|
||||
if (wcscmp(pszDataName, L"PortExists") == 0)
|
||||
return _HandlePortExists(pInputData, pOutputData, cbOutputData, pcbOutputNeeded);
|
||||
|
||||
if (wcscmp(pszDataName, L"PortIsValid") == 0)
|
||||
return _HandlePortIsValid(pInputData, pOutputData, cbOutputData, pcbOutputNeeded);
|
||||
|
||||
if (wcscmp(pszDataName, L"SetDefaultCommConfig") == 0)
|
||||
return _HandleSetDefaultCommConfig((PLOCALMON_XCV)hXcv, pInputData, pcbOutputNeeded);
|
||||
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
LocalmonXcvOpenPort(HANDLE hMonitor, PCWSTR pwszObject, ACCESS_MASK GrantedAccess, PHANDLE phXcv)
|
||||
{
|
||||
DWORD cbObject = 0;
|
||||
DWORD dwErrorCode;
|
||||
PLOCALMON_XCV pXcv;
|
||||
|
||||
// Sanity checks
|
||||
if (!hMonitor || !phXcv)
|
||||
{
|
||||
dwErrorCode = ERROR_INVALID_PARAMETER;
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
if (pwszObject)
|
||||
cbObject = (wcslen(pwszObject) + 1) * sizeof(WCHAR);
|
||||
|
||||
// Create a new LOCALMON_XCV structure and fill the relevant fields.
|
||||
pXcv = DllAllocSplMem(sizeof(LOCALMON_XCV) + cbObject);
|
||||
if (!pXcv)
|
||||
{
|
||||
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
||||
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
pXcv->GrantedAccess = GrantedAccess;
|
||||
|
||||
if (cbObject)
|
||||
{
|
||||
pXcv->pwszObject = (PWSTR)((PBYTE)pXcv + sizeof(LOCALMON_XCV));
|
||||
CopyMemory(pXcv->pwszObject, pwszObject, cbObject);
|
||||
}
|
||||
|
||||
// Return it as the Xcv handle.
|
||||
*phXcv = (HANDLE)pXcv;
|
||||
dwErrorCode = ERROR_SUCCESS;
|
||||
|
||||
Cleanup:
|
||||
SetLastError(dwErrorCode);
|
||||
return (dwErrorCode == ERROR_SUCCESS);
|
||||
}
|
Loading…
Reference in a new issue