>>I think the problem is with the ActiveExplorer object(s). When I get >>them "released" or set to None, then Outlook is happy to shutdown >>immediately (even when *other* interfaces are still referenced). If the >>ActiveExplorer object(s) are still referenced, then Outlook stays in >>memory (apparently to do some clean up). >> >>So, I'm looking into releasing the ActiveExplorer objects (well, all of >>the objects, but especially the ActiveExplorer), then I think I'll have >>the problem solved (fingers crossed). > > > Hi Bill, > > How did you end up going with this? Do you have an updated version of the > sample plugin that does not demonstrate the original problem? >
Mark, Yes, I have fixed the original problem. I would have got back to the list sooner, but I've been real busy lately :-). It was definitely the ActiveExplorer object that was making Outlook hang around in memory. I tried killing every *other* object and nothing changed until I killed the ActiveExplorer. My current code has a Gateway count of 1 and an Interface count of 1. When I shutdown Outlook, it closes immediately. The entire piece of code is below. I've used the code in the demos directory (..\site-packages\win32com\demos\outlookAddin.py) as a basis for my code. Keep in mind - I'm still learning, so if you see something that smells, let me know :-) Thank you for your help! Bill <code> import sys import os import re # Per comments in SpamBayes Outlook addin.py, # I've added this here and in two other spots. import locale locale.setlocale(locale.LC_NUMERIC, "C") import win32api import win32con from win32com import universal from win32com.server.exception import COMException from win32com.client import gencache, DispatchWithEvents import winerror import pythoncom from win32com.client import constants # Support for COM objects we use. gencache.EnsureModule('{00062FFF-0000-0000-C000-000000000046}', 0, 9, 0, bForDemand=True) # Outlook 9 gencache.EnsureModule('{2DF8D04C-5BFA-101B-BDE5-00AA0044DE52}', 0, 2, 1, bForDemand=True) # Office 9 # The TLB defining the interfaces we implement universal.RegisterInterfaces('{AC0714F2-3D04-11D1-AE7D-00A0C90F26F4}', 0, 1, 0, ["_IDTExtensibility2"]) class ButtonEvent: def Init(self, application): self.application = application self.activeExplorer = None def Close(self): self.application = None self.activeExplorer = None self.close() def OnClick(self, button, cancel): locale.setlocale(locale.LC_NUMERIC, "C") if self.activeExplorer is None: self.activeExplorer = self.application.ActiveExplorer() # Get the ID of the folder we're currently in. currentFolder = self.activeExplorer.CurrentFolder currentFolderID = currentFolder.Parent.StoreID, currentFolder.EntryID # Get the ID of the 'Sent Items' folder. sentFolder = self.application.Session.GetDefaultFolder(constants.olFolderSentMail) sentFolderID = sentFolder.Parent.StoreID, sentFolder.EntryID # If we're in the 'Sent Items' folder... if currentFolderID[1] == sentFolderID[1]: self.getSentEmailInfo() else: # not in the 'Sent Items' folder. self.folderError() def getSentEmailInfo(self): # Grab all of the fields from the currently # selected sent mail item. sentMailItem = self.activeExplorer.Selection.Item(1) try: To = sentMailItem.To CC = sentMailItem.CC BCC = sentMailItem.BCC Subject = sentMailItem.Subject Body = sentMailItem.Body except: # Don't forget to change this. print "Hit an error in getSentEmailInfo()" # Better kill the ActiveExplorer or Outlook # will hang on shutdown. self.activeExplorer = None self.createMailMessage(To, CC, BCC, Subject, Body) def createMailMessage(self, To, CC, BCC, Subject, Body): # Create the new mail message.... # # There's usually a 'download' link in the body of the # 'Invitation to Bid', if we find it, we'll use it. site = re.findall("http://.*", Body) if site: # Our link is top-level, let's create a new link # that points right to the addendum directory. link = site[0].strip("\r") + "/addendum" else: link = "" mailMessage = self.application.CreateItem(constants.olMailItem) mailMessage.To = To mailMessage.CC = CC mailMessage.BCC = BCC if "RE:" in Subject: mailMessage.Subject = Subject else: mailMessage.Subject = "RE: " + Subject mailMessage.Body = "A new addendum has been issued for this project.\n\n%s" % (link) mailMessage.Display() # Kill the ActiveExplorer. self.activeExplorer = None def folderError(self): errMsg = "You must be in the 'Sent Items' Folder to use this tool!" win32api.MessageBox(0, errMsg, 'Folder Error', win32con.MB_ICONEXCLAMATION) # Kill the ActiveExplorer. self.activeExplorer = None class OutlookAddin: _com_interfaces_ = ['_IDTExtensibility2'] _public_methods_ = [] _reg_clsctx_ = pythoncom.CLSCTX_INPROC_SERVER _reg_clsid_ = "{B61B8A3D-041E-4d82-908B-1503681A55B3}" _reg_progid_ = "InvitationHelper.OutlookAddin" _reg_policy_spec_ = "win32com.server.policy.EventHandlerPolicy" def __init__(self): self.application = None def OnConnection(self, application, connectMode, addin, custom): locale.setlocale(locale.LC_NUMERIC, "C") self.application = application # ActiveExplorer may be none when started without a UI (eg, WinCE synchronisation) activeExplorer = application.ActiveExplorer() if activeExplorer is not None: bars = activeExplorer.CommandBars toolbar = bars.Item("Standard") item = toolbar.Controls.Add(Type=constants.msoControlButton, Temporary=True) # Hook events for the item item = self.toolbarButton = DispatchWithEvents(item, ButtonEvent) item.Caption="Invitation Helper" item.TooltipText = "Creates a new email from a\n" \ "previously sent 'Invitation to Bid'." item.Enabled = True item.Init(self.application) self.item = item def OnDisconnection(self, mode, custom): self.item.Close() self.application = None print "Gateway Count: ", pythoncom._GetGatewayCount() print "Interface Count: ", pythoncom._GetInterfaceCount() def OnAddInsUpdate(self, custom): pass def OnStartupComplete(self, custom): pass def OnBeginShutdown(self, custom): pass def RegisterAddin(klass): import _winreg key = _winreg.CreateKey(_winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Office\\Outlook\\Addins") subkey = _winreg.CreateKey(key, klass._reg_progid_) _winreg.SetValueEx(subkey, "CommandLineSafe", 0, _winreg.REG_DWORD, 0) _winreg.SetValueEx(subkey, "LoadBehavior", 0, _winreg.REG_DWORD, 3) _winreg.SetValueEx(subkey, "Description", 0, _winreg.REG_SZ, "Invitation to Bid Tool") _winreg.SetValueEx(subkey, "FriendlyName", 0, _winreg.REG_SZ, "Invitation Helper") def UnregisterAddin(klass): import _winreg try: _winreg.DeleteKey(_winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Office\\Outlook\\Addins\\" + klass._reg_progid_) except WindowsError: pass if __name__ == '__main__': import win32com.server.register win32com.server.register.UseCommandLine(OutlookAddin) if "--unregister" in sys.argv: UnregisterAddin(OutlookAddin) else: RegisterAddin(OutlookAddin) </code> _______________________________________________ Python-win32 mailing list Python-win32@python.org http://mail.python.org/mailman/listinfo/python-win32