2 Copyright 2004 by the Massachusetts Institute of Technology
6 Permission to use, copy, modify, and distribute this software and its
7 documentation for any purpose and without fee is hereby granted,
8 provided that the above copyright notice appear in all copies and that
9 both that copyright notice and this permission notice appear in
10 supporting documentation, and that the name of the Massachusetts
11 Institute of Technology (M.I.T.) not be used in advertising or publicity
12 pertaining to distribution of the software without specific, written
15 M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
16 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
17 M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
18 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
19 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
20 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
33 LPWSTR lpConnectionName;
34 Args () : bQuiet (0), lpIPAddr (0), lpSubnetMask (0), lpConnectionName (0) { }
36 if (lpIPAddr) free (lpIPAddr);
37 if (lpSubnetMask) free (lpSubnetMask);
38 if (lpConnectionName) free (lpConnectionName);
51 #include "loopbackutils.h"
53 extern "C" DWORD UnInstallLoopBack(void)
58 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
59 SP_DEVINFO_DATA DeviceInfoData;
65 // initialize the structure size
66 DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
68 // copy the net class GUID
69 memcpy(&netGuid, &GUID_DEVCLASS_NET, sizeof(GUID_DEVCLASS_NET));
71 // return a device info set contains all installed devices of the Net class
72 hDeviceInfo = SetupDiGetClassDevs(&netGuid, NULL, NULL, DIGCF_PRESENT);
74 if (hDeviceInfo == INVALID_HANDLE_VALUE)
75 return GetLastError();
77 deviceDesc = (TCHAR *)malloc(MAX_PATH*sizeof(TCHAR));
78 // enumerate the driver info list
79 while (SetupDiEnumDeviceInfo(hDeviceInfo, index, &DeviceInfoData))
81 // try to get the DeviceDesc registry property
82 ok = SetupDiGetDeviceRegistryProperty(hDeviceInfo, &DeviceInfoData,
84 NULL, (PBYTE)deviceDesc,
85 MAX_PATH * sizeof(TCHAR), &size);
89 if (ret != ERROR_INSUFFICIENT_BUFFER)
91 // if the buffer is too small, reallocate
93 deviceDesc = (TCHAR *)malloc(size);
94 ok = SetupDiGetDeviceRegistryProperty(hDeviceInfo,
97 NULL, (PBYTE)deviceDesc,
103 // case insensitive comparison
105 if( _tcsstr(deviceDesc, DRIVER))
118 ret = GetLastError();
119 printf("The %s does not seem to be installed\n", DRIVER_DESC);
123 ok = SetupDiSetSelectedDevice(hDeviceInfo, &DeviceInfoData);
126 ret = GetLastError();
129 ok = SetupDiCallClassInstaller(DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
132 ret = GetLastError();
137 // clean up the device info set
138 if (hDeviceInfo != INVALID_HANDLE_VALUE)
139 SetupDiDestroyDeviceInfoList(hDeviceInfo);
144 BOOL IsLoopbackInstalled(void)
146 TCHAR * hwid = _T("*MSLOOP");
147 HDEVINFO DeviceInfoSet;
148 SP_DEVINFO_DATA DeviceInfoData;
153 // Create a Device Information Set with all present devices.
155 DeviceInfoSet = SetupDiGetClassDevs(NULL, 0, 0, DIGCF_ALLCLASSES | DIGCF_PRESENT ); // All devices present on system
156 if (DeviceInfoSet == INVALID_HANDLE_VALUE)
158 return FALSE; // nothing installed?
162 // Enumerate through all Devices.
165 DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
166 for (i=0; SetupDiEnumDeviceInfo(DeviceInfoSet,i,&DeviceInfoData); i++)
169 TCHAR *p, *buffer = NULL;
170 DWORD buffersize = 0;
173 // We won't know the size of the HardwareID buffer until we call
174 // this function. So call it with a null to begin with, and then
175 // use the required buffer size to Alloc the nessicary space.
176 // Keep calling we have success or an unknown failure.
178 while (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,&DeviceInfoData,SPDRP_HARDWAREID,&DataT,(PBYTE)buffer,buffersize,&buffersize))
180 if (GetLastError() == ERROR_INVALID_DATA)
182 // May be a Legacy Device with no hwid. Continue.
185 else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
187 // We need to change the buffer size.
190 buffer = (TCHAR *)LocalAlloc(LPTR,buffersize);
194 goto cleanup_DeviceInfo;
198 if (GetLastError() == ERROR_INVALID_DATA)
201 // Compare each entry in the buffer multi-sz list with our hwid.
202 for (p=buffer; *p && (p < &buffer[buffersize]); p += _tcslen(p)+1)
204 if (!_tcsicmp(hwid,p))
211 if (buffer) LocalFree(buffer);
217 err = GetLastError();
218 SetupDiDestroyDeviceInfoList(DeviceInfoSet);
225 extern "C" DWORD InstallLoopBack(LPCTSTR pConnectionName, LPCTSTR ip, LPCTSTR mask)
230 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
231 SP_DEVINFO_DATA DeviceInfoData;
232 SP_DRVINFO_DATA DriverInfoData;
233 SP_DEVINSTALL_PARAMS DeviceInstallParams;
234 TCHAR className[MAX_PATH];
235 TCHAR temp[MAX_PATH];
238 BOOL registered = FALSE;
239 BOOL destroyList = FALSE;
244 TCHAR pCfgGuidString[40];
246 // initialize the structure size
247 DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
248 DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
250 // copy the net class GUID
251 memcpy(&netGuid, &GUID_DEVCLASS_NET, sizeof(GUID_DEVCLASS_NET));
253 // create an empty device info set associated with the net class GUID
254 hDeviceInfo = SetupDiCreateDeviceInfoList(&netGuid, NULL);
255 if (hDeviceInfo == INVALID_HANDLE_VALUE)
256 return GetLastError();
258 // get the class name from GUID
259 ok = SetupDiClassNameFromGuid(&netGuid, className, MAX_PATH, NULL);
262 ret = GetLastError();
266 // create a device info element and add the new device instance
268 ok = SetupDiCreateDeviceInfo(hDeviceInfo, className, &netGuid, NULL, NULL,
269 DICD_GENERATE_ID, &DeviceInfoData);
272 ret = GetLastError();
276 // select the newly created device info to be the currently
278 ok = SetupDiSetSelectedDevice(hDeviceInfo, &DeviceInfoData);
281 ret = GetLastError();
285 // build a list of class drivers
286 ok = SetupDiBuildDriverInfoList(hDeviceInfo, &DeviceInfoData,
290 ret = GetLastError();
296 // enumerate the driver info list
297 while (SetupDiEnumDriverInfo(hDeviceInfo, &DeviceInfoData,
298 SPDIT_CLASSDRIVER, index, &DriverInfoData))
300 // if the manufacture is microsoft
301 if (_tcsicmp(DriverInfoData.MfgName, MANUFACTURE) == 0)
303 // case insensitive search for loopback
304 _tcscpy(temp, DriverInfoData.Description);
306 if( _tcsstr(temp, DRIVER))
317 ret = GetLastError();
318 printf("Could not find the %s driver to install\n", DRIVER_DESC);
322 // set the loopback driver to be the currently selected
323 ok = SetupDiSetSelectedDriver(hDeviceInfo, &DeviceInfoData,
327 ret = GetLastError();
331 // register the phantom device to repare for install
332 ok = SetupDiCallClassInstaller(DIF_REGISTERDEVICE, hDeviceInfo,
336 ret = GetLastError();
340 // registered, but remove if errors occur in the following code
343 // ask the installer if we can install the device
344 ok = SetupDiCallClassInstaller(DIF_ALLOW_INSTALL, hDeviceInfo,
348 ret = GetLastError();
349 if (ret != ERROR_DI_DO_DEFAULT)
357 // install the files first
358 ok = SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES, hDeviceInfo,
362 ret = GetLastError();
366 // get the device install parameters and disable filecopy
367 DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
368 ok = SetupDiGetDeviceInstallParams(hDeviceInfo, &DeviceInfoData,
369 &DeviceInstallParams);
372 DeviceInstallParams.Flags |= DI_NOFILECOPY;
373 ok = SetupDiSetDeviceInstallParams(hDeviceInfo, &DeviceInfoData,
374 &DeviceInstallParams);
377 ret = GetLastError();
383 // Register any device-specific co-installers for this device,
386 ok = SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS,
391 ret = GetLastError();
396 // install any installer-specified interfaces.
397 // and then do the real install
399 ok = SetupDiCallClassInstaller(DIF_INSTALLINTERFACES,
404 ret = GetLastError();
408 ok = SetupDiCallClassInstaller(DIF_INSTALLDEVICE,
413 ret = GetLastError();
418 /* Skip to the end if we aren't setting the name */
419 if (!pConnectionName) goto cleanup;
421 // Figure out NetCfgInstanceId
422 hkey = SetupDiOpenDevRegKey(hDeviceInfo,
428 if (hkey == INVALID_HANDLE_VALUE)
430 ret = GetLastError();
434 cbSize = sizeof(pCfgGuidString);
435 ret = RegQueryValueEx(hkey, _T("NetCfgInstanceId"), NULL,
436 &dwValueType, (LPBYTE)pCfgGuidString, &cbSize);
439 ret = RenameConnection(pCfgGuidString, pConnectionName);
442 printf("Could not set the connection name to \"%S\"\n",
447 if (!ip) goto cleanup;
448 ret = SetIpAddress(pCfgGuidString, ip, mask);
451 printf("Could not set the ip address and network mask\n");
454 ret = LoopbackBindings(pCfgGuidString);
457 printf("Could not properly set the bindings\n");
460 ret = !UpdateHostsFile( pConnectionName, ip, "hosts", FALSE );
463 printf("Could not update hosts file\n");
466 ret = !UpdateHostsFile( pConnectionName, ip, "lmhosts", TRUE );
469 printf("Could not update lmhosts file\n");
475 // an error has occured, but the device is registered, we must remove it
476 if (ret != 0 && registered)
477 SetupDiCallClassInstaller(DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
479 found = SetupDiDeleteDeviceInfo(hDeviceInfo, &DeviceInfoData);
481 // destroy the driver info list
483 SetupDiDestroyDriverInfoList(hDeviceInfo, &DeviceInfoData,
485 // clean up the device info set
486 if (hDeviceInfo != INVALID_HANDLE_VALUE)
487 SetupDiDestroyDeviceInfoList(hDeviceInfo);
492 /* The following functions provide the RunDll32 interface
493 * RunDll32 loopback_install.dll doLoopBackEntry [Interface Name] [IP address] [Subnet Mask]
496 static void wcsMallocAndCpy (LPWSTR * dst, const LPWSTR src) {
497 *dst = (LPWSTR) malloc ((wcslen (src) + 1) * sizeof (WCHAR));
501 static void display_usage()
504 L"Installation utility for the MS Loopback Adapter\r\n\r\n"
506 L"RunDll32 loopback_install.dll doLoopBackEntry [q|quiet] [Connection Name] [IP address] [Submask]\r\n",
507 L"loopback_install", MB_ICONINFORMATION | MB_OK );
510 static int process_args (LPWSTR lpCmdLine, Args & args) {
514 argvW = CommandLineToArgvW (lpCmdLine, &iNumArgs);
515 for (i = 0; i < iNumArgs; i++)
517 if (wcsstr (argvW[i], L"help")
518 || !_wcsicmp (argvW[i], L"?")
519 || (wcslen(argvW[i]) == 2 && argvW[i][1] == L'?'))
526 if (!_wcsicmp (argvW[i], L"q") || !_wcsicmp (argvW[i], L"quiet")) {
531 if (!args.lpConnectionName) {
532 wcsMallocAndCpy (&args.lpConnectionName, argvW[i]);
536 if (!args.lpIPAddr) {
537 wcsMallocAndCpy (&args.lpIPAddr, argvW[i]);
541 if (!args.lpSubnetMask) {
542 wcsMallocAndCpy (&args.lpSubnetMask, argvW[i]);
551 if (!args.lpConnectionName)
552 wcsMallocAndCpy (&args.lpConnectionName, DEFAULT_NAME);
554 wcsMallocAndCpy (&args.lpIPAddr, DEFAULT_IP);
555 if (!args.lpSubnetMask)
556 wcsMallocAndCpy (&args.lpSubnetMask, DEFAULT_MASK);
562 void CALLBACK doLoopBackEntryW (HWND hwnd, HINSTANCE hinst, LPWSTR lpCmdLine, int nCmdShow)
566 if (!process_args(lpCmdLine, args))
569 InstallLoopBack(args.lpConnectionName, args.lpIPAddr, args.lpSubnetMask);
572 void CALLBACK uninstallLoopBackEntryW (HWND hwnd, HINSTANCE hinst, LPWSTR lpCmdLine, int nCmdSHow)
577 // This and CoInitializeSecurity fail when running under the MSI
578 // engine, but there seems to be no ill effect (the security is now
579 // set on the specific object via CoSetProxyBlanket in loopback_configure)
580 if(CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE | COINIT_APARTMENTTHREADED ))
582 //Don't fail (MSI install will have already initialized COM)
583 //EasyErrorBox(0, L"Failed to initialize COM.");
587 // Initialize COM security (otherwise we'll get permission denied when we try to use WMI or NetCfg)
588 CoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
595 /* And an MSI installer interface */
597 UINT __stdcall installLoopbackMSI (MSIHANDLE hInstall)
600 DWORD cbValueBuf = 256;
604 szValueBuf = (LPWSTR) malloc (cbValueBuf * sizeof (WCHAR));
605 while (rc = MsiGetPropertyW(hInstall, L"CustomActionData", szValueBuf, &cbValueBuf)) {
607 if (rc == ERROR_MORE_DATA) {
609 szValueBuf = (LPWSTR) malloc (cbValueBuf * sizeof (WCHAR));
612 return ERROR_INSTALL_FAILURE;
615 if (!process_args(szValueBuf, args))
616 return ERROR_INSTALL_FAILURE;
618 rc = InstallLoopBack (args.lpConnectionName, args.lpIPAddr, args.lpSubnetMask);
621 return ERROR_INSTALL_FAILURE;
624 MsiDoActionW (hInstall, L"ScheduleReboot");
627 return ERROR_SUCCESS;
630 UINT __stdcall uninstallLoopbackMSI (MSIHANDLE hInstall)
633 DWORD cbValueBuf = 256;
637 szValueBuf = (LPWSTR) malloc (cbValueBuf * sizeof (WCHAR));
638 while (rc = MsiGetPropertyW(hInstall, L"CustomActionData", szValueBuf, &cbValueBuf)) {
640 if (rc == ERROR_MORE_DATA) {
642 szValueBuf = (LPWSTR) malloc (cbValueBuf * sizeof (WCHAR));
645 return ERROR_INSTALL_FAILURE;
648 if (!process_args(szValueBuf, args))
649 return ERROR_INSTALL_FAILURE;
651 rc = UnInstallLoopBack ();
654 return ERROR_INSTALL_FAILURE;
657 MsiDoActionW (hInstall, L"ScheduleReboot");
660 return ERROR_SUCCESS;