|
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;
}
|