excelAddin.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. # A demo plugin for Microsoft Excel
  2. #
  3. # This addin simply adds a new button to the main Excel toolbar,
  4. # and displays a message box when clicked. Thus, it demonstrates
  5. # how to plug in to Excel itself, and hook Excel events.
  6. #
  7. #
  8. # To register the addin, simply execute:
  9. # excelAddin.py
  10. # This will install the COM server, and write the necessary
  11. # AddIn key to Excel
  12. #
  13. # To unregister completely:
  14. # excelAddin.py --unregister
  15. #
  16. # To debug, execute:
  17. # excelAddin.py --debug
  18. #
  19. # Then open Pythonwin, and select "Tools->Trace Collector Debugging Tool"
  20. # Restart excel, and you should see some output generated.
  21. #
  22. # NOTE: If the AddIn fails with an error, Excel will re-register
  23. # the addin to not automatically load next time Excel starts. To
  24. # correct this, simply re-register the addin (see above)
  25. #
  26. # Author <ekoome@yahoo.com> Eric Koome
  27. # Copyright (c) 2003 Wavecom Inc. All rights reserved
  28. #
  29. # Redistribution and use in source and binary forms, with or without
  30. #modification, are permitted provided that the following conditions
  31. #are met:
  32. #
  33. #1. Redistributions of source code must retain the above copyright
  34. # notice, this list of conditions and the following disclaimer.
  35. #
  36. # THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. # DISCLAIMED. IN NO EVENT SHALL ERIC KOOME OR
  40. # ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. # SUCH DAMAGE.
  48. from win32com import universal
  49. from win32com.server.exception import COMException
  50. from win32com.client import gencache, DispatchWithEvents
  51. import winerror
  52. import pythoncom
  53. from win32com.client import constants, Dispatch
  54. import sys
  55. # Support for COM objects we use.
  56. gencache.EnsureModule('{00020813-0000-0000-C000-000000000046}', 0, 1, 3, bForDemand=True) # Excel 9
  57. gencache.EnsureModule('{2DF8D04C-5BFA-101B-BDE5-00AA0044DE52}', 0, 2, 1, bForDemand=True) # Office 9
  58. # The TLB defiining the interfaces we implement
  59. universal.RegisterInterfaces('{AC0714F2-3D04-11D1-AE7D-00A0C90F26F4}', 0, 1, 0, ["_IDTExtensibility2"])
  60. class ButtonEvent:
  61. def OnClick(self, button, cancel):
  62. import win32ui # Possible, but not necessary, to use a Pythonwin GUI
  63. import win32con
  64. win32ui.MessageBox("Hello from Python", "Python Test",win32con.MB_OKCANCEL)
  65. return cancel
  66. class ExcelAddin:
  67. _com_interfaces_ = ['_IDTExtensibility2']
  68. _public_methods_ = []
  69. _reg_clsctx_ = pythoncom.CLSCTX_INPROC_SERVER
  70. _reg_clsid_ = "{C5482ECA-F559-45A0-B078-B2036E6F011A}"
  71. _reg_progid_ = "Python.Test.ExcelAddin"
  72. _reg_policy_spec_ = "win32com.server.policy.EventHandlerPolicy"
  73. def __init__(self):
  74. self.appHostApp = None
  75. def OnConnection(self, application, connectMode, addin, custom):
  76. print("OnConnection", application, connectMode, addin, custom)
  77. try:
  78. self.appHostApp = application
  79. cbcMyBar = self.appHostApp.CommandBars.Add(Name="PythonBar", Position=constants.msoBarTop, MenuBar=constants.msoBarTypeNormal, Temporary=True)
  80. btnMyButton = cbcMyBar.Controls.Add(Type=constants.msoControlButton, Parameter="Greetings")
  81. btnMyButton=self.toolbarButton = DispatchWithEvents(btnMyButton, ButtonEvent)
  82. btnMyButton.Style = constants.msoButtonCaption
  83. btnMyButton.BeginGroup = True
  84. btnMyButton.Caption = "&Python"
  85. btnMyButton.TooltipText = "Python rules the World"
  86. btnMyButton.Width = "34"
  87. cbcMyBar.Visible = True
  88. except pythoncom.com_error as xxx_todo_changeme:
  89. (hr, msg, exc, arg) = xxx_todo_changeme.args
  90. print("The Excel call failed with code %d: %s" % (hr, msg))
  91. if exc is None:
  92. print("There is no extended error information")
  93. else:
  94. wcode, source, text, helpFile, helpId, scode = exc
  95. print("The source of the error is", source)
  96. print("The error message is", text)
  97. print("More info can be found in %s (id=%d)" % (helpFile, helpId))
  98. def OnDisconnection(self, mode, custom):
  99. print("OnDisconnection")
  100. self.appHostApp.CommandBars("PythonBar").Delete
  101. self.appHostApp=None
  102. def OnAddInsUpdate(self, custom):
  103. print("OnAddInsUpdate", custom)
  104. def OnStartupComplete(self, custom):
  105. print("OnStartupComplete", custom)
  106. def OnBeginShutdown(self, custom):
  107. print("OnBeginShutdown", custom)
  108. def RegisterAddin(klass):
  109. import winreg
  110. key = winreg.CreateKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Office\\Excel\\Addins")
  111. subkey = winreg.CreateKey(key, klass._reg_progid_)
  112. winreg.SetValueEx(subkey, "CommandLineSafe", 0, winreg.REG_DWORD, 0)
  113. winreg.SetValueEx(subkey, "LoadBehavior", 0, winreg.REG_DWORD, 3)
  114. winreg.SetValueEx(subkey, "Description", 0, winreg.REG_SZ, "Excel Addin")
  115. winreg.SetValueEx(subkey, "FriendlyName", 0, winreg.REG_SZ, "A Simple Excel Addin")
  116. def UnregisterAddin(klass):
  117. import winreg
  118. try:
  119. winreg.DeleteKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Office\\Excel\\Addins\\" + klass._reg_progid_)
  120. except WindowsError:
  121. pass
  122. if __name__ == '__main__':
  123. import win32com.server.register
  124. win32com.server.register.UseCommandLine(ExcelAddin)
  125. if "--unregister" in sys.argv:
  126. UnregisterAddin(ExcelAddin)
  127. else:
  128. RegisterAddin(ExcelAddin)