505 lines
16 KiB
C++
505 lines
16 KiB
C++
//+----------------------------------------------------------------------------
|
|
//
|
|
// File: cmsample.cpp
|
|
//
|
|
// Module: CMSAMPLE.DLL
|
|
//
|
|
// Synopsis: Main source for changing proxy file setting using a Tunnel Address
|
|
// with Connection Manager
|
|
//
|
|
// Copyright (c) 2001 - 2002 Microsoft Corporation. All rights reserved.
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
#include <windows.h>
|
|
#include <strsafe.h>
|
|
|
|
// Function prototypes
|
|
|
|
// Main Entry point
|
|
HRESULT WINAPI SetProxyUsingTunnelAddress(HWND hWnd, HINSTANCE hInst,
|
|
LPSTR pszArgs, DWORD nShow);
|
|
LPSTR *GetArgV(LPSTR pszCmdLine);
|
|
BOOL WriteProxyServerSettingToFile(LPCSTR pszSourceFile, LPSTR pszProxyServer);
|
|
BOOL ReadProxyServerByTunnelAddressFromFile(LPCSTR pszSourceFile,
|
|
LPSTR pszTunnelAddress,
|
|
LPSTR *ppszProxyServer);
|
|
|
|
#define CMSAMPLE_STARTING_BUF_SIZE 256 // Starting size of the string buffer
|
|
#define MAX_CMD_ARGS 15 // Maximum number of arguments expected
|
|
|
|
// Enumerations to keep pointer state for parsing command line arguments
|
|
typedef enum _CMDLN_STATE
|
|
{
|
|
CS_END_SPACE, // handling end space
|
|
CS_BEGIN_QUOTE, // we've encountered a begin quote
|
|
CS_END_QUOTE, // we've encountered an end quote
|
|
CS_CHAR, // we're scanning chars
|
|
CS_DONE
|
|
} CMDLN_STATE;
|
|
|
|
|
|
|
|
|
|
extern "C" BOOL WINAPI DllMain(
|
|
HINSTANCE hinstDLL, // handle to DLL module
|
|
DWORD fdwReason, // reason for calling function
|
|
LPVOID lpvReserved // reserved
|
|
)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: SetProxyUsingTunnelAddress
|
|
//
|
|
// Synopsis: Entry point for changing the proxy file settings using a tunnel
|
|
// address. The parameters to the dll are passed via a string which
|
|
// contains parameters.
|
|
//
|
|
// Arguments: HWND hWnd - Window handle of caller
|
|
// HINSTANCE hInst - Instance handle of caller
|
|
// LPSTR pszArgs - Argument string
|
|
// DWORD nShow - Reserved for future use
|
|
//
|
|
// Returns: HRESULT - S_OK or S_FALSE
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
HRESULT WINAPI SetProxyUsingTunnelAddress(HWND hWnd, HINSTANCE hInst,
|
|
LPSTR pszArgs, DWORD nShow)
|
|
{
|
|
// If we wanted to fail the connection we would return E_FAIL, since we
|
|
// still want to connect even if this custom action fails, we just return S_FALSE (by default)
|
|
// or S_OK in a successful case
|
|
HRESULT hr = S_FALSE;
|
|
LPSTR* ArgV = NULL;
|
|
LPSTR pszServiceDir = NULL;
|
|
LPSTR pszTunnelAddress = NULL;
|
|
LPSTR pszProxyFile = NULL;
|
|
LPSTR pszTunnelFile = NULL;
|
|
LPSTR pszTunnelSettingFilePath = NULL;
|
|
LPSTR pszProxyFilePath = NULL;
|
|
LPSTR pszProxyServer = NULL;
|
|
DWORD dwTunnelPathLen = 0;
|
|
DWORD dwProxyPathLen = 0;
|
|
HANDLE hCurrentHeap = GetProcessHeap();
|
|
int i = 0;
|
|
DWORD lcid = 0;
|
|
|
|
// Parse out the command line parameters
|
|
// command line is of the form:
|
|
// /ServiceDir %SERVICEDIR% /TunnelAddress %TUNNELADDRESS% /ProxyFile
|
|
// <PROXYFILE> /TunnelFile <TUNNELFILE>
|
|
|
|
// Check if we have any arguments
|
|
if (!pszArgs)
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Separate each argument in the string by '\0' and return a list of
|
|
// pointers to each argument
|
|
ArgV = GetArgV(pszArgs);
|
|
|
|
// Check if we have any valid parsed arguments
|
|
if (!ArgV)
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Search the command line arguments for the following switches and their
|
|
// corresponding values. Since actual paramter value is at i+1, make sure i
|
|
// is less than the maximum allowed parameters - 1.
|
|
|
|
|
|
lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
|
|
|
|
while (ArgV[i] && ((MAX_CMD_ARGS-1) > i))
|
|
{
|
|
if ((CSTR_EQUAL == CompareString(lcid, NORM_IGNORECASE, ArgV[i], -1, "/ServiceDir", -1)) && ArgV[i+1])
|
|
{
|
|
pszServiceDir = (ArgV[i+1]);
|
|
i = i+2;
|
|
}
|
|
else if ((CSTR_EQUAL == CompareString(lcid, NORM_IGNORECASE, ArgV[i], -1, "/TunnelAddress", -1)) && ArgV[i+1])
|
|
{
|
|
pszTunnelAddress = ArgV[i+1];
|
|
i = i+2;
|
|
}
|
|
else if ((CSTR_EQUAL == CompareString(lcid, NORM_IGNORECASE, ArgV[i], -1, "/ProxyFile", -1)) && ArgV[i+1])
|
|
{
|
|
pszProxyFile = ArgV[i+1];
|
|
i = i+2;
|
|
}
|
|
else if ((CSTR_EQUAL == CompareString(lcid, NORM_IGNORECASE, ArgV[i], -1, "/TunnelFile", -1)) && ArgV[i+1])
|
|
{
|
|
pszTunnelFile = ArgV[i+1];
|
|
i = i+2;
|
|
}
|
|
else
|
|
{
|
|
// Unknown option.
|
|
i++;
|
|
}
|
|
}
|
|
|
|
// Make sure we have values for the arguments
|
|
if (!pszServiceDir || !pszTunnelAddress || !pszProxyFile || !pszTunnelFile)
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Check to see if we got zero length string values from the command line
|
|
// arguments. Exit if that is the case.
|
|
if (!(*pszServiceDir) || !(*pszTunnelAddress) ||
|
|
!(*pszProxyFile) || !(*pszTunnelFile))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Calculate the string size for the two paths that need to be created
|
|
// Add 2 for the NULL and backslash
|
|
dwTunnelPathLen = lstrlen(pszServiceDir) + lstrlen(pszTunnelFile) + 2;
|
|
dwProxyPathLen = lstrlen(pszServiceDir) + lstrlen(pszProxyFile) + 2;
|
|
|
|
// Allocate the memory
|
|
pszTunnelSettingFilePath = (LPSTR)HeapAlloc(hCurrentHeap, HEAP_ZERO_MEMORY,
|
|
dwTunnelPathLen); // ANSI - char == byte
|
|
if (!pszTunnelSettingFilePath)
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
pszProxyFilePath = (LPSTR)HeapAlloc(hCurrentHeap, HEAP_ZERO_MEMORY,
|
|
dwProxyPathLen); // ANSI - char == byte
|
|
if (!pszProxyFilePath)
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Since we allocated pszTunnelSettingFilePath, we know that it has enough
|
|
// room to fit the path. Otherwise we would have to use _snprintf or wnsprintf.
|
|
// Copy the Service directory to create the full path.
|
|
StringCchPrintf(pszTunnelSettingFilePath, dwTunnelPathLen, "%s\\%s", pszServiceDir, pszTunnelFile);
|
|
|
|
// Since we allocated pszTunnelSettingFilePath, we know that it has enough
|
|
// room to fit the path. Otherwise we would have to use _snprintf or wnsprintf.
|
|
//Create the full path to the Proxy file.
|
|
StringCchPrintf(pszProxyFilePath, dwProxyPathLen, "%s\\%s", pszServiceDir, pszProxyFile);
|
|
|
|
if (ReadProxyServerByTunnelAddressFromFile(pszTunnelSettingFilePath,
|
|
pszTunnelAddress,
|
|
&pszProxyServer))
|
|
{
|
|
// Call WriteProxyServerSettingToFile - the function checks for empty
|
|
// strings
|
|
if(WriteProxyServerSettingToFile(pszProxyFilePath, pszProxyServer))
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
// Clean up allocated memory
|
|
// Delete the argument pointers, Tunnel Server path, Proxy file path and
|
|
// ProxyServer name pointers
|
|
if (ArgV)
|
|
HeapFree(hCurrentHeap, 0, (LPVOID)ArgV);
|
|
|
|
if (pszTunnelSettingFilePath)
|
|
HeapFree(hCurrentHeap, 0, (LPVOID)pszTunnelSettingFilePath);
|
|
|
|
if (pszProxyFilePath)
|
|
HeapFree(hCurrentHeap, 0, (LPVOID)pszProxyFilePath);
|
|
|
|
if (pszProxyServer)
|
|
HeapFree(hCurrentHeap, 0, (LPVOID)pszProxyServer);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: ReadProxyServerByTunnelAddressFromFile
|
|
//
|
|
// Synopsis: Reads the proxy settings from the given proxy file and stores
|
|
// them in the provided pointer. Please note that the buffers
|
|
// allocated here and stored in ppszProxyServer must be freed by
|
|
// the caller. If the TunnelAddress doesn't exist in the
|
|
// pszSourceFile this function still allocates memory and returns
|
|
// an empty string.
|
|
//
|
|
// Arguments: LPCSTR pszSourceFile - file from which to read the proxy
|
|
// settings
|
|
// LPSTR pszTunnelAddress - string containing the TunnelAddress
|
|
// used to look up the ProxyServer value
|
|
// OUT LPSTR *ppszProxyServer - string pointer that will have the Proxy
|
|
// server value (in server:port format)
|
|
//
|
|
// Returns: BOOL - TRUE if the settings were successfully read
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
BOOL ReadProxyServerByTunnelAddressFromFile(LPCSTR pszSourceFile,
|
|
LPSTR pszTunnelAddress,
|
|
LPSTR *ppszProxyServer)
|
|
{
|
|
BOOL bReturn = FALSE;
|
|
BOOL bExit = FALSE;
|
|
DWORD dwReturnedSize = 0;
|
|
DWORD dwSize = CMSAMPLE_STARTING_BUF_SIZE;
|
|
HANDLE hCurrentHeap = GetProcessHeap();
|
|
|
|
// Section in Tunnel to read
|
|
const CHAR* const c_pszTunnelAddressSection = "Tunnel Address";
|
|
|
|
// Check parameters
|
|
if ((NULL == ppszProxyServer) || (NULL == pszSourceFile) ||
|
|
(NULL == pszTunnelAddress))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Check for empty strings
|
|
if (!(*pszSourceFile) || !(*pszTunnelAddress))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Set the incoming pointer to NULL
|
|
*ppszProxyServer = NULL;
|
|
|
|
|
|
// In case the original buffer size is too small, the loop will try to
|
|
// allocate more buffer space and try to read the value until. The
|
|
// loop will exist if the value properly fits into the buffer or the size
|
|
// exceeds 2048.
|
|
do
|
|
{
|
|
if (*ppszProxyServer)
|
|
{
|
|
// Free allocated memory
|
|
HeapFree(hCurrentHeap, 0, (LPVOID)*ppszProxyServer);
|
|
*ppszProxyServer = NULL;
|
|
}
|
|
|
|
// Allocate space for the ProxyServer name
|
|
*ppszProxyServer = (LPSTR)HeapAlloc(hCurrentHeap, HEAP_ZERO_MEMORY,
|
|
dwSize); //ANSI - char == byte
|
|
|
|
if (*ppszProxyServer)
|
|
{
|
|
// Since memory allocation succeeded, read the value from the
|
|
// settings file
|
|
dwReturnedSize = GetPrivateProfileString(c_pszTunnelAddressSection,
|
|
pszTunnelAddress, "",
|
|
*ppszProxyServer, dwSize,
|
|
pszSourceFile);
|
|
|
|
// Check if the value fits into the buffer
|
|
if ((dwReturnedSize == (dwSize - 2)) ||
|
|
(dwReturnedSize == (dwSize - 1)))
|
|
{
|
|
// The buffer is too small, lets allocate a bigger one
|
|
dwSize = 2*dwSize;
|
|
if (dwSize > 2048)
|
|
{
|
|
// Allocation above 2K, need to exit
|
|
HeapFree(hCurrentHeap, 0, (LPVOID)*ppszProxyServer);
|
|
*ppszProxyServer = NULL;
|
|
goto exit;
|
|
}
|
|
}
|
|
else if (0 == dwReturnedSize)
|
|
{
|
|
// Either we got an error, or more likely there was no data
|
|
// to get
|
|
HeapFree(hCurrentHeap, 0, (LPVOID)*ppszProxyServer);
|
|
*ppszProxyServer = NULL;
|
|
goto exit;
|
|
}
|
|
else
|
|
{
|
|
// The function read in the data correctly. Just return.
|
|
return TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bExit = TRUE;
|
|
}
|
|
|
|
} while (!bExit);
|
|
|
|
exit:
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: WriteProxyServerSettingToFile
|
|
//
|
|
// Synopsis: Writes the specified settings to the given backup proxy filename.
|
|
// Please see the above format guide for specifics.
|
|
//
|
|
// Arguments: LPCSTR pszSourceFile - file to write the current settings to
|
|
// LPSTR pszProxyServer - proxy server string in server:port format
|
|
//
|
|
// Returns: BOOL - TRUE if the values were written successfully
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
BOOL WriteProxyServerSettingToFile(LPCSTR pszSourceFile, LPSTR pszProxyServer)
|
|
{
|
|
BOOL bReturn = FALSE;
|
|
|
|
// Section in Proxy file to update
|
|
const CHAR* const c_pszManualProxySection = "Manual Proxy";
|
|
|
|
// Key in Proxy file to update
|
|
const CHAR* const c_pszProxyServer = "ProxyServer";
|
|
|
|
// Check input params
|
|
if ( (NULL == pszSourceFile) || (NULL == pszProxyServer))
|
|
{
|
|
return bReturn;
|
|
}
|
|
|
|
// Check for empty strings
|
|
if (!(*pszSourceFile) || !(*pszProxyServer))
|
|
{
|
|
return bReturn;
|
|
}
|
|
|
|
// Save the Proxy Server name to the Proxy setting file
|
|
if (WritePrivateProfileString(c_pszManualProxySection, c_pszProxyServer,
|
|
pszProxyServer, pszSourceFile))
|
|
{
|
|
bReturn = TRUE;
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: GetArgV
|
|
//
|
|
// Synopsis: Simulates ArgV using GetCommandLine to parse the parameters
|
|
//
|
|
// Arguments: LPSTR pszCmdLine - Ptr to a copy of the command line to be
|
|
// processed
|
|
//
|
|
// Returns: LPSTR * - Ptr to a ptr array containing the arguments. Caller is
|
|
// responsible for releasing memory.
|
|
//
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
LPSTR *GetArgV(LPSTR pszCmdLine)
|
|
{
|
|
HANDLE hCurrentHeap = GetProcessHeap();
|
|
|
|
if (NULL == pszCmdLine || NULL == pszCmdLine[0])
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// Allocate Ptr array, up to MAX_CMD_ARGS ptrs
|
|
LPSTR *ppArgV = (LPSTR *) HeapAlloc(hCurrentHeap, HEAP_ZERO_MEMORY,
|
|
sizeof(LPSTR) * MAX_CMD_ARGS);
|
|
|
|
if (NULL == ppArgV)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// Declare locals
|
|
LPSTR pszCurr = NULL;
|
|
LPSTR pszNext = NULL;
|
|
LPSTR pszToken = NULL;
|
|
CMDLN_STATE state;
|
|
state = CS_CHAR;
|
|
int ndx = 0;
|
|
|
|
// Parse out pszCmdLine and store pointers in ppArgV
|
|
pszCurr = pszToken = pszCmdLine;
|
|
|
|
do
|
|
{
|
|
switch (*pszCurr)
|
|
{
|
|
case ' ':
|
|
if (state == CS_CHAR)
|
|
{
|
|
// We found a token
|
|
pszNext = CharNext(pszCurr);
|
|
*pszCurr = '\0';
|
|
|
|
ppArgV[ndx] = pszToken;
|
|
ndx++;
|
|
|
|
pszCurr = pszToken = pszNext;
|
|
state = CS_END_SPACE;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if (state == CS_END_SPACE || state == CS_END_QUOTE)
|
|
{
|
|
pszToken = CharNext(pszToken);
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case '\"':
|
|
if (state == CS_BEGIN_QUOTE)
|
|
{
|
|
// We found a token
|
|
pszNext = CharNext(pszCurr);
|
|
*pszCurr = '\0';
|
|
|
|
// skip the opening quote
|
|
pszToken = CharNext(pszToken);
|
|
|
|
ppArgV[ndx] = pszToken;
|
|
ndx++;
|
|
|
|
pszCurr = pszToken = pszNext;
|
|
|
|
state = CS_END_QUOTE;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
state = CS_BEGIN_QUOTE;
|
|
}
|
|
break;
|
|
|
|
case '\0':
|
|
if (state != CS_END_QUOTE)
|
|
{
|
|
// End of the line, set last token
|
|
ppArgV[ndx] = pszToken;
|
|
}
|
|
state = CS_DONE;
|
|
break;
|
|
|
|
default:
|
|
if (state == CS_END_SPACE || state == CS_END_QUOTE)
|
|
{
|
|
state = CS_CHAR;
|
|
}
|
|
break;
|
|
}
|
|
|
|
pszCurr = CharNext(pszCurr);
|
|
} while ((state != CS_DONE) && (MAX_CMD_ARGS > ndx));
|
|
|
|
return ppArgV;
|
|
}
|