Home Products Support Services Contact
TMG Development Home
  Generic Setup.exe Utility Software Applications : Developer Components : Consultancy 
Products
  PrintForm .NET
  PrintAdapters .NET
  Localizer ASP.NET
  WebExtenders .NET
  CryptoText
  BatteryTimer
Free Utilities
  VersionCheck .NET
  xsdcf .NET CF
  Setup.exe Utility
Downloads
Purchase
Support
  PrintForm .NET
  PrintAdapters .NET
  Localizer ASP.NET
  WebExtenders .NET
  CryptoText
  BatteryTimer
About Us
  Services
  Contact
  Privacy Statement
Developer Links
  .NET Links
  Pocket PC / WinCE
 
Microsoft Certified Partner

Generic Setup.exe Utility

When building .NET applications and components you may come across the need for a basic setup.exe that will launch your msi file in a user friendly manner.

Users expect to find a 'setup.exe' to click on when they receive your product, but the only way to get this from a Visual Studio .NET deployment project is to allow it to include the installers for MSI itself. Since these total over 3.5MB you don't usually want to distribute them unless you have to.

Our free Setup.exe app does the following:

  • Automatically locates any msi file in the same folder as itself (limitation: it will use the first one returned by the FindFirstFile API call)
  • Checks that the Windows Installer is present before trying to open the msi file, and presents a user friendly message if it isn't, directing the user to the Microsoft Downloads site
  • Reads the MSI Title from the package and presents a confirmation dialog like: 'This setup routine will install the following program: XYZ Product. Are you sure you want to continue?'. The MSI Title corresponds to the Title property of the Deployment Project in VS.NET
  • Launches MSIExec to process the msi file

Usage

To use setup.exe, all you have to do is copy it into the same folder as your msi file and run it.

Licensing

It is completely free to use and distribute with your own applications, though needless to say as a free utility comes with no warranty as to fitness for purpose at all.

Download Free Setup.exe utility here.

Here's the code we use to extract the title from the msi file, in case you want to incorporate it into your own apps:

/////////////////////////////////////////////////////////////////////////////////
// Dynamically loads msi.dll and locates functions necessary for querying the
// MSI file's title property.
// Returns true if necessary msi exported functions were found, false otherwise.
// The MSI Title is returned in the specified titleMSIBuffer.
/////////////////////////////////////////////////////////////////////////////////
bool GetInstallerTitle(LPCTSTR fileNameMSI, LPCTSTR titleMSIBuffer, size_t sizeBufferBytes)
{
	memset((LPVOID)titleMSIBuffer, 0, sizeBufferBytes);
	bool MSIInstalled = false;

	// get all the installer functions we need dynamically, we may not have MSI installed...
	HINSTANCE hInstMSI = ::LoadLibrary(_T("msi.dll"));
	UINT (APIENTRY *fnMsiOpenDatabase)(LPCTSTR, LPCTSTR, MSIHANDLE*);
	UINT (APIENTRY *fnMsiGetSummaryInformation)(MSIHANDLE, LPCTSTR, UINT, MSIHANDLE*);
	UINT (APIENTRY *fnMsiSummaryInfoGetProperty)(MSIHANDLE, UINT, UINT*, INT*, FILETIME*, LPSTR, DWORD*);
	UINT (APIENTRY *fnMsiCloseHandle)(MSIHANDLE);

	if (hInstMSI != NULL)
	{
#if defined (UNICODE)
		(FARPROC&)fnMsiOpenDatabase = GetProcAddress(hInstMSI, "MsiOpenDatabaseW");
		(FARPROC&)fnMsiGetSummaryInformation = GetProcAddress(hInstMSI, "MsiGetSummaryInformationW");
		(FARPROC&)fnMsiSummaryInfoGetProperty = GetProcAddress(hInstMSI, "MsiSummaryInfoGetPropertyW");
#else
		(FARPROC&)fnMsiOpenDatabase = GetProcAddress(hInstMSI, "MsiOpenDatabaseA");
		(FARPROC&)fnMsiGetSummaryInformation = GetProcAddress(hInstMSI, "MsiGetSummaryInformationA");
		(FARPROC&)fnMsiSummaryInfoGetProperty = GetProcAddress(hInstMSI, "MsiSummaryInfoGetPropertyA");
#endif
		(FARPROC&)fnMsiCloseHandle = GetProcAddress(hInstMSI, "MsiCloseHandle");

		// if got all necessary functions
		if (fnMsiCloseHandle && fnMsiSummaryInfoGetProperty && fnMsiGetSummaryInformation && fnMsiOpenDatabase)
		{
			MSIInstalled = true;
			DWORD ret = ERROR_SUCCESS;
			MSIHANDLE msih = NULL, sumh = NULL;
			UINT property_type = VT_LPSTR;

			if((ret = fnMsiOpenDatabase(fileNameMSI, MSIDBOPEN_READONLY, &msih)) == ERROR_SUCCESS)
			{
				if((ret = fnMsiGetSummaryInformation(msih, 0, 0, &sumh)) == ERROR_SUCCESS)
				{
					DWORD size = (DWORD)sizeBufferBytes/sizeof(*titleMSIBuffer);
					ret = fnMsiSummaryInfoGetProperty(sumh, PID_TITLE, &property_type, NULL, NULL, (LPTSTR)titleMSIBuffer, &size);
					ret = fnMsiCloseHandle(sumh);
				}
				ret = fnMsiCloseHandle(msih);
			}
		}
		FreeLibrary(hInstMSI);
	}

	return MSIInstalled;
}