windows-nt/Source/XPSP1/NT/base/pnp/setupapi/sputils/miscutil.c
2020-09-26 16:20:57 +08:00

639 lines
14 KiB
C

/*++
Copyright (c) 1993-2000 Microsoft Corporation
Module Name:
miscutil.c
Abstract:
Miscellaneous utility functions for SPUTILS
Author:
Ted Miller (tedm) 20-Jan-1995
Revision History:
Jamie Hunter (JamieHun) Jun-27-2000
Moved various functions out of setupapi into sputils
--*/
#include "precomp.h"
#pragma hdrstop
PTSTR
pSetupDuplicateString(
IN PCTSTR String
)
/*++
Routine Description:
Create a duplicate copy of a nul-terminated string.
If the string pointer is not valid an exception is generated.
Arguments:
String - supplies string to be duplicated.
Return Value:
NULL if out of memory.
Caller can free buffer with pSetupFree().
--*/
{
PTSTR p;
//
// The win32 lstrlen and lstrcpy functions are guarded with
// try/except (at least on NT). So if we use them and the string
// is invalid, we may end up 'laundering' it into a valid 0-length
// string. We don't want that -- we actually want to fault
// in that case. So use the CRT functions, which we know are
// unguarded and will generate exceptions with invalid args.
//
// Also handle the case where the string is valid when we are
// taking its length, but becomes invalid before or while we
// are copying it. If we're not careful this could be a memory
// leak. A try/finally does exactly what we want -- allowing us
// to clean up and still 'pass on' the exception.
//
if(p = pSetupCheckedMalloc((_tcslen(String)+1)*sizeof(TCHAR))) {
try {
//
// If String is or becomes invalid, this will generate
// an exception, but before execution leaves this routine
// we'll hit the termination handler.
//
_tcscpy(p,String);
} finally {
//
// If a fault occurred during the copy, free the copy.
// Execution will then pass to whatever exception handler
// might exist in the caller, etc.
//
if(AbnormalTermination()) {
pSetupFree(p);
p = NULL;
}
}
}
return(p);
}
#ifndef SPUTILSW
PSTR
pSetupUnicodeToMultiByte(
IN PCWSTR UnicodeString,
IN UINT Codepage
)
/*++
Routine Description:
Convert a string from unicode to ansi.
Arguments:
UnicodeString - supplies string to be converted.
Codepage - supplies codepage to be used for the conversion.
Return Value:
NULL if out of memory or invalid codepage.
Caller can free buffer with pSetupFree().
--*/
{
UINT WideCharCount;
PSTR String;
UINT StringBufferSize;
UINT BytesInString;
PSTR p;
WideCharCount = lstrlenW(UnicodeString) + 1;
//
// Allocate maximally sized buffer.
// If every unicode character is a double-byte
// character, then the buffer needs to be the same size
// as the unicode string. Otherwise it might be smaller,
// as some unicode characters will translate to
// single-byte characters.
//
StringBufferSize = WideCharCount * 2;
String = pSetupCheckedMalloc(StringBufferSize);
if(String == NULL) {
return(NULL);
}
//
// Perform the conversion.
//
BytesInString = WideCharToMultiByte(
Codepage,
0, // default composite char behavior
UnicodeString,
WideCharCount,
String,
StringBufferSize,
NULL,
NULL
);
if(BytesInString == 0) {
pSetupFree(String);
return(NULL);
}
//
// Resize the string's buffer to its correct size.
// If the realloc fails for some reason the original
// buffer is not freed.
//
if(p = pSetupRealloc(String,BytesInString)) {
String = p;
}
return(String);
}
PWSTR
pSetupMultiByteToUnicode(
IN PCSTR String,
IN UINT Codepage
)
/*++
Routine Description:
Convert a string to unicode.
Arguments:
String - supplies string to be converted.
Codepage - supplies codepage to be used for the conversion.
Return Value:
NULL if string could not be converted (out of memory or invalid cp)
Caller can free buffer with pSetupFree().
--*/
{
UINT BytesIn8BitString;
UINT CharsInUnicodeString;
PWSTR UnicodeString;
PWSTR p;
BytesIn8BitString = lstrlenA(String) + 1;
//
// Allocate maximally sized buffer.
// If every character is a single-byte character,
// then the buffer needs to be twice the size
// as the 8bit string. Otherwise it might be smaller,
// as some characters are 2 bytes in their unicode and
// 8bit representations.
//
UnicodeString = pSetupCheckedMalloc(BytesIn8BitString * sizeof(WCHAR));
if(UnicodeString == NULL) {
return(NULL);
}
//
// Perform the conversion.
//
CharsInUnicodeString = MultiByteToWideChar(
Codepage,
MB_PRECOMPOSED,
String,
BytesIn8BitString,
UnicodeString,
BytesIn8BitString
);
if(CharsInUnicodeString == 0) {
pSetupFree(UnicodeString);
return(NULL);
}
//
// Resize the unicode string's buffer to its correct size.
// If the realloc fails for some reason the original
// buffer is not freed.
//
if(p = pSetupRealloc(UnicodeString,CharsInUnicodeString*sizeof(WCHAR))) {
UnicodeString = p;
}
return(UnicodeString);
}
#endif // ! SPUTILSW
#ifdef UNICODE
DWORD
pSetupCaptureAndConvertAnsiArg(
IN PCSTR AnsiString,
OUT PCWSTR *UnicodeString
)
/*++
Routine Description:
Capture an ANSI string whose validity is suspect and convert it
into a Unicode string. The conversion is completely guarded and thus
won't fault, leak memory in the error case, etc.
Arguments:
AnsiString - supplies string to be converted.
UnicodeString - if successful, receives pointer to unicode equivalent
of AnsiString. Caller must free with pSetupFree(). If not successful,
receives NULL. This parameter is NOT validated so be careful.
Return Value:
Win32 error code indicating outcome.
NO_ERROR - success, UnicodeString filled in.
ERROR_NOT_ENOUGH_MEMORY - insufficient memory for conversion.
ERROR_INVALID_PARAMETER - AnsiString was invalid.
--*/
{
PSTR ansiString;
DWORD d;
//
// Capture the string first. We do this because pSetupMultiByteToUnicode
// won't fault if AnsiString were to become invalid, meaning we could
// 'launder' a bogus argument into a valid one. Be careful not to
// leak memory in the error case, etc (see comments in DuplicateString()).
// Do NOT use Win32 string functions here; we rely on faults occuring
// when pointers are invalid!
//
*UnicodeString = NULL;
d = NO_ERROR;
try {
ansiString = pSetupCheckedMalloc(strlen(AnsiString)+1);
if(!ansiString) {
d = ERROR_NOT_ENOUGH_MEMORY;
}
} except(EXCEPTION_EXECUTE_HANDLER) {
//
// If we get here, strlen faulted and ansiString
// was not allocated.
//
d = ERROR_INVALID_PARAMETER;
}
if(d == NO_ERROR) {
try {
strcpy(ansiString,AnsiString);
} except(EXCEPTION_EXECUTE_HANDLER) {
d = ERROR_INVALID_PARAMETER;
pSetupFree(ansiString);
}
}
if(d == NO_ERROR) {
//
// Now we have a local copy of the string; don't worry
// about faults any more.
//
*UnicodeString = pSetupMultiByteToUnicode(ansiString,CP_ACP);
if(*UnicodeString == NULL) {
d = ERROR_NOT_ENOUGH_MEMORY;
}
pSetupFree(ansiString);
}
return(d);
}
#else
DWORD
pSetupCaptureAndConvertAnsiArg(
IN PCSTR AnsiString,
OUT PCWSTR *UnicodeString
)
{
//
// Stub so the dll will link.
//
UNREFERENCED_PARAMETER(AnsiString);
UNREFERENCED_PARAMETER(UnicodeString);
return(ERROR_CALL_NOT_IMPLEMENTED);
}
#endif
BOOL
pSetupConcatenatePaths(
IN OUT PTSTR Target,
IN PCTSTR Path,
IN UINT TargetBufferSize,
OUT PUINT RequiredSize OPTIONAL
)
/*++
Routine Description:
Concatenate 2 paths, ensuring that one, and only one,
path separator character is introduced at the junction point.
Arguments:
Target - supplies first part of path. Path is appended to this.
Path - supplies path to be concatenated to Target.
TargetBufferSize - supplies the size of the Target buffer,
in characters.
RequiredSize - if specified, receives the number of characters
required to hold the fully concatenated path, including
the terminating nul.
Return Value:
TRUE if the full path fit in Target buffer. Otherwise the path
will have been truncated.
--*/
{
UINT TargetLength,PathLength;
BOOL TrailingBackslash,LeadingBackslash;
UINT EndingLength;
TargetLength = lstrlen(Target);
PathLength = lstrlen(Path);
//
// See whether the target has a trailing backslash.
//
if(TargetLength && (*CharPrev(Target,Target+TargetLength) == TEXT('\\'))) {
TrailingBackslash = TRUE;
TargetLength--;
} else {
TrailingBackslash = FALSE;
}
//
// See whether the path has a leading backshash.
//
if(Path[0] == TEXT('\\')) {
LeadingBackslash = TRUE;
PathLength--;
} else {
LeadingBackslash = FALSE;
}
//
// Calculate the ending length, which is equal to the sum of
// the length of the two strings modulo leading/trailing
// backslashes, plus one path separator, plus a nul.
//
EndingLength = TargetLength + PathLength + 2;
if(RequiredSize) {
*RequiredSize = EndingLength;
}
if(!LeadingBackslash && (TargetLength < TargetBufferSize)) {
Target[TargetLength++] = TEXT('\\');
}
if(TargetBufferSize > TargetLength) {
lstrcpyn(Target+TargetLength,Path,TargetBufferSize-TargetLength);
}
//
// Make sure the buffer is nul terminated in all cases.
//
if (TargetBufferSize) {
Target[TargetBufferSize-1] = 0;
}
return(EndingLength <= TargetBufferSize);
}
PCTSTR
pSetupGetFileTitle(
IN PCTSTR FilePath
)
/*++
Routine Description:
This routine returns a pointer to the first character in the
filename part of the supplied path. If only a filename was given,
then this will be a pointer to the first character in the string
(i.e., the same as what was passed in).
To find the filename part, the routine returns the last component of
the string, beginning with the character immediately following the
last '\', '/' or ':'. (NB NT treats '/' as equivalent to '\' )
Arguments:
FilePath - Supplies the file path from which to retrieve the filename
portion.
Return Value:
A pointer to the beginning of the filename portion of the path.
--*/
{
PCTSTR LastComponent = FilePath;
TCHAR CurChar;
while(CurChar = *FilePath) {
FilePath = CharNext(FilePath);
if((CurChar == TEXT('\\')) || (CurChar == TEXT('/')) || (CurChar == TEXT(':'))) {
LastComponent = FilePath;
}
}
return LastComponent;
}
#ifndef SPUTILSW
BOOL
_pSpUtilsInitializeSynchronizedAccess(
OUT PMYLOCK Lock
)
/*++
Routine Description:
Initialize a lock structure to be used with Synchronization routines.
Arguments:
Lock - supplies structure to be initialized. This routine creates
the locking event and mutex and places handles in this structure.
Return Value:
TRUE if the lock structure was successfully initialized. FALSE if not.
--*/
{
if(Lock->Handles[TABLE_DESTROYED_EVENT] = CreateEvent(NULL,TRUE,FALSE,NULL)) {
if(Lock->Handles[TABLE_ACCESS_MUTEX] = CreateMutex(NULL,FALSE,NULL)) {
return(TRUE);
}
CloseHandle(Lock->Handles[TABLE_DESTROYED_EVENT]);
}
return(FALSE);
}
VOID
_pSpUtilsDestroySynchronizedAccess(
IN OUT PMYLOCK Lock
)
/*++
Routine Description:
Tears down a lock structure created by InitializeSynchronizedAccess.
ASSUMES THAT THE CALLING ROUTINE HAS ALREADY ACQUIRED THE LOCK!
Arguments:
Lock - supplies structure to be torn down. The structure itself
is not freed.
Return Value:
None.
--*/
{
HANDLE h1,h2;
h1 = Lock->Handles[TABLE_DESTROYED_EVENT];
h2 = Lock->Handles[TABLE_ACCESS_MUTEX];
Lock->Handles[TABLE_DESTROYED_EVENT] = NULL;
Lock->Handles[TABLE_ACCESS_MUTEX] = NULL;
CloseHandle(h2);
SetEvent(h1);
CloseHandle(h1);
}
VOID
pSetupCenterWindowRelativeToParent(
HWND hwnd
)
/*++
Routine Description:
Centers a dialog relative to its owner, taking into account
the 'work area' of the desktop.
Arguments:
hwnd - window handle of dialog to center
Return Value:
None.
--*/
{
RECT rcFrame,
rcWindow;
LONG x,
y,
w,
h;
POINT point;
HWND Parent;
Parent = GetWindow(hwnd,GW_OWNER);
if(Parent == NULL) {
return;
}
point.x = point.y = 0;
ClientToScreen(Parent,&point);
GetWindowRect(hwnd,&rcWindow);
GetClientRect(Parent,&rcFrame);
w = rcWindow.right - rcWindow.left + 1;
h = rcWindow.bottom - rcWindow.top + 1;
x = point.x + ((rcFrame.right - rcFrame.left + 1 - w) / 2);
y = point.y + ((rcFrame.bottom - rcFrame.top + 1 - h) / 2);
//
// Get the work area for the current desktop (i.e., the area that
// the tray doesn't occupy).
//
if(!SystemParametersInfo(SPI_GETWORKAREA, 0, (PVOID)&rcFrame, 0)) {
//
// For some reason SPI failed, so use the full screen.
//
rcFrame.top = rcFrame.left = 0;
rcFrame.right = GetSystemMetrics(SM_CXSCREEN);
rcFrame.bottom = GetSystemMetrics(SM_CYSCREEN);
}
if(x + w > rcFrame.right) {
x = rcFrame.right - w;
} else if(x < rcFrame.left) {
x = rcFrame.left;
}
if(y + h > rcFrame.bottom) {
y = rcFrame.bottom - h;
} else if(y < rcFrame.top) {
y = rcFrame.top;
}
MoveWindow(hwnd,x,y,w,h,FALSE);
}
#endif // !SPUTILSW