2 * PROJECT: ReactOS Local Port Monitor
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Various support functions shared by multiple files
5 * COPYRIGHT: Copyright 2015 Colin Finck (colin@reactos.org)
13 * Checks all Port Monitors installed on the local system to find out if a given port already exists.
16 * The port name to check.
19 * TRUE if a port with that name already exists on the local system.
20 * If the return value is FALSE, either the port doesn't exist or an error occurred.
21 * Use GetLastError in this case to check the error case.
24 DoesPortExist(PCWSTR pwszPortName
)
26 BOOL bReturnValue
= FALSE
;
32 PPORT_INFO_1W pPortInfo1
= NULL
;
34 // Determine the required buffer size.
35 EnumPortsW(NULL
, 1, NULL
, 0, &cbNeeded
, &dwReturned
);
36 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
38 dwErrorCode
= GetLastError();
39 ERR("EnumPortsW failed with error %lu!\n", dwErrorCode
);
43 // Allocate a buffer large enough.
44 pPortInfo1
= DllAllocSplMem(cbNeeded
);
47 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
48 ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
52 // Now get the actual port information.
53 if (!EnumPortsW(NULL
, 1, (PBYTE
)pPortInfo1
, cbNeeded
, &cbNeeded
, &dwReturned
))
55 dwErrorCode
= GetLastError();
56 ERR("EnumPortsW failed with error %lu!\n", dwErrorCode
);
60 // We were successful! Loop through all returned ports.
61 dwErrorCode
= ERROR_SUCCESS
;
64 for (i
= 0; i
< dwReturned
; i
++)
66 // Check if this existing port matches our queried one.
67 if (wcsicmp(p
->pName
, pwszPortName
) == 0)
78 DllFreeSplMem(pPortInfo1
);
80 SetLastError(dwErrorCode
);
85 GetLPTTransmissionRetryTimeout(VOID
)
88 DWORD dwReturnValue
= 90; // Use 90 seconds as default if we fail to read from registry.
92 // Six digits is the most you can enter in Windows' LocalUI.dll.
93 // Larger values make it crash, so introduce a limit here.
94 WCHAR wszBuffer
[6 + 1];
96 // Open the key where our value is stored.
97 lStatus
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, L
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows", 0, KEY_READ
, &hKey
);
98 if (lStatus
!= ERROR_SUCCESS
)
100 ERR("RegOpenKeyExW failed with status %ld!\n", lStatus
);
105 cbBuffer
= sizeof(wszBuffer
);
106 lStatus
= RegQueryValueExW(hKey
, L
"TransmissionRetryTimeout", NULL
, NULL
, (PBYTE
)wszBuffer
, &cbBuffer
);
107 if (lStatus
!= ERROR_SUCCESS
)
109 ERR("RegQueryValueExW failed with status %ld!\n", lStatus
);
113 // Return it converted to a DWORD.
114 dwReturnValue
= wcstoul(wszBuffer
, NULL
, 10);
120 return dwReturnValue
;
124 * @name GetPortNameWithoutColon
126 * Most of the time, we operate on port names with a trailing colon. But some functions require the name without the trailing colon.
127 * This function checks if the port has a trailing colon and if so, it returns the port name without the colon.
129 * @param pwszPortName
130 * The port name with colon
132 * @param ppwszPortNameWithoutColon
133 * Pointer to a PWSTR that will contain the port name without colon.
134 * You have to free this buffer using DllFreeSplMem.
137 * ERROR_SUCCESS if the port name without colon was successfully copied into the buffer.
138 * ERROR_INVALID_PARAMETER if this port name has no trailing colon.
139 * ERROR_NOT_ENOUGH_MEMORY if memory allocation failed.
142 GetPortNameWithoutColon(PCWSTR pwszPortName
, PWSTR
* ppwszPortNameWithoutColon
)
144 DWORD cchPortNameWithoutColon
;
146 // Compute the string length of pwszPortNameWithoutColon.
147 cchPortNameWithoutColon
= wcslen(pwszPortName
) - 1;
149 // Check if pwszPortName really has a colon as the last character.
150 if (pwszPortName
[cchPortNameWithoutColon
] != L
':')
151 return ERROR_INVALID_PARAMETER
;
153 // Allocate the output buffer.
154 *ppwszPortNameWithoutColon
= DllAllocSplMem((cchPortNameWithoutColon
+ 1) * sizeof(WCHAR
));
155 if (!*ppwszPortNameWithoutColon
)
157 ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
158 return ERROR_NOT_ENOUGH_MEMORY
;
161 // Copy the port name without colon into the buffer.
162 // The buffer is already zero-initialized, so no additional null-termination is necessary.
163 CopyMemory(*ppwszPortNameWithoutColon
, pwszPortName
, cchPortNameWithoutColon
* sizeof(WCHAR
));
165 return ERROR_SUCCESS
;
171 * Checks if the given port name is a virtual Ne port.
172 * A virtual Ne port may appear in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Ports and can have the formats
173 * Ne00:, Ne01:, Ne-02:, Ne456:
174 * This check is extra picky to not cause false positives (like file name ports starting with "Ne").
176 * @param pwszPortName
177 * The port name to check.
180 * TRUE if this is definitely a virtual Ne port, FALSE if not.
183 _IsNEPort(PCWSTR pwszPortName
)
185 PCWSTR p
= pwszPortName
;
187 // First character needs to be 'N' (uppercase or lowercase)
188 if (*p
!= L
'N' && *p
!= L
'n')
191 // Next character needs to be 'E' (uppercase or lowercase)
193 if (*p
!= L
'E' && *p
!= L
'e')
196 // An optional hyphen may follow now.
201 // Now an arbitrary number of digits may follow.
202 while (*p
>= L
'0' && *p
<= L
'9')
205 // Finally, the virtual Ne port must be terminated by a colon.
209 // If this is the end of the string, we have a virtual Ne port.
211 return (*p
== L
'\0');
215 GetTypeFromName(LPCWSTR name
)
219 if (!wcsncmp(name
, L
"LPT", ARRAYSIZE(L
"LPT") - 1) )
222 if (!wcsncmp(name
, L
"COM", ARRAYSIZE(L
"COM") - 1) )
225 if (!lstrcmpW(name
, L
"FILE:") )
228 // if (name[0] == '/')
229 // return PORT_IS_UNIXNAME;
231 // if (name[0] == '|')
232 // return PORT_IS_PIPE;
234 if ( _IsNEPort( name
) )
237 if (!wcsncmp(name
, L
"XPS", ARRAYSIZE(L
"XPS") - 1))
240 /* Must be a file or a directory. Does the file exist ? */
241 hfile
= CreateFileW(name
, GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
243 FIXME("%p for OPEN_EXISTING on %s\n", hfile
, debugstr_w(name
));
245 if (hfile
== INVALID_HANDLE_VALUE
)
247 /* Can we create the file? */
248 hfile
= CreateFileW(name
, GENERIC_WRITE
, 0, NULL
, OPEN_ALWAYS
, FILE_FLAG_DELETE_ON_CLOSE
, NULL
);
249 FIXME("%p for OPEN_ALWAYS\n", hfile
);
252 if (hfile
!= INVALID_HANDLE_VALUE
)
254 CloseHandle(hfile
); FIXME("PORT_IS_FILENAME %d\n",PORT_IS_FILENAME
);
255 return PORT_IS_FILENAME
;
257 FIXME("PORT_IS_UNKNOWN %d\n",PORT_IS_UNKNOWN
);
258 /* We can't use the name. use GetLastError() for the reason */
259 return PORT_IS_UNKNOWN
;