The official release notes in service pack 3 do not mention fixes to all of the bugs listed here. Briefly scanning the code seems to confirm this. However, there are many changes to the P&DW code and I have not confirmed which of the bugs are fixed, which not by service pack 3.
You can try service pack 3 ( http://msdn.microsoft.com/vstudio/sp/default.asp) first, to see if this resolves your problems. I've noticed sp3 cleans up the P&DW code by reducing goto statements and handling types more precisely. However, it introduces some serious bugs. As time permits, I'll update this page with sp3 changes. Check what's new for updates.
If you already made changes to your setup1.vbp before upgrading to service pack 3, you may need to be careful restoring the setup1 project to its original state. The sp3 install warns if non-version files are newer, they may not get overwritten with the new ones.
Items listed as (SP3) are bugs introduce in SP3, (SP2) are bugs that are fixed in SP3, (SP2 & SP3) are bugs both in SP2 and SP3, and those without any indicator means I have not verified it is fixed in SP3.
Also see Every file installed is logged as new below.
AddDirSep mstrConcatDriveafter:
If mstrConcatDrive <> vbNullString ThenIf bootstrap files are loaded after a reboot, they will fail if the temp folder is on a different disk drive than the system folder. Either move temp file to same drive or move files in winint.ini file before rebooting.
Not mentioned in Microsoft's knowledge base, there are two additional problems that can cause install to continually attempt to update bootstrap files after reboot.
If someone has a command in their autoexec.bat file that deletes files from the temp directory, the bootstrap files never get copied after reboot.
Another case I have seen can be fixed by deleting left over files as described in Disk n not found below. I don't know why and may never since we don't get to see the source code.
Unfortunately, since the bootstrap code is in the setup.exe which Microsoft does not give us the source, there is no clean workaround.
(File was not found or was an older version -- new file copied)
when this is not always true.
For one, the AddActionNote after the:
Case intFILEUPTODATEshould read:
AddActionNote ResolveResString(resLOG_FILEUPTODATE)instead of:
AddActionNote ResolveResString(resLOG_FILECOPIED)Additionally, change the IsNewerVer function in setup1.bas from:
(.FileVerPart4 = sDestVer.FileVerPart4) Then GoTo INVNewer
to:
(.FileVerPart4 = sDestVer.FileVerPart4) Then IsNewerVer = 2
Then in the CopySection function, instead of checking
if IsNewerVer(sSrcVerInfo, sDestVerInfo) = False thencheck for False or 2 and only execute the code up to:
If Not fOverWrite Then
only if False.
To fix, reverse fcNewer and fcOlder in the SourceFileIsNewer function in setup1.bas as follows:
If sFile.varDate < datDest Then
SourceFileIsNewer = fcNewer
ElseIf sFile.varDate = datDest Then
SourceFileIsNewer = fcEquivalent
Else
SourceFileIsNewer = fcOlder
End If
with
If sFile.varDate < datDest Then
SourceFileIsNewer = fcOlder
ElseIf sFile.varDate = datDest Then
SourceFileIsNewer = fcEquivalent
Else
SourceFileIsNewer = fcNewer
End If
Thanks John Reynaert
If sFile.varDate <= FileDateTime(strDestDir & strDestName) Then
Before a file that has no version overwrites an existing file with the same name,
the setup displays a useless message that lists the description and version number
that by definition are blank. It should, instead list file date and size of new and
old file so the user can make an educated decision.
To add to the confusion is the use of a negative "not newer" instead of "older".
frm.show vbModal, frmSetup1insert:
frmCopy.ZOrder
When installing over a newer version, the warning states "Your version: x.x.xxx.xx" which
is unclear to the user. It turns out "your" means the new file which is contrary to what
most people think when installing. It is more confusing when it asks "Do you want to keep
this file?" It should phrase it as "New version:" and "Do you want to keep the existing
file?". In addition, it does not list the version number of
the existing file for a better educated decision. Also, it should have a cancel
button to allow you to exit the install.
Change lines 1001, 1004, and 1005 in Setup1.res resource file.
Microsoft's position is that operating system files should not be updated by your installation routine. However, the tools Microsoft supplies to developers do not identify what files are operating system files. And the P&DW is placing these files in the installation in the first place. In addition, how is a developer to know if the newer file is needed to fix a bug? And finally, Microsoft does the same thing with their applications, so how can they expect us not follow suit? An install routine that access violates is unacceptable!
The real fix is to make an entry in the wininit.ini file (win9x) or use MOVEFILE_DELAY_UNTIL_REBOOT (NT) as follows (SP2 only!):
In Setup1.bas add the following to the declarations section:
Global gReBoot As Boolean Declare Function GetPrivateProfileSection Lib "kernel32" Alias "GetPrivateProfileSectionA" (ByVal lpAppName As String, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFilename As String) As Long Declare Function WritePrivateProfileSection Lib "kernel32" Alias "WritePrivateProfileSectionA" (ByVal lpAppName As String, ByVal lpString As String, ByVal lpFilename As String) As Long Declare Function MoveFileEx Lib "Kernel32" Alias "MoveFileExA" (ByVal OldFilename As String, ByVal NewFileName As String, ByVal nWord As Long) As LongIn ExitSetup procedure add the reboot flag:
If GetKeyValue(HK_LOCAL_MACHINE, sKEY, sValue, sRet) Or gReBoot Then
Replace the CopyFile function with the following:
Function CopyFile(ByVal strSrcDir As String, ByVal strDestDir As String, ByVal strSrcName As String, ByVal strDestName As String, ByVal fShared As Boolean, ByVal fSystem As Boolean, Optional ByVal fOverWrite As Boolean = False) As Boolean
Const intUNKNOWN% = 0
Const intCOPIED% = 1
Const intNOCOPY% = 2
Const intFILEUPTODATE% = 3
Const intDELAYED = 4
Const MOVEFILE_DELAY_UNTIL_REBOOT = &H4
Const MOVEFILE_REPLACE_EXISTING = &H1
Const MOVEFILE_DELAY_AND_REPLACE = MOVEFILE_DELAY_UNTIL_REBOOT + MOVEFILE_REPLACE_EXISTING
'
'VerInstallFile() Flags
'
Const VIFF_FORCEINSTALL% = &H1
Const VIF_TEMPFILE& = &H1
Const VIF_SRCOLD& = &H4
Const VIF_DIFFLANG& = &H8
Const VIF_DIFFCODEPG& = &H10
Const VIF_DIFFTYPE& = &H20
Const VIF_WRITEPROT& = &H40
Const VIF_FILEINUSE& = &H80
Const VIF_OUTOFSPACE& = &H100
Const VIF_ACCESSVIOLATION& = &H200
Const VIF_SHARINGVIOLATION = &H400
Const VIF_CANNOTCREATE = &H800
Const VIF_CANNOTDELETE = &H1000
Const VIF_CANNOTRENAME = &H2000
Const VIF_OUTOFMEMORY = &H8000&
Const VIF_CANNOTREADSRC = &H10000
Const VIF_CANNOTREADDST = &H20000
Const VIF_BUFFTOOSMALL = &H40000
Static fIgnoreWarn As Integer 'user warned about ignoring error?
Dim strMsg As String
Dim lRC As Long
Dim lpTmpNameLen As Long
Dim intFlags As Integer
Dim intRESULT As Integer
Dim fFileAlreadyExisted
On Error Resume Next
CopyFile = False
'
'Ensure that the source file is available for copying
'
If DetectFile(strSrcDir & strSrcName) = vbIgnore Then
AbortAction
Exit Function
End If
'
' Make sure that the Destination path (including path, filename, commandline args, etc.
' is not longer than the max allowed.
'
If Not fCheckFNLength(strDestDir & strDestName) Then
AbortAction
strMsg = ResolveResString(resCANTCOPYPATHTOOLONG) & vbLf & vbLf & ResolveResString(resCHOOSENEWDEST) & vbLf & vbLf & strDestDir & strDestName
Call MsgError(strMsg, vbOKOnly, gstrSETMSG)
ExitSetup frmCopy, gintRET_FATAL
Exit Function
End If
'
'Make the destination directory, prompt the user to retry if there is an error
'
If Not MakePath(strDestDir) Then
AbortAction ' Abort file copy
Exit Function
End If
'
'Make sure we have the LFN (long filename) of the destination directory
'
strDestDir = GetLongPathName(strDestDir)
'
'Setup for VerInstallFile call
'
lpTmpNameLen = gintMAX_SIZE
mstrVerTmpName = String$(lpTmpNameLen, 0)
intFlags = 0
If fOverWrite Then intFlags = VIFF_FORCEINSTALL
fFileAlreadyExisted = FileExists(strDestDir & strDestName)
intRESULT = intUNKNOWN
Do While intRESULT = intUNKNOWN
'VerInstallFile under Windows 95 does not handle
' long filenames, so we must give it the short versions
' (32-bit only).
Dim strShortSrcName As String
Dim strShortDestName As String
Dim strShortSrcDir As String
Dim strShortDestDir As String
strShortSrcName = strSrcName
strShortSrcDir = strSrcDir
strShortDestName = strDestName
strShortDestDir = strDestDir
If Not FileExists(strDestDir & strDestName) Then
'If the destination file does not already
' exist, we create a dummy with the correct
' (long) filename so that we can get its
' short filename for VerInstallFile.
Open strDestDir & strDestName For Output Access Write As #1
Close #1
End If
On Error GoTo UnexpectedErr
If Not IsWindowsNT() Then
Dim strTemp As String
'This conversion is not necessary under Windows NT
strShortSrcDir = GetShortPathName(strSrcDir)
If GetFileName(strSrcName) = strSrcName Then
strShortSrcName = GetFileName(GetShortPathName(strSrcDir & strSrcName))
Else
strTemp = GetShortPathName(strSrcDir & strSrcName)
strShortSrcName = Mid$(strTemp, Len(strShortSrcDir) + 1)
End If
strShortDestDir = GetShortPathName(strDestDir)
strShortDestName = GetFileName(GetShortPathName(strDestDir & strDestName))
End If
On Error Resume Next
lRC = VerInstallFile(intFlags, strShortSrcName, strShortDestName, strShortSrcDir, strShortDestDir, 0&, mstrVerTmpName, lpTmpNameLen)
If Err <> 0 Then
'
'If the version or file expansion DLLs couldn't be found, then abort setup
'
ExitSetup frmCopy, gintRET_FATAL
End If
If lRC = 0 Then
'
'File was successfully installed, increment reference count if needed
'
'One more kludge for long filenames: VerInstallFile may have renamed
'the file to its short version if it went through with the copy.
'Therefore we simply rename it back to what it should be.
Name strDestDir & strShortDestName As strDestDir & strDestName
intRESULT = intCOPIED
ElseIf lRC And VIF_SRCOLD Then
'
'Source file was older, so not copied, the existing version of the file
'will be used. Increment reference count if needed
'
intRESULT = intFILEUPTODATE
ElseIf lRC And (VIF_DIFFLANG Or VIF_DIFFCODEPG Or VIF_DIFFTYPE) Then
'
'We retry and force installation for these cases. You can modify the code
'here to prompt the user about what to do.
'
intFlags = VIFF_FORCEINSTALL
ElseIf lRC And VIF_WRITEPROT Then
strMsg = ResolveResString(resWRITEPROT)
GoSub CFMsg
ElseIf lRC And VIF_FILEINUSE Then
strMsg = ResolveResString(resINUSE)
GoSub MvFileDelay
ElseIf lRC And VIF_OUTOFSPACE Then
strMsg = ResolveResString(resOUTOFSPACE) & Left$(strDestDir, 2)
GoSub CFMsg
ElseIf lRC And VIF_ACCESSVIOLATION Then
strMsg = ResolveResString(resACCESSVIOLATION)
GoSub MvFileDelay
ElseIf lRC And VIF_SHARINGVIOLATION Then
strMsg = ResolveResString(resSHARINGVIOLATION)
GoSub MvFileDelay
ElseIf lRC And VIF_OUTOFMEMORY Then
strMsg = ResolveResString(resOUTOFMEMORY)
GoSub CFMsg
Else
'
' For these cases, we generically report the error and do not install the file
' unless this is an SMS install; in which case we abort.
'
If lRC And VIF_CANNOTCREATE Then
strMsg = ResolveResString(resCANNOTCREATE)
ElseIf lRC And VIF_CANNOTDELETE Then
strMsg = ResolveResString(resCANNOTDELETE)
ElseIf lRC And VIF_CANNOTRENAME Then
strMsg = ResolveResString(resCANNOTRENAME)
ElseIf lRC And VIF_CANNOTREADSRC Then
strMsg = ResolveResString(resCANNOTREADSRC)
ElseIf lRC And VIF_CANNOTREADDST Then
strMsg = ResolveResString(resCANNOTREADDST)
ElseIf lRC And VIF_BUFFTOOSMALL Then
strMsg = ResolveResString(resBUFFTOOSMALL)
End If
strMsg = strMsg & ResolveResString(resNOINSTALL)
MsgError strMsg, vbOKOnly Or vbExclamation, gstrTitle
If gfSMS Then
ExitSetup frmSetup1, gintRET_FATAL
End If
intRESULT = intNOCOPY
End If
Loop
'
'If there was a temp file left over from VerInstallFile, remove it
'
If lRC And VIF_TEMPFILE Then
Kill mstrVerTmpName
End If
'Abort or commit the current Action, and do reference counting
Select Case intRESULT
Case intNOCOPY
AbortAction
Case intCOPIED
DecideIncrementRefCount strDestDir & strDestName, fShared, fSystem, fFileAlreadyExisted
If (Extension(strDestName) = gsEXT_FONTFON) Or (Extension(strDestName) = gsEXT_FONTTTF) Then
'do nothing
Else
AddActionNote ResolveResString(resLOG_FILECOPIED)
CommitAction
End If
CopyFile = True
Case intDELAYED
DecideIncrementRefCount strDestDir & strDestName, fShared, fSystem, fFileAlreadyExisted
If (Extension(strDestName) = gsEXT_FONTFON) Or (Extension(strDestName) = gsEXT_FONTTTF) Then
'do nothing
Else
AddActionNote "File installation delayed after reboot."
CommitAction
End If
CopyFile = True
Case intFILEUPTODATE
DecideIncrementRefCount strDestDir & strDestName, fShared, fSystem, fFileAlreadyExisted
If (Extension(strDestName) = gsEXT_FONTFON) Or (Extension(strDestName) = gsEXT_FONTTTF) Then
'do nothing
Else
'AddActionNote ResolveResString(resLOG_FILECOPIED)
AddActionNote ResolveResString(resLOG_FILEUPTODATE)
CommitAction
End If
CopyFile = True
Case Else
AbortAction ' Defensive - this shouldn't be reached
'End Case
End Select
Exit Function
UnexpectedErr:
MsgError error$ & vbLf & vbLf & ResolveResString(resUNEXPECTED), vbOKOnly Or vbExclamation, gstrTitle
ExitSetup frmCopy, gintRET_FATAL
MvFileDelay:
Dim strProfileSection As String
Dim lngLength As Long
Dim lngSize As Long
Dim strFile As String
Static lngUnique As Long
If lngUnique = 0 Then
lngUnique = Format$(Now(), "ddhhnnss")
Else
lngUnique = lngUnique + 1
End If
strFile = Format$(lngUnique, "00000000") & ".tmp"
intFlags = 0
On Error GoTo 0
On Error Resume Next
lRC = VerInstallFile(intFlags, strShortSrcName, strFile, strShortSrcDir, strShortDestDir, 0&, mstrVerTmpName, lpTmpNameLen)
If Err = 0 And lRC = 0 Then
If IsWindowsNT() Then
If MoveFileEx(strDestDir & strFile, strDestDir & strDestName, MOVEFILE_DELAY_AND_REPLACE) <> 0 Then
intRESULT = intDELAYED
gReBoot = True
Else
GoSub CFMsg
End If
Else
strProfileSection = String$(32767, 0)
lngLength = GetPrivateProfileSection("Rename" & vbNullChar, strProfileSection, 32767, "WinInit.ini" & vbNullChar)
If lngLength <> 32765 Then
If WritePrivateProfileSection("Rename" & vbNullChar, _
Left(strProfileSection, lngLength) & strShortDestDir & strDestName & "=" & strShortDestDir & strFile & vbNullChar, _
"WinInit.ini" & vbNullChar) = 0 Then
GoSub CFMsg
Else
intRESULT = intDELAYED
gReBoot = True
End If
Else
GoSub CFMsg
End If
End If
Else
GoSub CFMsg
End If
Return
CFMsg: '(Subroutine)
Dim intMsgRet As Integer
strMsg = strDestDir & strDestName & vbLf & vbLf & strMsg
intMsgRet = MsgError(strMsg, vbAbortRetryIgnore Or vbExclamation Or vbDefaultButton2, gstrTitle)
If gfNoUserInput Then intMsgRet = vbAbort
Select Case intMsgRet
Case vbAbort
ExitSetup frmCopy, gintRET_ABORT
Case vbIgnore
If fIgnoreWarn = True Then
intRESULT = intNOCOPY
Else
fIgnoreWarn = True
strMsg = strMsg & vbLf & vbLf & ResolveResString(resWARNIGNORE)
If MsgError(strMsg, vbYesNo Or vbQuestion Or vbDefaultButton2, gstrTitle) = vbYes Then
intRESULT = intNOCOPY
Else
'Will retry
End If
End If
'End Case
End Select
Return
End Function
Dim StartDate As Date
StartDate = Now
Before service pack 3:
Dim sFileDate As Date
sFileDate = FileDateTime(sFile.strDestDir & sFile.strDestName)
If DateDiff("s", StartDate, sFileDate) > 0 Then
Service pack 3:
sFileDate = Format$(FileDateTime(sFile.strDestDir & sFile.strDestName), "m/d/yyyy h:m")
sCurDate = Format$(Now, "m/d/yyyy h:m")
If sFileDate = sCurDate Then
with these:
Dim sFileDate2 As Date
sFileDate2 = FileDateTime(sFile.strDestDir & sFile.strDestName)
If DateDiff("s", StartDate, sFileDate2) > 0 Then
\WINDOWS\SYSTEM\VB6STKIT.DLL \WINDOWS\SYSTEM\MSVBVM60.DLL \WINDOWS\ST6UNST.EXE \WINDOWS\SETUP.EXE \WINDOWS\SETUP.LST \WINDOWS\SETUP1.EXE \WINDOWS\*.CABRemove the following files *ONLY* if they are zero bytes in length:
\WINDOWS\SYSTEM\SCRRUN.DLL (might not be found on all machines) \WINDOWS\SYSTEM\OLEAUT32.DLLThe major cause for this error is that the cab files are not always removed after an aborted installation. This is because the code assumes the cabs are extracted in numerical order which in most cases is not true.
To prevent the major cause add:
Form_Unload 0
KillTempFolder
before the following line in frmSetup1:
CopySection gstrINI_FILES
Then change the frmSetup1 unload event as follows (and same code in basSetup1.MoveAppRemovalFiles):
Public Sub Form_Unload(Cancel As Integer)
'Get rid of the cab file in the windows dir (if it exists).
Dim lCount As Long
Dim sCab As String
Dim sTemp As String
'Get rid of the cab file in the windows dir (if it exists).
If gintCabs = 1 Then
sCab = gstrWinDir
AddDirSep sCab
sCab = sCab & BaseName(GetShortPathName(gsCABNAME))
If FileExists(sCab) Then
SetAttr sCab, vbNormal
Kill sCab
endif
Else
For lCount = 1 To gintCabs
sCab = gstrWinDir
AddDirSep sCab
sTemp = Left(gsCABNAME, Len(gsCABNAME) - 5) & CStr(lCount) & gstrSEP_EXT & gsINI_CABNAME
sCab = sCab & BaseName(sTemp)
If FileExists(sCab) Then
SetAttr sCab, vbNormal
Kill sCab
End If
Next lCount
End If
End Sub
Then in basSetup1, change KillTempFolder from Private to Public.
As a workaround, remove the shared designation in the setup.lst file.
Rule of thumb is not to believe anything the P&D Wizard tells you; double check it!
SP3 partially resolves this by also indicating the other files that have changed.
SP2 had a bug where it included only one entry in Add/Remove wizard if the application name had a lower case letter in it. As a result, uninstall would not decrement multiple shares, not all files would be removed and/or missing file errors were displayed.
SP3 creates multilple uninstall entries which when removed at least decrement share counts. However, users may be confused and accidently remove the application. Also, missing file errors were displayed, though at least all files are removed if the user removes each. Adding to the confusion is the names listed in the Add/Remove wizard. The second entry appends the folder, the third through n appends the folder followed by #3 to #n respectfully.
ACTION: SystemFile: "C:\WINDOWS\SYSTEM\VB6STKIT.DLL" (File currently on disk was already up to date)after
NOTE: Now spawning the main Setup program...and replace SystemFile with SharedFile
ACTION: SharedFile: "C:\WINDOWS\SYSTEM\VB6STKIT.DLL" (File currently on disk was already up to date)This could be dangerous, however, if and when Microsoft decides to fix the uninstaller. Hopefully it would be fixed with a point release (i.e. st7unst.exe) or they would change the setup1 as suggested above.
SetAttr sCab, vbNormal
is added.
I suspect it is needed for the new vbajet32.dll. How to address this issue depends on what you ship. From what I can tell, if you also ship 6.0.8268 version of vbajet32.dll, make sure expsrv.dll is listed after vbajet32.dll in the setup.lst. People tell me moving it to the end works.
If you ship the previous version of vbajet32.dll you can either remove $(DLLSelfRegister) from the setup.lst file or place the previous version of expsrv.dll in your "Program Files\Microsoft Visual Studio\VB98\Wizards\PDWizard\Redist" folder and rerun P&D Wizard.
SP3 ships 6.0.8269 which the P&DW does not attempt to register. Be careful, however, Windows 98 Second Edition reinstalls 6.0.8268.
As a workaround, do not use the setup.exe that comes with SP3.
MyRecordset.findfirst "myfield = Null"DAO 3.6 will never find nulls this way. As a workaround change the above to:
MyRecordset.findfirst "myfield is Null"
(SELECT * FROM table WHERE DateField = #10:00 AM#)As a workaround for homogeneous environments, execute the following SQL statement:
UPDATE table Set DateField = CVDate(Format(DateField, 'hh:nn:ss ampm'))Heterogeneous environments are out of luck. In other words, the above workaround only works if you are upgrading or downgrading to one or the other version. For example, dates with times created in Access 2.0 may not be found in Access 97 and visa versa.
As a workaround use the freelocks statement after errors.
MyDB.CreateQueryDef "MyQuery", "PARAMETERS [T No] Long; SELECT * FROM MyTable where MyField = [T No]"fails because it can't handle the [T No] field. As a workaround, remove the space from your database field or upgrade to Access 97.