Modified Easy Installer






3.77/5 (8 votes)
Aug 10, 2005
1 min read

38990
Abu Mami's Easy Installer modified , to create a setup.exe style installer for installations from CD.
Introduction
I modified Abu Mami's Easy Installer, to create a setup.exe style installer for installations from CD. Following are my notes, and the code for the replacement module for "Unwrap.cpp".
Using the code
The data for a particular installer is simply compiled in; to create setup, just adjust it and compile. No other modules of the Installer need changing, although I made some other changes, for example reading a single machine license key in AgreementPage; and changing the MessageBox
in CInstallPage::OnWizardFinish()
as follows:
str = "Installation of " + unwrap.GetPrjName() + " has been successfully completed." + "\nClick Yes to view readme file, No to exit."; if (AfxMessageBox(str,MB_ICONEXCLAMATION|MB_YESNO)==IDYES) WinExec("notepad readme", SW_SHOW);
unzip
is no longer needed; it is replaced by a recursive copy subroutine in unwrap
. I also added some code for setting environment variables in the registry, which works for NT or XP.
I used VC 6.0, without any problem. Like Abu I've used the MFC static library. I had to make one change in CreateInstaller\wrap.cpp when I was testing it. CStringArray::GetCount()
does not exist, so use GetSize()
instead.
We only had the free version of InstallShield, so we couldn't add on our own C programs, which we needed to do. I was going to write a setup from scratch, but thought to look on the Web first, and found Abu's program. It took three days to finish the job. The .NET professional edition of InstallShield costs over $1000. I like this method a lot better.
I wonder whether eventually it wouldn't be better to get rid of NewWizDialog, the main reason being that the pages all have to be the same size.
----- replacement module for Unwrap // Based on ExeExtractor written // by Kaushal Malhotra (malhotrakaushal@mantraonline.com) // Copyright (c) 2001 // Revised by Martin Dowd for "CD version" (straight copy), 2005 // Various data is "hard-coded"; simply revise it and compile to // produce the Installer executable (e.g. "setup.exe"). // Hard-coded data is preceded by a comment containing "DATA". #include "stdafx.h" #include ".\unwrap.h" #include "ShellUtils.h" #include "unzip.h" #include "resource.h" #include "kill.h" CUnwrap unwrap; CUnwrap::CUnwrap(void) { } CUnwrap::~CUnwrap(void) { } BOOL CUnwrap::Init() { // DATA, project name m_prjName = "MCAD_AFEMS"; // DATA, executable name m_prjExeName = ""; // DATA, web site caption m_webCaption = ""; // DATA, web site URL m_webURL = ""; // DATA, agreement; don't use newlines m_agreement = "This product needs a machine-dependent key. " "You must obtain this from FEM Engineering, " "based on your machine ID. Your machine ID " "is shown below. Obtain your key, type it " "below, accept the license agreement, and continue."; // DATA, info m_info = ""; // DATA, allowed Windows versions // b0-7: 95, 98, ME, NT35, NT4, 2K, XP m_winVer = 0xa0; return TRUE; } void CUnwrap::Close() { } void CUnwrap::SetPath(CString path) { m_path = path; } void CUnwrap::SetShortcut(BOOL shortcut) { m_shortcut = shortcut; } void CUnwrap::SetStartup(BOOL startup) { m_startup = startup; } void CUnwrap::SetStartMenu(BOOL startmenu) { m_startmenu = startmenu; } DWORD CUnwrap::GetWinVer() { return m_winVer; } CString CUnwrap::GetPrjName() { return m_prjName; } CString CUnwrap::GetPrjExeName() { return m_prjExeName; } CString CUnwrap::GetWebCaption() { return m_webCaption; } CString CUnwrap::GetWebURL() { return m_webURL; } CString CUnwrap::GetAgreement() { return m_agreement; } CString CUnwrap::GetInfo() { return m_info; } // recursive copy subroutine // returns FALSE if doesn't complete. // pathname length required to be < MAX_PATH // paths have terminating \'s; input dstpth assumed to exist // uses TCHAR, etc for UNICODE (the SDK functions all do) // there's no Windows generic memcpy, so define one. #ifdef _UNICODE #define _tcmcpy wmemcpy #else #define _tcmcpy memcpy #endif const char *errm[]={ "MAX_PATH exceeded; aborting file copy", "Missing input file; aborting file copy", "CopyFile failed; aborting file copy", "CreateDirectory failed; aborting file copy", "FindFirstFile failed; aborting file copy", "Couldn't open registry; values not set", }; #define ERRX(N) {AfxMessageBox(errm[N], MB_ICONEXCLAMATION|MB_OK); return FALSE;} static TCHAR srcpth[MAX_PATH+1]; /*extra for wildcard*/ static TCHAR dstpth[MAX_PATH]; static unsigned short srcpl,dstpl; static WIN32_FIND_DATA fnd_d; static int cpy_rec(const TCHAR *nm) {unsigned short psl,pdl; HANDLE fnd_h; psl=srcpl; pdl=dstpl; // update src, dst { unsigned short l; l=_tcslen(nm); if (srcpl+l>=MAX_PATH || dstpl+l>=MAX_PATH) ERRX(0) _tcmcpy(srcpth+srcpl,nm,l); srcpl+=l; srcpth[srcpl]=0; _tcmcpy(dstpth+dstpl,nm,l); dstpl+=l; dstpth[dstpl]=0; } // check if file; copy if so {unsigned attr; if ((attr=GetFileAttributes(srcpth))==0xffffffff) ERRX(1) else if (!(attr&FILE_ATTRIBUTE_DIRECTORY)) {if (CopyFile(srcpth,dstpth,FALSE)) goto xit; else ERRX(2) }} // create dst path if (CreateDirectory(dstpth,NULL)==0) {if (GetLastError()!=ERROR_ALREADY_EXISTS) ERRX(3)} //call recursively for contents srcpth[srcpl++]=_T('\\'); dstpth[dstpl++]=_T('\\'); srcpth[srcpl]=_T('*'); srcpth[srcpl+1]=0; if ((fnd_h=FindFirstFile(srcpth,&fnd_d))== INVALID_HANDLE_VALUE) ERRX(4) while (1) {if (fnd_d.cFileName[0]!='.') //skip . and .. {if (!cpy_rec(fnd_d.cFileName)) return FALSE;} if (!FindNextFile(fnd_h,&fnd_d)) break; } FindClose(fnd_h); xit: srcpl=psl; dstpl=pdl; return TRUE; } // OK flag; should be added to class, or files should return value unsigned short unwrok = 0; // registry key for system environment variables const TCHAR sys_env_key[]= _T("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment"); // Subroutine to convert TCHAR length to byte length // doesn't handle MCBS int _tclb(int l) { #ifdef UNICODE l<<=1; #endif return l; } void CUnwrap::Files() { // DATA, files / directories to copy #define N_CPY_NMS 3 const TCHAR *cpy_nms[N_CPY_NMS]={"readme.txt","bin","doc"}; // recursively copy items in list m_nFiles = N_CPY_NMS; if (GetCurrentDirectory(MAX_PATH,srcpth)==0) {AfxMessageBox ("GetCurrentDirectory failed; aborting file copy", MB_ICONEXCLAMATION | MB_OK); return; } srcpl=_tcslen(srcpth); if (srcpth[srcpl-1]!=_T('\\')) srcpth[srcpl++]=_T('\\'); _tcscpy(dstpth,(LPCTSTR)m_path); dstpl=_tcslen(dstpth); for(int idx = 0; idx < (int)m_nFiles; idx++) if (!cpy_rec(cpy_nms[idx])) return; // DATA, shortcuts, etc. // full path to executable #define N_SHORTCUTS 0 const TCHAR *shortcuts[1]={""}; #define N_STARTUPS 0 const TCHAR *startups[1]={""}; #define N_MENUITMS 0 const TCHAR *menuitms[1]={""}; //create shortcuts, etc. LPCSTR path; TCHAR dir[MAX_PATH]; TCHAR drive[MAX_PATH]; TCHAR file[MAX_PATH]; TCHAR ext[MAX_PATH]; CString menuDir; // CreateShortcut arguments: // 1: full path of executable // 2: link file name // 3: working directory // 4: description CoInitialize(NULL); if (m_shortcut) for (idx=0; idx<N_SHORTCUTS; idx++) { path=shortcuts[idx]; _tsplitpath(path, drive, dir, file, ext); CShellUtils::CreateShortcut(path,file,dir,file,CSIDL_DESKTOP);} if (m_startup) for (idx=0; idx<N_STARTUPS; idx++) { path=startups[idx]; _tsplitpath(path, drive, dir, file, ext); CShellUtils::CreateShortcut(path,file,dir,file,CSIDL_STARTUP);} if (m_startmenu) for (idx=0; idx<N_STARTUPS; idx++) { path=menuitms[idx]; _tsplitpath(path, drive, dir, file, ext); menuDir.Format("%s\\%s", m_prjName, file); CShellUtils::CreateShortcut(path,menuDir,dir,file,CSIDL_PROGRAMS);} CoUninitialize(); // DATA, dlls to register // The extension (e.g. ".dll") must be present in the name in the list. #define N_DLL_FILES 0 const TCHAR *dll_files[1]={""}; // register DLLs for (idx = 0; idx < N_DLL_FILES; idx++) Register(dll_files[idx]); // DATA, flag for setting environment variables // 1 for system, 2 for user #define SETENV 1 #if SETENV // set environment variables HKEY key; #if SETENV==1 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,sys_env_key,0,KEY_WRITE,&key) #elif SETENV==2 if (RegOpenKeyEx(HKEY_CURRENT_USER,_T("Environment"),0,KEY_WRITE,&key) #endif != ERROR_SUCCESS) {AfxMessageBox(errm[5],MB_ICONEXCLAMATION|MB_OK); return;} // destination path dstpth[dstpl]=0; //see above; gets text added RegSetValueEx(key,_T("FEM"),0,REG_SZ, (unsigned char *)dstpth,_tclb(dstpl+1)); // single machine licence key extern CString af_id_txt; RegSetValueEx(key,_T("AFEMS_KEY"),0,REG_SZ, (unsigned char *)(LPCTSTR)af_id_txt, _tclb(af_id_txt.GetLength()+1)); RegCloseKey(key); #endif // set success flag unwrok=1; } BOOL CUnwrap::CheckExecutables() { // DATA, Executables to check if active // The extension (e.g. ".exe") must be present in the name in the list. #define N_EXE_FILES 0 const char *exe_files[1]={""}; for (int idx = 0; idx < N_EXE_FILES; idx++) { DWORD dwId; HANDLE hProcess = kill.FindProcess(exe_files[idx], dwId); if(hProcess) return TRUE; } return FALSE; } void CUnwrap::Register(CString dll) { BOOL rc = FALSE; HMODULE hm = LoadLibrary(dll); if(hm) { rc = GetProcAddress(hm, TEXT("DllRegisterServer") ) != NULL; FreeLibrary(hm); } if(!rc) return; CString str; str.Format("Regsvr32.exe /s \"" + dll + "\""); WinExec(str, SW_SHOW); }