I have written code to use the automatic CD-Burn routine inside WinXP and above.

But I cannot start the CD Writing Wizard by python code. Has anybody any idea how to do it?
This is my code so far:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os, sys
import win32com.client
import win32file
from ctypes import *
from time import sleep
from win32com.shell import shell, shellcon

MAX_PATH = 260 
HICON = c_int

class SHFILEINFO(Structure): _fields_ = [("hIcon", HICON), ("iIcon", c_int), ("dwAttributes", c_uint), ("szDisplayName", c_char * MAX_PATH), ("szTypeName", c_char * 80)]

SHGFI_ICON = 0x000000100 
SHGFI_DISPLAYNAME = 0x000000200 
SHGFI_TYPENAME = 0x000000400 
SHGFI_ATTRIBUTES = 0x000000800 
SHGFI_ICONLOCATION = 0x000001000 
SHGFI_EXETYPE = 0x000002000 
SHGFI_SYSICONINDEX = 0x000004000 
SHGFI_LINKOVERLAY = 0x000008000 
SHGFI_SELECTED = 0x000010000 
SHGFI_ATTR_SPECIFIED = 0x000020000 
SHGFI_LARGEICON = 0x000000000 
SHGFI_SMALLICON = 0x000000001 
SHGFI_OPENICON = 0x000000002 
SHGFI_SHELLICONSIZE = 0x000000004 
SHGFI_PIDL = 0x000000008 
SHGFI_USEFILEATTRIBUTES = 0x000000010

shfileinfo = SHFILEINFO()
shflags = SHGFI_DISPLAYNAME | SHGFI_TYPENAME | SHGFI_ATTRIBUTES


def find_drives():
        drivebits=win32file.GetLogicalDrives()
        # print drivebits
        not_removable_drives_no_cd = []
        removable_drives = []
        cd_rom = []
        cd_rom_type = []
        cd_writer = []
        cd_dvd = []
        for d in range(0,26):
            mask=1 << d
            if drivebits & mask:
                # here if the drive is at least there
                drname='%c:\\' % chr(ord('A')+d)
                # print drname, 
                t=win32file.GetDriveType(drname)
                if t == win32file.DRIVE_REMOVABLE:
                    # print "is removable",
                    removable_drives.append(drname.split("\\")[0])
                else:
                    # print "is not removable",
                    if t == win32file.DRIVE_CDROM:
                        # print "and is a CDROM drive",
                        cd_rom.append(drname.split("\\")[0])
                        windll.shell32.SHGetFileInfo(drname, 0, byref(shfileinfo), sizeof(shfileinfo), shflags)
                        cd_rom_type.append(shfileinfo.szDisplayName)
                        if cd_rom_type[-1].find("RW")>-1 or cd_rom_type[-1].find("RAM")>-1 or cd_rom_type[-1].find("Writer")>-1 or cd_rom_type[-1].find("WRITER")>-1:
                            cd_writer.append(True)
                        else:
                            cd_writer.append(False)
                        if cd_rom_type[-1].find("DVD")>-1:
                            cd_dvd.append("DVD")
                        else:
                            cd_dvd.append("CD")
                    else:
                        # print "and is not a CDROM drive",
                        not_removable_drives_no_cd.append(drname.split("\\")[0])
        return [not_removable_drives_no_cd,removable_drives,cd_rom,cd_rom_type,cd_writer,cd_dvd]

drives = find_drives()

print "CD-ROM letters/labels:",drives[2]
print "CD-ROM-Type:",drives[3]
print "CD-Writer:",drives[4]
print "CD or DVD:",drives[5]

cdburn_pidl = shell.SHGetFolderLocation (0, shellcon.CSIDL_CDBURN_AREA, 0, 0)
CDBurnStageArea = shell.SHGetPathFromIDList (cdburn_pidl)
# print "1st way to get folder:",CDBurnStageArea

# copy a file to CD Burn Stage Area
win32file.CopyFile (sys.executable, os.path.join(CDBurnStageArea,os.path.basename(sys.executable)), 0)

shell = win32com.client.Dispatch("WScript.Shell")
# strBurnDirectory = shell.RegRead("HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\CD Burning")
# print "2nd way to get folder:",strBurnDirectory

objShell = win32com.client.Dispatch("Shell.Application")

drive = ""

for d in range(len(drives[2])):
    if drives[4][d] == True:
        drive = drive + drives[2][d] + "\\"
        break

if drive == "":
    raise IOError, "No CD Writer found"

# show the CD writer drive and its contents supposed to be written
shell.Run("explorer.exe " + drive)
sleep(2)
windll.user32.MessageBoxA(None, "Please click onto:\nWrite these files to CD.\nThe CD Writing Wizard will start immediately.", "How to proceed", 0)

# this unfortunately not working:
"""
shell.AppActivate ("CD Writing Wizard")
while not shell.AppActivate("CD Writing Wizard"):
    print "waiting"
    sleep(1)
"""

I would love to know how to trigger the CD Writing Wizard without having to go through the GUI. Have you found how to launch that wizard?

Thanks,

Jody

I would love to know how to trigger the CD Writing Wizard without having to go through the GUI. Have you found how to launch that wizard?

OK, here is a rather bad hack, but it seems to work if you need to start the CD Writing Wizard of WinXP and above. You need to install the sendkeys module available from http://www.rutherfurd.net/python/sendkeys/

I rather would prefer a a clean solution programmatically called by a windows routine or so. Anybody any ideas?

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os, sys
import win32com.client
import win32file
from ctypes import *
from time import sleep
from win32com.shell import shell, shellcon


MAX_PATH = 260 
HICON = c_int

class SHFILEINFO(Structure): _fields_ = [("hIcon", HICON), ("iIcon", c_int), ("dwAttributes", c_uint), ("szDisplayName", c_char * MAX_PATH), ("szTypeName", c_char * 80)]

SHGFI_ICON = 0x000000100 
SHGFI_DISPLAYNAME = 0x000000200 
SHGFI_TYPENAME = 0x000000400 
SHGFI_ATTRIBUTES = 0x000000800 
SHGFI_ICONLOCATION = 0x000001000 
SHGFI_EXETYPE = 0x000002000 
SHGFI_SYSICONINDEX = 0x000004000 
SHGFI_LINKOVERLAY = 0x000008000 
SHGFI_SELECTED = 0x000010000 
SHGFI_ATTR_SPECIFIED = 0x000020000 
SHGFI_LARGEICON = 0x000000000 
SHGFI_SMALLICON = 0x000000001 
SHGFI_OPENICON = 0x000000002 
SHGFI_SHELLICONSIZE = 0x000000004 
SHGFI_PIDL = 0x000000008 
SHGFI_USEFILEATTRIBUTES = 0x000000010

shfileinfo = SHFILEINFO()
shflags = SHGFI_DISPLAYNAME | SHGFI_TYPENAME | SHGFI_ATTRIBUTES


def find_drives():
        drivebits=win32file.GetLogicalDrives()
        # print drivebits
        not_removable_drives_no_cd = []
        removable_drives = []
        cd_rom = []
        cd_rom_type = []
        cd_writer = []
        cd_dvd = []
        for d in range(0,26):
            mask=1 << d
            if drivebits & mask:
                # here if the drive is at least there
                drname='%c:\\' % chr(ord('A')+d)
                # print drname, 
                t=win32file.GetDriveType(drname)
                if t == win32file.DRIVE_REMOVABLE:
                    # print "is removable",
                    removable_drives.append(drname.split("\\")[0])
                else:
                    # print "is not removable",
                    if t == win32file.DRIVE_CDROM:
                        # print "and is a CDROM drive",
                        cd_rom.append(drname.split("\\")[0])
                        windll.shell32.SHGetFileInfo(drname, 0, byref(shfileinfo), sizeof(shfileinfo), shflags)
                        cd_rom_type.append(shfileinfo.szDisplayName)
                        if cd_rom_type[-1].find("RW")>-1 or cd_rom_type[-1].find("RAM")>-1 or cd_rom_type[-1].find("Writer")>-1 or cd_rom_type[-1].find("WRITER")>-1:
                            cd_writer.append(True)
                        else:
                            cd_writer.append(False)
                        if cd_rom_type[-1].find("DVD")>-1:
                            cd_dvd.append("DVD")
                        else:
                            cd_dvd.append("CD")
                    else:
                        # print "and is not a CDROM drive",
                        not_removable_drives_no_cd.append(drname.split("\\")[0])
        return [not_removable_drives_no_cd,removable_drives,cd_rom,cd_rom_type,cd_writer,cd_dvd]

drives = find_drives()

print "CD-ROM letters/labels:",drives[2]
print "CD-ROM-Type:",drives[3]
print "CD-Writer:",drives[4]
print "CD or DVD:",drives[5]

cdburn_pidl = shell.SHGetFolderLocation (0, shellcon.CSIDL_CDBURN_AREA, 0, 0)
CDBurnStageArea = shell.SHGetPathFromIDList (cdburn_pidl)
# print "1st way to get folder:",CDBurnStageArea

# copy a file to CD Burn Stage Area
win32file.CopyFile (sys.executable, os.path.join(CDBurnStageArea,os.path.basename(sys.executable)), 0)

shell = win32com.client.Dispatch("WScript.Shell")
# strBurnDirectory = shell.RegRead("HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\CD Burning")
# print "2nd way to get folder:",strBurnDirectory

drive = ""

for d in range(len(drives[2])):
    if drives[4][d] == True:
        drive = drive + drives[2][d] + "\\"
        break

if drive == "":
    raise IOError, "No CD Writer found"

# show the CD writer drive and its contents supposed to be written
shell.Run("explorer.exe " + drive)
sleep(2)
# windll.user32.MessageBoxA(None, "Please click onto:\nWrite these files to CD.\nThe CD Writing Wizard will start immediately.", "How to proceed", 0)

# and start the CD Wizard by using sendkeys module
# available at http://www.rutherfurd.net/python/sendkeys/

shell.SendKeys("%", 1) # 1 for pause = true 0 for none
shell.SendKeys("{DOWN}", 1)
shell.SendKeys("~", 1)
shell.SendKeys("%", 1) # 1 for pause = true 0 for none
shell.SendKeys("{DOWN}", 1)
shell.SendKeys("{UP}", 1)
shell.SendKeys("~", 1)

# see the docs for SendKeys at:
# http://win32com.goermezer.de/content/view/136/254/

For Vista you might want to add some lines of code, just tried it on a Vista machine, and it seems to work except that you must not close the parent window since otherwise the child process CD Writing Wizard also closes:
So change and add this code from line 116 to 119:

import platform
if platform.release() == "XP":
    # close the parent window without aborting CD Writing wizard
    # CD Writing Wizard closes if you close parent window in Vista
    shell.SendKeys("%", 1) # 1 for pause = true 0 for none
    shell.SendKeys("{DOWN}", 1)
    shell.SendKeys("{UP}", 1)
    shell.SendKeys("~", 1)

Edited 6 Years Ago by bunkus: n/a

Thanks to Tim Golden from http://timgolden.me.uk/python/index.html
we have a solution for calling the CD Writing Wizard under WinXP or Vista to burn a CD according to the contents inside the CD burn staging area. So here is the code for calling the wizard:

import os, sys
import shutil

from comtypes import *
import comtypes.client
from ctypes.wintypes import *

S_OK = 0
CSIDL_CDBURN_AREA = 59

##
## ICDBurn
##
IID_ICDBurn = "{3d73a659-e5d0-4d42-afc0-5121ba425c8d}"

class ICDBurn (IUnknown):
  _iid_ = GUID (IID_ICDBurn)
  _methods_ = [
    STDMETHOD (HRESULT, "GetRecorderDriveLetter", (LPWSTR, UINT)),
    STDMETHOD (HRESULT, "Burn", (HWND,)),
    STDMETHOD (HRESULT, "HasRecordableDrive", (POINTER (BOOL),))
  ]
  
def main (directory):
  CDBurn_GUID = '{fbeb8a05-beee-4442-804e-409d6c4515e9}'
  CDBurn = comtypes.client.CreateObject (CDBurn_GUID, interface=ICDBurn)

  has_recordable_drive = BOOL ()
  CDBurn.HasRecordableDrive (byref (has_recordable_drive))
  if not has_recordable_drive:
    raise RuntimeError ("No recordable drive found")

  letter = create_unicode_buffer (4)
  cch = UINT (4)
  result = CDBurn.GetRecorderDriveLetter (letter, cch)
  if result != S_OK:
    raise RuntimeError ("Unable to get recorder drive letter: %d" % result)
  else:
    print "Using drive", letter.value

  path_buffer = create_unicode_buffer (1024)
  result = windll.shell32.SHGetFolderPathW (HWND (0), CSIDL_CDBURN_AREA, None, 0, path_buffer)
  if result != S_OK:
    raise RuntimeError ("Unable to find staging area: %d" % result)

  burn_area = path_buffer.value
  shutil.copytree (directory, os.path.join (burn_area, os.path.basename (directory)))

  CDBurn.Burn (0)

if __name__ == '__main__':
  main (*sys.argv[1:])
This question has already been answered. Start a new discussion instead.