440 lines
15 KiB
C++
440 lines
15 KiB
C++
/*
|
|
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
* PARTICULAR PURPOSE.
|
|
*
|
|
* Copyright © 2000 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* Author: Stephen R. Husak - Microsoft Developer Support
|
|
*
|
|
* Abstract:
|
|
* The DLL provides DLLRegisterServer/DLLUnregisterServer
|
|
* exports to provide a way to install the DLL into the registry
|
|
* correctly for Windows 2000. In this manner one can use regsvr32.exe
|
|
* to add/remove the custom DLL in the registry. This is normally used
|
|
* for COM objects and servers but I use it here as a simple technique of
|
|
* wrapping everything in one place.
|
|
*/
|
|
|
|
/*
|
|
* Includes
|
|
*/
|
|
//#define WINVER 0x0500 // needed for Windows 2000 RAS extensions
|
|
|
|
#ifndef UNICODE
|
|
#define UNICODE // this is UNICODE
|
|
#endif
|
|
|
|
#include <windows.h> // include windows
|
|
#include <ras.h> // include RAS for creating the entry
|
|
#include <raserror.h>
|
|
#include <stddef.h> // includes type definitions
|
|
#include <strsafe.h>
|
|
|
|
#define CELEMS(x) ((sizeof(x))/(sizeof(x[0])))
|
|
|
|
/*
|
|
* constants for configuration
|
|
*/
|
|
#define RASCUSTOMDIAL_KEYPATH L"SYSTEM\\CurrentControlSet\\Services\\Rasman\\Parameters"
|
|
#define RASCUSTOMDIAL_VALUENAME L"CustomDLL"
|
|
#define RASCUSTOMDIAL_ENTRYNAME L"Steelhead"
|
|
#define RASCUSTOMDIAL_PHONENO L"29719"
|
|
|
|
/*
|
|
* from the customdial.cpp file
|
|
*/
|
|
extern HANDLE g_hInstance; // from DLLMain
|
|
extern void OutputTraceString(LPTSTR lpszFormatString, ...);
|
|
|
|
/*
|
|
* CreateTestEntry
|
|
*
|
|
* creates a test entry for testing this DLL
|
|
*/
|
|
BOOL CreateTestEntry(LPCTSTR szDLLPath)
|
|
{
|
|
DWORD rc; // return code from function calls
|
|
DWORD dwSize; // structure size
|
|
RASENTRY *RasEntry = NULL; // Ras Entry structure
|
|
BOOL bResult = TRUE; // return for the function
|
|
RasEntry = (RASENTRY *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
sizeof(RASENTRY));
|
|
|
|
OutputTraceString(L"CreateTestEntry called in customdial.dll\n");
|
|
rc = RasGetEntryProperties(NULL, L"", RasEntry, &dwSize, NULL, NULL);
|
|
if( rc == ERROR_BUFFER_TOO_SMALL )
|
|
{
|
|
RasEntry = (RASENTRY *) HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
RasEntry, dwSize);
|
|
RasEntry->dwSize = sizeof( RASENTRY );
|
|
rc = RasGetEntryProperties(NULL, L"", RasEntry, &dwSize, NULL, NULL);
|
|
}
|
|
|
|
if( rc != ERROR_SUCCESS )
|
|
{
|
|
OutputTraceString(L"--- RasGetEntryProperties returned error: %ld.\n", rc );
|
|
bResult = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// Validate the format of the connection entry name.
|
|
rc = RasValidateEntryName(NULL, RASCUSTOMDIAL_ENTRYNAME);
|
|
if (rc == ERROR_INVALID_NAME)
|
|
{
|
|
OutputTraceString(L"--- RasValidateEntryName returned invalid name in CreateTestEntry: %d\n", rc);
|
|
bResult = FALSE;
|
|
}
|
|
else if (rc == ERROR_ALREADY_EXISTS)
|
|
{
|
|
rc = RasGetEntryProperties(NULL, RASCUSTOMDIAL_ENTRYNAME, RasEntry, &dwSize, NULL, NULL);
|
|
|
|
if (rc == ERROR_BUFFER_TOO_SMALL)
|
|
{
|
|
RasEntry = (RASENTRY *) HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
RasEntry, dwSize);
|
|
RasEntry->dwSize = sizeof( RASENTRY );
|
|
rc = RasGetEntryProperties(NULL, RASCUSTOMDIAL_ENTRYNAME, RasEntry, &dwSize, NULL, NULL);
|
|
}
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
OutputTraceString(L"--- RasGetEntryProperties failed in CreateTestEntry: %d\n", rc);
|
|
bResult = FALSE;
|
|
}
|
|
else
|
|
// Just modify the existing entry to make sure DLL is set
|
|
StringCchCopy(RasEntry->szCustomDialDll, CELEMS(RasEntry->szCustomDialDll), szDLLPath);
|
|
}
|
|
else
|
|
{
|
|
|
|
rc = RasGetEntryProperties(NULL, L"", RasEntry, &dwSize, NULL, NULL);
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
OutputTraceString(L"--- RasGetEntryProperties failed in CreateTestEntry: %d\n", rc);
|
|
bResult = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// Modify the default entry
|
|
StringCchCopy(RasEntry->szLocalPhoneNumber, CELEMS( RasEntry->szLocalPhoneNumber ), RASCUSTOMDIAL_PHONENO);
|
|
StringCchCopy(RasEntry->szDeviceType, CELEMS( RasEntry->szDeviceType ), RASDT_Modem);
|
|
StringCchCopy(RasEntry->szCustomDialDll, CELEMS( RasEntry->szCustomDialDll ), szDLLPath);
|
|
|
|
//
|
|
// enumerate to get the device name to use - we'll just pick one (a modem)
|
|
//
|
|
// first get the size of the buffer required
|
|
LPRASDEVINFO lpRasDevInfo;
|
|
DWORD dwNumEntries;
|
|
|
|
RasEnumDevices(NULL, &dwSize, &dwNumEntries);
|
|
lpRasDevInfo = (LPRASDEVINFO) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
|
|
if (lpRasDevInfo == NULL)
|
|
{
|
|
OutputTraceString(L"--- HeapAlloc failed in CreateTestEntry (GetLastError = %d)\n", GetLastError());
|
|
bResult = FALSE;
|
|
}
|
|
else
|
|
{
|
|
lpRasDevInfo->dwSize = sizeof(RASDEVINFO);
|
|
|
|
rc = RasEnumDevices(lpRasDevInfo, &dwSize, &dwNumEntries);
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
OutputTraceString(L"--- RasEnumDevices failed in CreateTestEntry: %d", rc);
|
|
bResult = FALSE;
|
|
}
|
|
else
|
|
{
|
|
for (UINT i=0; i < dwNumEntries; i++, lpRasDevInfo++)
|
|
{
|
|
if (lstrcmpi(lpRasDevInfo->szDeviceType, RASDT_Modem) == 0)
|
|
{
|
|
OutputTraceString(L"-- Modem device: %s\n", lpRasDevInfo->szDeviceName);
|
|
StringCchCopy(RasEntry->szDeviceName, CELEMS( RasEntry->szDeviceName ), lpRasDevInfo->szDeviceName);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(), 0, lpRasDevInfo);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( rc == ERROR_SUCCESS )
|
|
{
|
|
// write the phonebook entry.
|
|
rc = RasSetEntryProperties(NULL, RASCUSTOMDIAL_ENTRYNAME, RasEntry, sizeof(RASENTRY), NULL, 0);
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
OutputTraceString(L"--- RasSetEntryProperties failed in CreateTestEntry: %d\n", rc);
|
|
bResult = FALSE;
|
|
}
|
|
}
|
|
|
|
OutputTraceString(L"CreateTestEntry exiting customdial.dll\n");
|
|
|
|
if( RasEntry )
|
|
{
|
|
HeapFree( GetProcessHeap(), 0, RasEntry );
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
* CheckForSelf
|
|
*
|
|
* checks a buffer of \0 terminated strings for an instance of
|
|
* string that could be present and returns the position of that
|
|
* string in the buffer
|
|
*/
|
|
TCHAR * CheckForSelf(LPCTSTR pSrc, LPBYTE pDest, DWORD dwBufLen)
|
|
{
|
|
DWORD dwLen = 0; // length of the buffer
|
|
TCHAR * p; // pointer into the buffer
|
|
|
|
// loop through the buffer up to the length
|
|
while (dwLen < dwBufLen)
|
|
{
|
|
p = (LPTSTR) &pDest[dwLen]; // get out string
|
|
|
|
if (lstrcmpi(pSrc, p) == 0) // check it
|
|
return p;
|
|
|
|
// go past string we just checked + the terminating '\0'
|
|
dwLen = dwLen + ((lstrlen(p) + 1) * sizeof(TCHAR));
|
|
}
|
|
|
|
return NULL; // string was not found
|
|
}
|
|
|
|
/*
|
|
* DllRegisterServer
|
|
*
|
|
* We are "overriding" the intent of this to provide an easy way to
|
|
* install our DLL into the correct registry locations using "common" tools
|
|
* such as regsvr32.exe.
|
|
*
|
|
* We need to add our DLL to the list of custom dial DLLs in:
|
|
* Path: \\HKLM\System\CurrentControlSet\Services\Rasman\Parameters
|
|
* Key Type: REG_MULTI_SZ
|
|
* Value Name: CustomDLL
|
|
* Value: Full path to the DLL
|
|
*
|
|
* this either return E_UNEXPECTED if any error occurred or S_OK if success or
|
|
* if it is already there
|
|
*/
|
|
STDAPI DllRegisterServer(void)
|
|
{
|
|
HRESULT hr = E_UNEXPECTED; // return code
|
|
HKEY hKey; // handle to open registry key
|
|
TCHAR wszPath[MAX_PATH]; // full path to this DLL
|
|
|
|
|
|
OutputTraceString(L"DllRegisterServer called in customdial.dll\n");
|
|
|
|
// get the path to this DLL
|
|
GetModuleFileName((HMODULE) g_hInstance, wszPath, MAX_PATH);
|
|
|
|
// open registry for reading/writing
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, RASCUSTOMDIAL_KEYPATH,
|
|
0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
// read in current value
|
|
DWORD dwSize = 0; // size of buffer for reading registry
|
|
DWORD dwBufSize = 0; // size of buffer for writing to registry
|
|
DWORD dwType; // type of buffer
|
|
LPBYTE buffer = NULL; // the buffer
|
|
|
|
__try
|
|
{
|
|
// obtain current value size
|
|
RegQueryValueEx(hKey, RASCUSTOMDIAL_VALUENAME, NULL, &dwType, NULL, &dwSize);
|
|
|
|
// allocate buffer to read (and write) all NULLs will be there
|
|
if (dwSize > 0)
|
|
dwBufSize = dwSize + (lstrlen(wszPath) * sizeof(TCHAR)) + sizeof(TCHAR); // should be terminated in a \0
|
|
else
|
|
dwBufSize = (lstrlen(wszPath) * sizeof(TCHAR)) + (2 * sizeof(TCHAR)); // should be terminated in a \0\0 pair
|
|
|
|
buffer = (LPBYTE) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS, dwBufSize);
|
|
|
|
// read it if dwSize was > 0
|
|
if (dwSize > 0)
|
|
{
|
|
if (RegQueryValueEx(hKey, RASCUSTOMDIAL_VALUENAME, NULL, &dwType, buffer, &dwSize) != ERROR_SUCCESS)
|
|
return hr; // force to finally block via AbnormalTermination
|
|
}
|
|
|
|
// if it isn't there add it in
|
|
if (CheckForSelf(wszPath, buffer, dwSize) == NULL)
|
|
{
|
|
DWORD dwBufPosition = 0; // position of new string in the buffer
|
|
|
|
if (dwSize > 0)
|
|
dwBufPosition = dwSize - sizeof(TCHAR); // back off original pos
|
|
|
|
// add to the buffer
|
|
CopyMemory(&buffer[dwBufPosition], wszPath, lstrlen(wszPath) * sizeof(TCHAR));
|
|
|
|
// write it
|
|
dwType = REG_MULTI_SZ;
|
|
if (RegSetValueEx(hKey, RASCUSTOMDIAL_VALUENAME, 0, dwType, buffer, dwBufSize) != ERROR_SUCCESS)
|
|
return hr; // force to finally block via AbnormalTermination
|
|
}
|
|
else
|
|
__leave; // it is already there - force to finally block normally
|
|
}
|
|
__finally
|
|
{
|
|
if (!AbnormalTermination())
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
|
|
if (buffer)
|
|
HeapFree(GetProcessHeap(), 0, buffer);
|
|
|
|
RegCloseKey(hKey);
|
|
} // finally block
|
|
}
|
|
|
|
CreateTestEntry(wszPath);
|
|
|
|
if (hr == S_OK)
|
|
MessageBox(NULL, L"Windows may have to be restarted for the changes to take effect.",
|
|
L"CustomDial DLL Sample", MB_OK);
|
|
|
|
OutputTraceString(L"DllRegisterServer exiting customdial.dll with return code: 0x%08x\n", hr);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*
|
|
* DllUnregisterServer
|
|
*
|
|
* We are "overriding" the intent of this to provide an easy way to
|
|
* uninstall our DLL from the registry using "common" tools such as
|
|
* regsvr32.exe.
|
|
*
|
|
* this either return E_UNEXPECTED if any error occurred or S_OK if success or
|
|
* if it isn't there
|
|
*/
|
|
STDAPI DllUnregisterServer(void)
|
|
{
|
|
HRESULT hr = E_UNEXPECTED; // return code
|
|
HKEY hKey; // handle to open registry key
|
|
TCHAR wszPath[MAX_PATH]; // full path to this DLL
|
|
DebugBreak();
|
|
|
|
OutputTraceString(L"DllUnregisterServer called in customdial.dll\n");
|
|
|
|
// get the path to this DLL
|
|
GetModuleFileName((HMODULE) g_hInstance, wszPath, MAX_PATH);
|
|
|
|
// open registry for reading/writing
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, RASCUSTOMDIAL_KEYPATH,
|
|
0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
DWORD dwSize = 0; // size of buffer for reading/writing registry
|
|
DWORD dwType = 0; // type of buffer
|
|
LPBYTE buffer = NULL; // the buffer
|
|
LPBYTE newBuffer = NULL; // pointer to buffer
|
|
TCHAR * p = NULL; // pointer to the string in the buffer
|
|
ptrdiff_t uPos = 0; // position of string in buffer
|
|
|
|
__try
|
|
{
|
|
// obtain current value size
|
|
RegQueryValueEx(hKey, RASCUSTOMDIAL_VALUENAME, NULL, &dwType, NULL, &dwSize);
|
|
|
|
if (dwSize > 0)
|
|
{
|
|
// allocate buffer to read
|
|
buffer = (LPBYTE) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS, dwSize);
|
|
}
|
|
else
|
|
__leave; // there's nothing there...
|
|
|
|
// read current value
|
|
if (RegQueryValueEx(hKey, RASCUSTOMDIAL_VALUENAME, NULL, &dwType, buffer, &dwSize) != ERROR_SUCCESS)
|
|
return hr; // force to finally block via AbnormalTermination
|
|
|
|
// rebuild buffer without the string in there
|
|
newBuffer = buffer;
|
|
p = CheckForSelf(wszPath, newBuffer, dwSize);
|
|
|
|
if (p == NULL) // it's not there
|
|
__leave;
|
|
|
|
// determine the position of the string in the buffer, move other data
|
|
// accordingly and adjust size
|
|
uPos = (LPBYTE) p - newBuffer;
|
|
if (uPos == 0)
|
|
{
|
|
// it's the beginning - just move the buffer
|
|
newBuffer = &newBuffer[(lstrlen(p) + 1) * sizeof(TCHAR)];
|
|
dwSize = dwSize - ((lstrlen(p) + 1) * sizeof(TCHAR));
|
|
}
|
|
else
|
|
if (uPos + (lstrlen(p) * sizeof(TCHAR)) + (2 * sizeof(TCHAR)) == dwSize)
|
|
{
|
|
// it's the last one - adjust size and add a double termination
|
|
dwSize = dwSize - ((lstrlen(p) + 1) * sizeof(TCHAR));
|
|
CopyMemory(&newBuffer[dwSize - sizeof(TCHAR)], L"\0", sizeof(TCHAR));
|
|
}
|
|
else
|
|
{
|
|
// it's in the middle - move the back to overwriting the org. position
|
|
DWORD dwCopySize = dwSize - (uPos + ((lstrlen(p) + 1) * sizeof(TCHAR)));
|
|
dwSize = dwSize - ((lstrlen(p) + 1) * sizeof(TCHAR));
|
|
CopyMemory(&newBuffer[uPos], &newBuffer[uPos + ((lstrlen(p) + 1) * sizeof(TCHAR))], dwCopySize);
|
|
}
|
|
|
|
// write it or delete it
|
|
if (dwSize > sizeof(TCHAR)) // there is only 1 '\0' left...
|
|
{
|
|
dwType = REG_MULTI_SZ;
|
|
if (RegSetValueEx(hKey, RASCUSTOMDIAL_VALUENAME, 0, dwType, newBuffer, dwSize) != ERROR_SUCCESS)
|
|
return hr; // force to finally block via AbnormalTermination
|
|
}
|
|
else
|
|
if (RegDeleteValue(hKey, RASCUSTOMDIAL_VALUENAME) != ERROR_SUCCESS)
|
|
return hr; // force to finally block via AbnormalTermination
|
|
}
|
|
__finally
|
|
{
|
|
if (!AbnormalTermination())
|
|
{
|
|
// means there was no error during calls and we reached here via normal
|
|
// unwrapping of the stack
|
|
hr = S_OK;
|
|
}
|
|
|
|
if (buffer)
|
|
HeapFree(GetProcessHeap(), 0, buffer);
|
|
|
|
RegCloseKey(hKey);
|
|
} // finally block
|
|
}
|
|
|
|
// remove the test entry
|
|
if (DWORD rc = RasDeleteEntry(NULL, RASCUSTOMDIAL_ENTRYNAME) != ERROR_SUCCESS)
|
|
OutputTraceString(L"--- RasDeleteEntry failed in DllUnregisterServer: Error = %d\n", rc);
|
|
|
|
if (hr == S_OK)
|
|
MessageBox(NULL, L"Windows may have to be restarted for the changes to take effect.",
|
|
L"CustomDial DLL Sample", MB_OK);
|
|
|
|
OutputTraceString(L"DllUnregisterServer exiting customdial.dll with return code: 0x%08x\n", hr);
|
|
|
|
return hr;
|
|
}
|
|
|
|
// EOF: customdialreg.cpp
|