我已经编写了一个 python 脚本,它将作为我支持的启用宏的 PowerPoint 文件的“构建脚本”。
该脚本创建一个新的空 PowerPoint 演示文稿,导入所有 VBA 模块,保存文件并将其转换为 ZIP 存档,以便插入 RibbonUI 配置(ribbon_xml.xml文件和mylogo.jpg文件)。
所有这些都或多或少地按预期工作 - 直到我尝试使用输出文件(手动从 .zip 重命名为 .pptm 并在 PowerPoint 中打开它)。
错误代码干净地退出,但转换为 PPTM 文件时的输出存档 (copy.zip) 没有干净地打开。
我收到配置有问题的警告,PowerPoint 将尝试修复文件。
PowerPoint,其本质当然并不表明问题是什么,只是它发现了“不可读的内容”并且这些内容已“被删除”......在比较我创建的一些文件后我唯一能看到的手动,是 CustomUI 的 XML 属性似乎使用某种 GUID 作为其 id 属性的一部分
当前解决方法:函数build_ribbon可以使用 CustomUI 编辑器工具手动完成,大约需要 3 分钟才能可靠地生成 PPTM 输出。
所以这不是一个特别“Python”的问题,因为它是一个关于 CustomUI XML/ribbon XML 接口的实现的问题。
完整代码:
import win32com.client
import os
import zipfile
import uuid
#### PARAMETERS
vba_source_control_path = r"C:\Repos\MyAddIn\VBA\ChartBuilder_PPT\Modules"
output_path = r"C:\debug\output.pptm"
ribbon_xml_path = r"C:\Repos\MyAddIn\Ribbon XML\ribbon_xml.xml"
ribbon_logo_path = r"C:\Repos\MyAddIn\Ribbon XML\mylogo.jpg"
def build_addin(pres, path):
"""
This procedure does the following:
1. adds all of the VBComponents to the working PPTM file
The .PPTM file is used for local development & debugging and
is only usually packaged as a PPAM for Testing and Distribution
"""
for fn in [fn for fn in os.listdir(path) if not(fn.endswith(".frx"))]:
pres.VBProject.VBComponents.Import(path + "\\" + fn)
# Clean up old files, if any
if os.path.isfile(output_path):
os.remove(output_path)
if os.path.isfile(output_path.replace(".pptm", ".zip")):
os.remove(output_path.replace(".pptm", ".zip"))
# Save the new file with VBProject components
pres.SaveAs(output_path)
pres.Close()
def build_ribbon_zip():
"""
build_ribbon_zip handles manipulation of the .ZIP contents and places the
necessary components within the PPTM ZIP archive structure
2. converts the PPTM to a .ZIP
3. Adds the CustomUI XML and logo.jpg to the .ZIP directory
4. converts the .ZIP to a PPTM
"""
id = '<Relationship Id='
schema = 'http://schemas.openxmlformats.org/officeDocument/2006/'
_path = output_path.replace(".pptm", ".zip")
copy_path = r"C:\debug\copy.zip"
# Convert to ZIP archive
os.rename(output_path, _path)
zip = zipfile.ZipFile(_path, 'a')
copy = zipfile.ZipFile(copy_path, 'w')
guid = str(uuid.uuid4()).replace('-', '')[:16]
for itm in [itm for itm in zip.infolist() if itm.filename != r'_rels/.rels']:
buffer = zip.read(itm.filename)
copy.writestr(itm, buffer)
# Append the Logo file to the .zip and create the archive
copy.write(ribbon_logo_path, r'\CustomUI\images\jdplogo.jpg')
# append the CustomUI xml part to the .zip and create the archive
copy.write(ribbon_xml_path, r'\CustomUI\customUI14.xml')
# append the .rels file to CustomUI\_rels
rels_xml = r'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
rels_xml += r'<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'
rels_xml += r'<Relationship Id="jdplogo" Type="'+schema+'relationships/image" Target="images/jdplogo.jpg"/>'
rels_xml += r'</Relationships>'
copy.writestr(r'CustomUI\_rels\customUI14.xml.rels', rels_xml.encode('utf-8'))
# get the existing _rels/.rels XML content and append the UI:
rels_xml = zip.read(r'_rels/.rels').rstrip()[:-16]
rels_xml += id + r'"R'+guid+'" Type="http://schemas.microsoft.com/office/2007/relationships/ui/extensibility"'
rels_xml += r'Target="customUI/customUI14.xml"/></Relationships>'
rels_xml = rels_xml.replace(os.linesep, '')
# this file-like object is read-only, and the writestr method will create another .rels file...
copy.writestr(r'_rels/.rels', rels_xml.encode('utf-8'))
zip.close()
copy.close()
if __name__ == "__main__":
"""
Procedure to create a new PowerPoint Presentation and insert the Code Modules from source control
"""
ppApp = win32com.client.Dispatch("PowerPoint.Application")
pres = ppApp.Presentations.Add(False)
pres.Slides.AddSlide(1, pres.SlideMaster.CustomLayouts(1))
build_addin(pres, vba_source_control_path)
ppApp.Quit()
build_ribbon_zip()