windows-nt/Source/XPSP1/NT/sdktools/wsremote/remote.c
2020-09-26 16:20:57 +08:00

1065 lines
26 KiB
C

/*++
Copyright (C) Microsoft Corporation, 1993 - 1999
Module Name:
Remote.c
Abstract:
This module contains the main() entry point for Remote.
Calls the Server or the Client depending on the first parameter.
Author:
Rajivendra Nath (rajnath) 2-Jan-1993
Environment:
Console App. User mode.
Revision History:
--*/
#include <stdio.h>
#include <stdlib.h>
#include "Remote.h"
TCHAR HostName[HOSTNAMELEN];
TCHAR * ChildCmd;
TCHAR* PipeName;
TCHAR* ServerName;
TCHAR* Username;
TCHAR* Password;
HANDLE MyOutHandle;
BOOL bIPLocked=FALSE;
BOOL IsAdvertise=TRUE;
DWORD ClientToServerFlag;
TCHAR* ColorList[]={
TEXT("black"),
TEXT("blue"),
TEXT("green"),
TEXT("cyan"),
TEXT("red"),
TEXT("purple"),
TEXT("yellow"),
TEXT("white"),
TEXT("lblack"),
TEXT("lblue"),
TEXT("lgreen"),
TEXT("lcyan"),
TEXT("lred"),
TEXT("lpurple"),
TEXT("lyellow"),
TEXT("lwhite")
};
WORD
GetColorNum(
TCHAR* color
);
VOID
SetColor(
WORD attr
);
BOOL
GetNextConnectInfo(
TCHAR** SrvName,
TCHAR** PipeName
);
CONSOLE_SCREEN_BUFFER_INFO csbiOriginal;
int _cdecl _tmain(int argc, TCHAR *argv[])
{
WORD RunType; // Server or Client end of Remote
DWORD len=HOSTNAMELEN-1;
int i, FirstArg;
BOOL bSetAttrib=FALSE; // Change Console Attributes
BOOL bPromptForArgs=FALSE; // Is /P option
BOOL bIPSession=TRUE; // Is /N for Named Pipes
TCHAR szTitle[100]; // New Title
TCHAR szOrgTitle[100]; // Old Title
WORD wAttrib; // Console Attributes
GetComputerName((LPTSTR)HostName,&len);
MyOutHandle=GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(MyOutHandle,&csbiOriginal);
//
// Parameter Processing
//
// For Server:
// Remote /S <Executable> <PipeName> [Optional Params]
//
// For Client:
// Remote /C <Server Name> <PipeName> [Optional Params]
// or
// Remote /P
// This will loop continously prompting for different
// Servers and Pipename
if ((argc<2)||((argv[1][0]!='/')&&(argv[1][0]!='-')))
{
DisplayServerHlp();
DisplayClientHlp();
return(1);
}
switch(argv[1][1])
{
case 'c':
case 'C':
//
// Is Client End of Remote
//
if ((argc<4)||((argv[1][0]!='/')&&(argv[1][0]!='-')))
{
DisplayServerHlp();
DisplayClientHlp();
return(1);
}
ServerName=argv[2];
PipeName=argv[3];
FirstArg=4;
RunType=REMOTE_CLIENT;
break;
case 'p':
case 'P':
//
// Is Client End of Remote
//
bPromptForArgs=TRUE;
RunType=REMOTE_CLIENT;
FirstArg=2;
break;
case 's':
case 'S':
//
// Is Server End of Remote
//
if ((argc<4)||((argv[1][0]!='/')&&(argv[1][0]!='-')))
{
DisplayServerHlp();
DisplayClientHlp();
return(1);
}
ChildCmd=argv[2];
PipeName=argv[3];
FirstArg=4;
RunType=REMOTE_SERVER;
break;
default:
DisplayServerHlp();
DisplayClientHlp();
return(1);
}
//
// Save Existing Values
//
//
//Colors /f <ForeGround> /b <BackGround>
//
wAttrib=csbiOriginal.wAttributes;
//
//Title /T Title
//
GetConsoleTitle( szOrgTitle, lstrlen( szOrgTitle) );
if (RunType==REMOTE_SERVER)
{
//
// Base Name of Executable
// For setting the title
//
TCHAR *tcmd=ChildCmd;
while ((*tcmd!=' ') &&(*tcmd!=0)) tcmd++;
while ((tcmd!=ChildCmd)&&(*tcmd!='\\'))tcmd--;
_stprintf( szTitle, TEXT("%-8.8s [WSRemote /C %s %s]"), tcmd, HostName, PipeName);
}
//
//Process Common (Optional) Parameters
//
for (i=FirstArg;i<argc;i++)
{
if ((argv[i][0]!='/')&&(argv[i][0]!='-'))
{
_tprintf( TEXT("Invalid parameter %s:Ignoring\n"),argv[i]);
continue;
}
switch(argv[i][1])
{
case 'u': // Only Valid for Server End
case 'U': // Username To Use to Connect to Session
i++;
if (i>=argc)
{
_tprintf( TEXT("Incomplete Param %s..Ignoring\n"),argv[i-1]);
break;
}
Username=(argv[i]);
break;
case 'p': // Only Valid for Server End
case 'P': // Password To Use to Connect to Session
i++;
if (i>=argc)
{
_tprintf( TEXT("Incomplete Param %s..Ignoring\n"),argv[i-1]);
break;
}
Password=(argv[i]);
break;
case 'l': // Only Valid for client End
case 'L': // Max Number of Lines to recieve from Server
i++;
if (i>=argc)
{
_tprintf(TEXT("Incomplete Param %s..Ignoring\n"),argv[i-1]);
break;
}
LinesToSend=(DWORD)_ttoi(argv[i])+1;
break;
case 't': // Title to be set instead of the default
case 'T':
i++;
if (i>=argc)
{
_tprintf(TEXT("Incomplete Param %s..Ignoring\n"),argv[i-1]);
break;
}
_stprintf( szTitle, TEXT("%s"),argv[i]);
break;
case 'b': // Background color
case 'B':
i++;
if (i>=argc)
{
_tprintf(TEXT("Incomplete Param %s..Ignoring\n"),argv[i-1]);
break;
}
{
WORD col=GetColorNum(argv[i]);
if (col!=0xffff)
{
bSetAttrib=TRUE;
wAttrib=col<<4|(wAttrib&0x000f);
}
break;
}
case 'f': // Foreground color
case 'F':
i++;
if (i>=argc)
{
_tprintf(TEXT("Incomplete Param %s..Ignoring\n"),argv[i-1]);
break;
}
{
WORD col=GetColorNum(argv[i]);
if (col!=0xffff)
{
bSetAttrib=TRUE;
wAttrib=col|(wAttrib&0x00f0);
}
break;
}
case 'q':
case 'Q':
IsAdvertise=FALSE;
ClientToServerFlag|=0x80000000;
break;
case 'n':
case 'N':
bIPSession=FALSE;
break;
case 'i':
case 'I':
bIPLocked=TRUE;
break;
default:
_tprintf(TEXT("Unknown Parameter=%s %s\n"),argv[i-1],argv[i]);
break;
}
}
//
//Now Set various Parameters
//
//
//Colors
//
SetColor(wAttrib);
if (RunType==REMOTE_CLIENT)
{
BOOL done=FALSE;
//
// Set Client end defaults and start client
//
while(!done)
{
if (!bPromptForArgs ||
GetNextConnectInfo(&ServerName,&PipeName)
)
{
_stprintf( szTitle, TEXT("WSRemote /C %s %s"),ServerName,PipeName);
SetConsoleTitle(szTitle);
if (!bIPSession)
{
//
// Start Client (Client.C)
//
Client(ServerName,PipeName);
}
else
{
SockClient(ServerName,PipeName);
}
}
done=!bPromptForArgs;
}
}
if (RunType==REMOTE_SERVER)
{
SetConsoleTitle(szTitle);
//
// Start Server (Server.C)
//
Server(ChildCmd,PipeName);
}
//
//Reset Colors
//
SetColor(csbiOriginal.wAttributes);
SetConsoleTitle(szOrgTitle);
ExitProcess(0);
return( 1 );
}
/*************************************************************/
VOID
ErrorExit(
TCHAR* str
)
{
_tprintf(TEXT("Error-%d:%s\n"),GetLastError(),str);
ExitProcess(1);
}
/*************************************************************/
DWORD
ReadFixBytes(
HANDLE hRead,
TCHAR* Buffer,
DWORD ToRead,
DWORD TimeOut //ignore for timebeing
)
{
DWORD xyzBytesRead=0;
DWORD xyzBytesToRead=ToRead;
TCHAR* xyzbuff=Buffer;
while(xyzBytesToRead!=0)
{
if (!ReadFile(hRead,xyzbuff,xyzBytesToRead,&xyzBytesRead,NULL))
{
return(xyzBytesToRead);
}
xyzBytesToRead-=xyzBytesRead;
xyzbuff+=xyzBytesRead;
}
return(0);
}
/*************************************************************/
/*************************************************************/
DWORD
SockReadFixBytes(
SOCKET hSocket,
TCHAR* Buffer,
DWORD ToRead,
DWORD TimeOut //ignore for timebeing
)
{
DWORD xyzBytesRead=0;
DWORD xyzBytesToRead=ToRead;
TCHAR* xyzbuff=Buffer;
while(xyzBytesToRead!=0)
{
if (!ReadSocket(hSocket,xyzbuff,xyzBytesToRead,&xyzBytesRead))
{
return(xyzBytesToRead);
}
xyzBytesToRead-=xyzBytesRead;
xyzbuff+=xyzBytesRead;
}
return(0);
}
/*************************************************************/
VOID
DisplayClientHlp()
{
_tprintf(TEXT("\n To Start the CLIENT end of WSREMOTE\n"));
_tprintf(TEXT(" ---------------------------------\n"));
_tprintf(TEXT(" Syntax : WSREMOTE /C <ServerName> <Unique Id> [Param]\n"));
_tprintf(TEXT(" Example: WSREMOTE /C iisdebug 70\n"));
_tprintf(TEXT(" This would connect to a server session on \n"));
_tprintf(TEXT(" iisdebug with id \"70\" if there was a\n"));
_tprintf(TEXT(" WSREMOTE /S <\"Cmd\"> 70\n"));
_tprintf(TEXT(" started on the machine iisdebug.\n\n"));
_tprintf(TEXT(" To Exit: %cQ (Leaves the Remote Server Running)\n"),COMMANDCHAR);
_tprintf(TEXT(" [Param]: /L <# of Lines to Get>\n"));
_tprintf(TEXT(" [Param]: /F <Foreground color eg blue, lred..>\n"));
_tprintf(TEXT(" [Param]: /B <Background color eg cyan, lwhite..>\n"));
_tprintf(TEXT(" [Param]: /N (Connect over Named Pipes)\n"));
_tprintf(TEXT(" [Param]: /U <Username> (Username to connect)\n"));
_tprintf(TEXT(" [Param]: /P <Password> (Password to connect)\n"));
_tprintf(TEXT("\n"));
}
/*************************************************************/
VOID
DisplayServerHlp()
{
#define WRITEF2(VArgs) { \
HANDLE xh=GetStdHandle(STD_OUTPUT_HANDLE); \
TCHAR VBuff[256]; \
DWORD tmp; \
_stprintf VArgs; \
WriteFile(xh,VBuff,lstrlen(VBuff),&tmp,NULL); \
} \
_tprintf(TEXT("\n To Start the SERVER end of WSREMOTE\n"));
_tprintf(TEXT(" ---------------------------------\n"));
_tprintf(TEXT(" Syntax : WSREMOTE /S <\"Cmd\"> <Unique Id or Port Number> [Param]\n"));
_tprintf(TEXT(" Syntax : WSREMOTE /S <\"Cmd\"> <Unique Id or Port Number> [Param]\n"));
_tprintf(TEXT(" Example: WSREMOTE /S \"cmd.exe\" inetinfo\n"));
_tprintf(TEXT(" To interact with this \"Cmd\" \n"));
_tprintf(TEXT(" from some other machine\n"));
_tprintf(TEXT(" - start the client end by:\n"));
_tprintf(TEXT(" REMOTE /C %s PortNum\n\n"),HostName);
_tprintf(TEXT(" To Exit: %cK \n"),COMMANDCHAR);
_tprintf(TEXT(" [Param]: /F <Foreground color eg yellow, black..>\n"));
_tprintf(TEXT(" [Param]: /B <Background color eg lblue, white..>\n"));
_tprintf(TEXT(" [Param]: /I (Turns ON IP Blocking)\n"));
_tprintf(TEXT(" [Param]: /U <Username> (Username to connect)\n"));
_tprintf(TEXT(" [Param]: /P <Password> (Password to connect)\n"));
_tprintf(TEXT("\n"));
}
WORD
GetColorNum(
TCHAR *color
)
{
WORD wIndex;
_tcslwr(color);
for (wIndex=0;wIndex<16;wIndex++)
{
if (_tcscmp(ColorList[wIndex],color)==0)
{
return(wIndex);
}
}
return ((WORD)_ttoi(color));
}
VOID
SetColor(
WORD attr
)
{
COORD origin={0,0};
DWORD dwrite;
FillConsoleOutputAttribute
(
MyOutHandle,attr,csbiOriginal.dwSize.
X*csbiOriginal.dwSize.Y,origin,&dwrite
);
SetConsoleTextAttribute(MyOutHandle,attr);
}
BOOL
GetNextConnectInfo(
TCHAR** SrvName,
TCHAR** PipeName
)
{
static TCHAR szServerName[64];
static TCHAR szPipeName[32];
TCHAR *s;
__try
{
ZeroMemory(szServerName,64);
ZeroMemory(szPipeName,32);
SetConsoleTitle( TEXT("Remote - Prompting for next Connection"));
_tprintf(TEXT("Debugger machine (server): "));
fflush(stdout);
if (((*SrvName=_getts(szServerName))==NULL)||
(_tcslen(szServerName)==0))
{
return(FALSE);
}
if (szServerName[0] == COMMANDCHAR &&
(szServerName[1] == 'q' || szServerName[1] == 'Q')
)
{
return(FALSE);
}
if (s = _tcschr( szServerName, ' ' )) {
*s++ = '\0';
while (*s == ' ') {
s += 1;
}
*PipeName=_tcscpy(szPipeName, s);
_tprintf(szPipeName);
fflush(stdout);
}
if (_tcslen(szPipeName) == 0) {
_tprintf(TEXT("Debuggee machine : "));
fflush(stdout);
if ((*PipeName=_getts(szPipeName))==NULL)
{
return(FALSE);
}
}
if (s = _tcschr(szPipeName, ' ')) {
*s++ = '\0';
}
if (szPipeName[0] == COMMANDCHAR &&
(szPipeName[1] == 'q' || szPipeName[1] == 'Q')
)
{
return(FALSE);
}
_tprintf(TEXT("\n\n"));
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
return(FALSE); // Ignore exceptions
}
return(TRUE);
}
/*************************************************************/
VOID
Errormsg(
TCHAR* str
)
{
_tprintf(TEXT("Error (%d) - %s\n"),GetLastError(),str);
}
/*************************************************************/
BOOL ReadSocket(SOCKET s,TCHAR * buff,int len,DWORD* dread)
{
BOOL bRet = FALSE;
DWORD numread;
#ifdef UNICODE
char * pszAnsiStr = (char *)calloc( (len + 1), sizeof(char) );
if (pszAnsiStr)
{
int nErr;
numread = (DWORD)recv( s, pszAnsiStr, len, 0);
if (SOCKET_ERROR != numread)
{
nErr = MultiByteToWideChar( CP_ACP,
MB_PRECOMPOSED,
pszAnsiStr,
len,
buff,
len );
if (nErr)
{
*dread = numread;
bRet = TRUE;
}
//Base64Decode(buff,DecodeBuffer);
}
free( pszAnsiStr );
}
#else
numread = (DWORD)recv( s, buff, len, 0);
if (SOCKET_ERROR != numread)
{
*dread = numread;
bRet = TRUE;
}
#endif
return bRet;
}
// returns TRUE if successful, false otherwise
BOOL WriteSocket(
SOCKET s,
TCHAR * buff,
int len,
DWORD* dsent)
{
BOOL bRet = FALSE;
DWORD numsent;
#ifdef UNICODE
int nStrLen = lstrlen( buff );
if (nStrLen)
{
char * pszAnsiStr = (char *)malloc( nStrLen + 1 );
if (pszAnsiStr)
{
int nErr = WideCharToMultiByte( CP_ACP,
WC_COMPOSITECHECK,
buff,
nStrLen,
pszAnsiStr,
nStrLen,
NULL,
NULL );
if (nErr)
{
numsent = (DWORD)send(s, pszAnsiStr, nStrLen, 0);
if (SOCKET_ERROR != numsent)
{
*dsent = numsent;
bRet = TRUE;
}
}
//Base64Decode(buff,DecodeBuffer);
free( pszAnsiStr );
}
}
#else
numsent = (DWORD)send(s, buff, len, 0);
if (SOCKET_ERROR != numsent)
{
*dsent = numsent;
bRet = TRUE;
}
#endif
return bRet;
}
#ifdef UNICODE
// returns TRUE if successful, false otherwise
BOOL WriteSocketA(
SOCKET s,
char * pszAnsiStr,
int len,
DWORD * dsent)
{
BOOL bRet = FALSE;
DWORD numsent;
numsent = (DWORD)send(s, pszAnsiStr, len, 0);
if (SOCKET_ERROR != numsent)
{
*dsent = numsent;
bRet = TRUE;
}
//Base64Decode(buff,DecodeBuffer);
return bRet;
}
#endif
////////////////////////////////////////////////
unsigned char Base64Table[64] =
{'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'};
VOID
Base64Encode(
TCHAR * String,
DWORD StringLength,
TCHAR * EncodeBuffer)
{
DWORD EncodeDword;
int Index;
memset(EncodeBuffer, 0, 2 * StringLength);
Index = 0;
while (StringLength >= 3) {
//
// Encode a three byte chunk
//
EncodeDword = (String[0] << 16) & 0xff0000;
EncodeDword += (String[1] << 8) & 0xff00;
EncodeDword += String[2] & 0xff;
EncodeBuffer[Index++] = Base64Table[(EncodeDword >> 18) & 63];
EncodeBuffer[Index++] = Base64Table[(EncodeDword >> 12) & 63];
EncodeBuffer[Index++] = Base64Table[(EncodeDword >> 6) & 63];
EncodeBuffer[Index++] = Base64Table[EncodeDword & 63];
String += 3;
StringLength -= 3;
}
switch (StringLength) {
case 1:
EncodeDword = (String[0] << 16) & 0xff0000;
EncodeBuffer[Index++] = Base64Table[(EncodeDword >> 18) & 63];
EncodeBuffer[Index++] = Base64Table[(EncodeDword >> 12) & 63];
EncodeBuffer[Index++] = '=';
EncodeBuffer[Index++] = '=';
break;
case 2:
EncodeDword = (String[0] << 16) & 0xff0000;
EncodeDword += (String[1] << 8) & 0xff00;
EncodeBuffer[Index++] = Base64Table[(EncodeDword >> 18) & 63];
EncodeBuffer[Index++] = Base64Table[(EncodeDword >> 12) & 63];
EncodeBuffer[Index++] = Base64Table[(EncodeDword >> 6) & 63];
EncodeBuffer[Index++] = '=';
break;
}
EncodeBuffer[Index] = 0;
return;
}
int
GetBase64Index(
TCHAR A)
{
int i;
for (i=0; i<64; i++) {
if (Base64Table[i] == A) {
return i;
}
}
return -1;
}
VOID
Base64Decode(
TCHAR * String,
TCHAR * DecodeBuffer)
{
DWORD DecodeDword;
int Index = 0;
memset(DecodeBuffer, 0, _tcslen(String));
if (_tcslen(String) % 4) {
printf("WCAT INTERNAL ERROR %s %d\n", __FILE__, __LINE__);
return;
}
while (*String) {
//
// Decode a four byte chunk
//
if (GetBase64Index(String[0]) < 0) {
//
// Invalid string
//
printf("WCAT INTERNAL ERROR %s %d\n", __FILE__, __LINE__);
return;
}
DecodeDword = ((unsigned int) GetBase64Index(String[0])) << 18;
if (GetBase64Index(String[1]) >= 0) {
//
// still more characters
//
DecodeDword += ((unsigned int) GetBase64Index(String[1])) << 12;
if (GetBase64Index(String[2]) >= 0) {
//
// still more characters
//
DecodeDword += ((unsigned int) GetBase64Index(String[2])) << 6;
if (GetBase64Index(String[3]) >= 0) {
//
// still more characters
//
DecodeDword += (unsigned int) GetBase64Index(String[3]);
DecodeBuffer[Index++] = (unsigned char) ((DecodeDword >> 16) & 0xff);
DecodeBuffer[Index++] = (unsigned char) ((DecodeDword >> 8) & 0xff);
DecodeBuffer[Index++] = (unsigned char) (DecodeDword & 0xff);
} else {
DecodeBuffer[Index++] = (unsigned char) ((DecodeDword >> 16) & 0xff);
DecodeBuffer[Index++] = (unsigned char) ((DecodeDword >> 8) & 0xff);
}
} else {
DecodeBuffer[Index++] = (unsigned char) ((DecodeDword >> 16) & 0xff);
}
}
String += 4;
}
return;
}
VOID
SplitUserName(
TCHAR * FullName,
TCHAR * Domain,
TCHAR * UserName)
{
TCHAR * Slash;
Slash = _tcsstr(FullName, TEXT(":"));
if (Slash) {
// there is a domain name
*Slash = 0;
_tcscpy(Domain, FullName);
_tcscpy(UserName, Slash+1);
*Slash = ':';
} else {
*Domain = 0;
_tcscpy(UserName, FullName);
}
}
#ifdef UNICODE
// caller must free buffer
WCHAR * inet_ntoaw(
struct in_addr stInet
)
{
char * pszAnsiInetStr = inet_ntoa( stInet );
int nStrLen = strlen( pszAnsiInetStr );
WCHAR * pszInetStr = (WCHAR *)calloc( (nStrLen + 1), sizeof( TCHAR ));
int nErr = MultiByteToWideChar( CP_ACP,
MB_PRECOMPOSED,
pszAnsiInetStr,
nStrLen,
pszInetStr,
nStrLen );
if (!nErr)
{
free( pszInetStr );
pszInetStr = NULL;
}
return pszInetStr;
}
BOOL ReadFileW(
HANDLE hFile, // handle of file to read
WCHAR * pszBuffer, // pointer to buffer that receives data
DWORD dwLength, // number of bytes to read
LPDWORD pdwRead, // pointer to number of bytes read
LPOVERLAPPED pData // pointer to structure for data
)
{
BOOL bRet = FALSE;
char * pszAnsi = (char *)calloc( dwLength + 1, sizeof(char *));
if (pszAnsi)
{
bRet = ReadFile( hFile,
pszAnsi,
dwLength,
pdwRead,
pData);
if (bRet)
{
int nErr = MultiByteToWideChar( CP_ACP,
MB_PRECOMPOSED,
pszAnsi,
*pdwRead,
pszBuffer,
*pdwRead );
if (!nErr)
{
bRet = FALSE;
}
}
free( pszAnsi );
}
return bRet;
}
BOOL WriteFileW(
HANDLE hFile, // handle to file to write to
WCHAR * pszBuffer, // pointer to data to write to file
DWORD dwWrite, // number of bytes to write
LPDWORD pdwWritten, // pointer to number of bytes written
LPOVERLAPPED pData // pointer to structure for overlapped I/O
)
{
BOOL bRet = FALSE;
int nStrLen = lstrlen( pszBuffer );
if (nStrLen)
{
char * pszAnsiStr = (char *)malloc( nStrLen + 1 );
if (pszAnsiStr)
{
int nErr = WideCharToMultiByte( CP_ACP,
WC_COMPOSITECHECK,
pszBuffer,
nStrLen,
pszAnsiStr,
nStrLen,
NULL,
NULL );
if (nErr)
{
bRet = WriteFile( hFile,
pszAnsiStr,
dwWrite,
pdwWritten,
pData);
}
free( pszAnsiStr );
}
}
return bRet;
}
// caller most free buffer
BOOL GetAnsiStr(
WCHAR * pszWideStr,
char * pszAnsiStr,
UINT uBufSize
)
{
BOOL bRet = FALSE;
if (pszWideStr && pszAnsiStr)
{
int nStrLen = lstrlen( pszWideStr );
if (nStrLen)
{
int nErr = WideCharToMultiByte( CP_ACP,
WC_COMPOSITECHECK,
pszWideStr,
nStrLen,
pszAnsiStr,
uBufSize - 1,
NULL,
NULL );
if (nErr)
{
pszAnsiStr[nStrLen] = '\0';
bRet = TRUE;
}
}
}
return bRet;
}
#endif