2
\$\begingroup\$

Windows only. So I am writing code to decompile a Windows compiled html help file (*.chm) and then tidy the files found within. Whilst, I have blogged some simple Python examples I now want to write Python code closer to production standards so I'd like a code review thanks.

I will bring forth a series of classes , each of them will have a COM interface so they can be scripted from VBA. VBA is my main programming language and interoperability is non-negotiable.

I have formatted code according to PEP8. I shortened strings etc.

The code can be run as just a script to test its workings, this is how I developed it. The code needs admin rights to register the COM class (you can comment that out if it annoys)

Code does the following

  1. Creates a working directory inside %Temp%
  2. Copies chm file to working directory inside %Temp%
  3. Creates a working subdirectory based of chm filename.
  4. Decompiles the chm using hh.exe depositing html files to subdirectory.

Code was ported from VBA equivalent class but I think I moved all over to os.path where it mattered.

Other future modules will be posted in future questions.

class HelpFileDecompiler(object):
    _reg_clsid_ = "{4B388A08-8CAB-4568-AF78-47032744A368}"
    _reg_progid_ = 'PythonInVBA.HelpFileDecompiler'
    _public_methods_ = ['DecompileHelpFileMain']

    def DecompileHelpFileMain(self, sHelpFile):
        import os.path
        eg = ", e.g. 'c:\\foo.chm'"
        if not isinstance(sHelpFile, str):
            raise Exception("sHelpFile needs to be a string" + eg)
        if len(sHelpFile) == 0:
            raise Exception("sHelpFile needs to be a non-null string" + eg)
        if sHelpFile.lower()[-4:] != ".chm":
            raise Exception("sHelpFile needs to end with '.chm' " + eg)
        if not os.path.isfile(sHelpFile):
            raise Exception("sHelpFile " + sHelpFile + " not found")

        self.BuildTmpDirectory()
        sCopiedFile = self.CopyChmFileToTempAppPath(sHelpFile)
        self.DecompileHelpFile(sCopiedFile)

    def BuildTmpDirectory(self):
        import os
        import os.path
        sTempAppPath = os.path.join(os.environ['tmp'], 'HelpFileDecompiler')

        if not os.path.isdir(sTempAppPath):
            os.mkdir(sTempAppPath)

    def CopyChmFileToTempAppPath(self, sHelpFile):
        import shutil
        import os.path
        sDestFile = os.path.join(os.environ['tmp'], 'HelpFileDecompiler',
                                 os.path.basename(sHelpFile))
        shutil.copyfile(sHelpFile, sDestFile)
        return sDestFile

    def DecompileHelpFile(self, sHelpFile):
        import win32api
        import subprocess
        import os.path

        if not os.path.isfile(sHelpFile):
            raise Exception("sHelpFile " + sHelpFile + " not found")

        sDecompiledFolder = os.path.join(
            os.environ['tmp'],
            'HelpFileDecompiler',
            os.path.basename(sHelpFile).split(".")[0])

        if not os.path.isdir(sDecompiledFolder):
            os.mkdir(sDecompiledFolder)

        sHELPEXE = "C:\Windows\hh.exe"
        if not os.path.isfile(sHELPEXE):
            raise Exception("sHELPEXE " + sHELPEXE + " not found")

        # Not allowed to quote arguments to HH.EXE
        # so we take the short path to eliminate spaces
        sHelpFileShort = win32api.GetShortPathName(sHelpFile)
        sDecompiledFolderShort = win32api.GetShortPathName(sDecompiledFolder)

        # so now we can run the decompiler
        subprocess.run([sHELPEXE, '-decompile',
                       sDecompiledFolderShort, sHelpFileShort])


if __name__ == '__main__':
    print ("Registering COM servers...")
    import win32com.server.register
    win32com.server.register.UseCommandLine(HelpFileDecompiler)

    helpFile=("C:\\Program Files\\Microsoft Office 15\\root\\vfs\\"
              "ProgramFilesCommonX86\\Microsoft Shared\\VBA\\VBA7.1\\"
              "1033\\VBLR6.chm")
    test = HelpFileDecompiler()
    test.DecompileHelpFileMain(helpFile)

Test VBA code is below (but actually one can run from command line also)

Option Explicit

Sub Test()

    Dim obj As Object
    Set obj = VBA.CreateObject("PythonInVBA.HelpFileDecompiler")

    obj.DecompileHelpFileMain "C:\Program Files\Microsoft Office 15\root\vfs\" & _
              "ProgramFilesCommonX86\Microsoft Shared\VBA\VBA7.1\" & _
              "1033\VBLR6.chm"

End Sub

Notes:

  1. Because the VBA client has no type library I have done much argument checking in DecompileHelpFileMain
\$\endgroup\$
  • \$\begingroup\$ You have a comment stating "Not allowed to quote arguments to HH.EXE". Why is that? \$\endgroup\$ – 301_Moved_Permanently Jul 20 '18 at 16:40
  • \$\begingroup\$ I can't quite remember sorry. \$\endgroup\$ – S Meaden Jul 20 '18 at 16:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.