Jesper A
March 25th, 2003, 02:45 PM
Is there anyone who knows which mfc70.dll files I need
to redistribute with my program? ( I donīt want to link
statically ) And is it safe to overwrite clients mfc70.dll if
the case is that is allready installed on their computer?
Regards
Jesper
Andreas Masur
March 25th, 2003, 05:24 PM
The following might be more than you are asking for...but it might be helpful...
You can link the MFC dll statically as suggested but I do not like this thing very much since it blows up your application file etc. Usually I suggest building a custom-based installation file (you can use InstallShield for example) which installs your application and all necessary dll's on the target system even with version checking...
Updating system dll's is always a tricky thing to do. But nevertheless sometimes your software requires changing some of the system dll's.
In this context it is important to install a newer version of a file and not an older one. For example, you will want to install a newer version of a system DLL on top of an older version, but not an older version on top of a newer version. Typically, version checking is the responsibility of the setup program. If you write your own custom setup program, you must manually check the version when installing redistributable files.
First of all you need to find out which dll's needs to be redistributed to make sure that your application will run independent of the installed dll's on the target system. For an overview of the dependicies of your application you have two possibilities:
1. Use the 'Dependency Walker' (depends.exe)
2. Use 'Dumpbin' (dumpbin.exe) with the parameter /DEPENDENTS
Both methods will show you a list of dll's that are linked to your application - either statically or dynamically. To find out which dll's are dynamically loaded you need to use the profiling feature of the 'Dependeny Walker'.
Be always aware that a dll might have dependicies to other dll's or even a version of a specific dll. If you have installed your application on a target system and it won't run you can again use the 'Dependency Walker'. Run it on the target machine and it will report which dll's are either missing or present with an incorrect version. Dll's should always overwrite the existing dll's to avoid multiple instances of the dll on the system.
If your application needs MFC support and you don't want to link it statically to your application (which I normally not recommend) you need to distribute it as well. MFC dll's are shared components therefore they will be placed within the system directory. You can get the system directory by a call to the API function
UINT GetSystemDirectory(LPTSTR lpBuffer, UINT uSize)
Again, installations within the system directory needs to be done carefully. NEVER overwrite a newer dll since other applications may rely on the specific version. To check the version of a dll Windows provides several API functions (Version API).
Your setup application needs to place needed files in the correct locations and prompt the user if the setup application notice some significantly difference like different language version or you try to overwrite a newer file with the older one. Therefore you will need some information on those files like name and location of the source and destination file and much more important the sharing status of the file (only used by one application or shared between multiple applications).
Regarding the location and the sharing status you can use the function
DWORD VerFindFile(DWORD dwFlags,
LPTSTR szFileName,
LPTSTR szWinDir,
LPTSTR szAppDir,
LPTSTR szCurDir,
PUINT lpuCurDirLen,
LPTSTR szDestDir,
PUINT lpuDestDirLen)
This function will return several error codes whether the file is currently used by the system etc. Depending on the error code your setup program must react in a proper way.
To install the source file you should use the function
DWORD VerInstallFile(DWORD uFlags,
LPTSTR szSrcFileName,
LPTSTR szDestFileName,
LPTSTR szSrcDir,
LPTSTR szDestDir,
LPTSTR szCurDir,
LPTSTR szTmpFile,
PUINT lpuTmpFileLen)
since it will do some work for you. It copies the source file to a temporary file within the destination directory - if necessary it will expand a compressed file. After that an automatic comparison of the version information of the temporary and the destination file will be done. Again, your setup program should react to the returned error codes in a proper way. This function can be called multiple times with different flags. For example, if the first call returned an error indicating a version conflict you can force the installation disregarding the conflict by calling this function again with the 'VIFF_FORCEINSTALL' flag. On the other side your setup program needs to take care of the created temporary file by deleting them properly.
To retrieve the version information your setup program can use the following functions...
DWORD GetFileVersionInfoSize(LPTSTR lptstrFilename, LPDWORD lpdwHandle)
BOOL GetFileVersionInfo(LPTSTR lptstrFilename,
DWORD dwHandle,
DWORD dwLen,
LPVOID lpData)
BOOL VerQueryValue(const LPVOID pBlock,
LPTSTR lpSubBlock,
LPVOID *lplpBuffer,
PUINT puLen)
DWORD VerLanguageName(DWORD wLang, LPTSTR szLang, DWORD nSize)
'GetFileVersionInfoSize()' returns the size of the version information. 'GetFileVersionInfo()' uses information retrieved by 'GetFileVersionInfoSize()' to retrieve a structure that contains the version information. 'VerQueryValue()' retrieves a specific member from that structure. Your setup program needs to call those function depending on the error code returned by e.g. 'VerInstallFile()'.
The following is an example to get the product version...
#include <string>
#include <sstream>
#include <iomanip>
#include <iostream>
#include <malloc.h>
#include <memory.h>
#include <windows.h>
struct Language
{
WORD m_wLanguage;
WORD m_wCodePage;
};
int main()
{
Language *pLanguageInfo = NULL;
LPVOID pvResourceData = NULL;
// Allocate language structure
pLanguageInfo = new Language;
if(pLanguageInfo)
{
// Clear structure
memset(pLanguageInfo, 0, sizeof(Language));
// Get version info
DWORD dwHandle = 0;
DWORD dwResourceSize = ::GetFileVersionInfoSize("Name of application", &dwHandle);
if(dwResourceSize)
{
pvResourceData = malloc(dwResourceSize);
if(pvResourceData)
if(::GetFileVersionInfo("Name of application", 0, dwResourceSize, pvResourceData) != FALSE)
{
UINT uiSize = 0;
// Get language information
if(::VerQueryValue(pvResourceData,
"\\VarFileInfo\\Translation",
reinterpret_cast<LPVOID *>(&pLanguageInfo),
&uiSize) == FALSE)
return -1;
}
}
}
// Get specific info
UINT uiSize = 0;
std::stringstream strsQueryString;
LPVOID pvValue = NULL;
// Build query string
strsTemp << "\\StringFileInfo\\" << std::setw(4) << std::setfill('0') << std::hex
<< pLanguageInfo->m_wLanguage << std::setw(4) << pLanguageInfo->m_wCodePage
<< "\\ProductVersion";
if(::VerQueryValue(pvResourceData,
const_cast<LPTSTR>(strsTemp.str().c_str()),
static_cast<LPVOID *>(&pvValue),
&uiSize) != FALSE)
{
// Convert product version
std::string strProductVersion = static_cast<LPTSTR>(pvValue);
std::string::size_type pos = 0;
while((pos = strProductVersion.find(",", pos)) < std::string::npos)
{
strProductVersion.replace(pos, 1, ".");
++pos;
}
std::cout << strProductVersion;
}
return 0;
}
This of course is only a 'crash-course' in version management. But I hope it gives you at least a basic understanding how you can proceed with your setup application...
Jesper A
March 26th, 2003, 02:31 PM
What a reply!!! This solves all I was thinking of and
more than that. If this wasnīt an article I suggest
you put it up as one...
Thanks alot Andreas.
Regards
Jesper
sarambur
April 9th, 2003, 10:38 AM
that was good, but, does microsoft have any installation program to install mfc libraries?
I dont want to make my own setup utility if microsoft has its own, you know.
So, can anyone post any link to thar MFC installer?
Jesper A
April 9th, 2003, 03:23 PM
In VC++.net you can make a setup project. Choose
"Setup and deployment" in the new projekt wizard.
Itīs easier to deal with then Install shield and seems to
do the most that needs to be done.