Search code examples
excelzipwindows-shellvba

Create zip error: Namespace method fails on IShellDispatch


We have been trying to resolve this issue for almost a week now without an answer. Issue: While creating zip file, an error is thrown saying "The method Namespace failed on IShellDispatch6." What we have tried so far? Our code is based on instructions at https://www.rondebruin.nl/win/s7/win001.htm. It works on our development environments but explicitly fails on few of client's machine. Our code:

    Code (vb):
    Option Explicit
    Public zipfile As Variant ' Care taken that this must be a variant
    Private baseDirectory As Variant ' Care taken that this must be a variant
    Private FileName As String ' This needn't be a variant - tried and tested.
    Private done As Boolean

    #If VBA7 Then
      Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwmilliseconds As Long)
    #Else
      Private Declare Sub Sleep Lib "kernel32" (ByVal dwmilliseconds As Long)
    #End If

    ' Optional folderNumber taken to try create 10 zip files in a loop.
    ' Read somewhere that shell activities spawn into separate threads.
    ' A loop can expose any such vulneribility
    Public Sub zip(Optional folderNumber As Integer = 0)
    Dim oApp
    Dim dFolder
    Sleep 100
    baseDirectory = "C:\Users\Siddhant\AppData\Local\Temp\b w\"
    zipfile = "" & baseDirectory & "stestzip" & CStr(folderNumber) & ".zip"
    FileName = "" & baseDirectory & "stestzip.txt"
    'Set dFolder = CreateObject("WScript.Shell")
     Set oApp = CreateObject("Shell.Application")
    Debug.Print "Starting zip process at " & CStr(VBA.Timer) & ". First creating zip file."
    ' Note the round brackets below around zipfile - These evaluate zipfile at run-time.
    ' These are not  for parameter passing but to force evaluation.
     NewZip (zipfile)
    Debug.Print "Zip created at " & CStr(VBA.Timer)
      'On Error GoTo here
    ' On development machine, following works fine.
    ' On client machine, call to oApp.Namespace(zipfile) fails
    ' giving error message described at beginning of this post..
    Debug.Print "Critical Error----------------" & CStr(oApp.Namespace(zipfile) Is Nothing)

    Dim loopChecker As Integer
    loopChecker = 1
    ' On client machine, code doesn't even reach here.
    While oApp.Namespace(zipfile) Is Nothing
    ' Well this loop simply waits 3 seconds
    ' in case the spawned thread couldn't create zipfile in time.
    Debug.Print "Waiting till zip gets created."
      Sleep 100
    If loopChecker = 30 Then
    Debug.Print "Wated 3 seconds for zip to get created. Can't wait any longer."
    GoTo afterloop
    End If
    loopChecker = loopChecker + 1
    Wend
    afterloop:
    Debug.Print "Now Condition is ---------------" & CStr(oApp.Namespace(zipfile) Is Nothing)
    If oApp.Namespace(zipfile) Is Nothing Then
      Debug.Print "Couldnot create zip file " & zipfile
      Exit Sub
    End If
      Set dFolder = oApp.Namespace(zipfile)
      'MsgBox FileName
     Sleep 200
      dFolder.CopyHere "" & FileName, 4
      'Keep script waiting until Compressing is done
     On Error Resume Next
      Do Until dFolder.Items.Count = 1
      done = False
      'Application.Wait (Now + TimeValue("0:00:01"))
     Sleep 100  'wait for 1/10 th of second
     Loop
      done = True
      On Error GoTo 0
    here:

    If Not dFolder Is Nothing Then
      Set dFolder = Nothing
    End If

    If Not oApp Is Nothing Then
      Set oApp = Nothing
    End If

    End Sub

    Public Function Success() As Boolean
      Success = done
    End Function

    Public Sub ClearFileSpecs()
      FileName = ""
    End Sub

    Public Sub AddFileSpec(FileLocation As String)
      FileName = FileLocation
    End Sub

    Sub NewZip(sPath)
    'Create empty Zip File
     If Len(Dir(sPath)) > 0 Then Kill sPath
    Debug.Print "Creating zip file"
      Open sPath For Output As #1
    Debug.Print "Zip file created, writing zip header"
      Print #1, Chr$(80) & Chr$(75) & Chr$(5) & Chr$(6) & String(18, 0)
    Debug.Print "zip header written, closing file."
      Close #1
    Debug.Print "Closing zip file."
    End Sub


    Function Split97(sStr As Variant, sdelim As String) As Variant
      Split97 = Evaluate("{""" & _
      Application.Substitute(sStr, sdelim, """,""") & """}")
    End Function


    Sub testZipping()
    Dim i As Integer
    For i = 1 To 10
      zip i
    Next i
    MsgBox "Done"
    End Sub

    Sub tryWait()
    Dim i As Integer
    For i = 1 To 10
    Sleep 2000
    Next i
    End Sub

By the way, we have also tried another solution to call oApp.Namespace((zipfile)) forcing evaluation of zipfile variable. Many forums described another issue where literal strings worked with oApp.Namespace("c:\an\example"). In such forums solution to use 2 round brackets was suggested.

But neither keeping "DIM zipfile As Variant" worked nor "oApp.Namespace((zipfile))" work.

Could it be the case that the shell32.dll is damaged on client's machine? Please help! I would be quite thankful for any help offered!

I've also posted this issue at http://forum.chandoo.org/threads/create-zip-error-namespace-method-fails-on-ishelldispatch.34010/


Solution

  • We were finally able to get this through. When it came down to Namespace() method failing on IShellDispatch instance, OS installation had to be repaired which fixed the issue. Further, we later discovered that relying on Windows Shell based zipping isn't reliable enough as the copyhere() method doesn't return any status of completion. Additionally, it is asynchronous which mandates hacks like putting a loop after copyhere() call. This loop would sleep few milliseconds and compare source and target folders' items. This hack causes a possible conflict in actual copyhere operation and the comparison query. We have finally moved on to implementing ZLib based DLL that can help us with our compression and decompression requirements.