a oe?@sdZddlZddlZddlZddlZddlmZddlmZddlm Z dZ dZ dZ dZ ee e e e ee e e e d d gGd d d eZGd ddeZGdddeZGdddeZedkrddlZejjedS)a@Excel IRTDServer implementation. This module is a functional example of how to implement the IRTDServer interface in python, using the pywin32 extensions. Further details, about this interface and it can be found at: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnexcl2k2/html/odc_xlrtdfaq.asp N) universal)gencache) COMExceptionz&{00020813-0000-0000-C000-000000000046} IRtdServerZIRTDUpdateEventcseZdZdZdgZgdZejZdZ dZ fddZ dd Z d d Z d d ZddZddZddZddZd#ddZddZddZddZdd Zd!d"ZZS)$ExcelRTDServeraBase RTDServer class. Provides most of the features needed to implement the IRtdServer interface. Manages topic adding, removal, and packing up the values for excel. Shouldn't be instanciated directly. Instead, descendant classes should override the CreateTopic() method. Topic objects only need to provide a GetValue() function to play nice here. The values given need to be atomic (eg. string, int, float... etc). Also note: nothing has been done within this class to ensure that we get time to check our topics for updates. I've left that up to the subclass since the ways, and needs, of refreshing your topics will vary greatly. For example, the sample implementation uses a timer thread to wake itself up. Whichever way you choose to do it, your class needs to be able to wake up occaisionally, since excel will never call your class without being asked to first. Excel will communicate with our object in this order: 1. Excel instanciates our object and calls ServerStart, providing us with an IRTDUpdateEvent callback object. 2. Excel calls ConnectData when it wants to subscribe to a new "topic". 3. When we have new data to provide, we call the UpdateNotify method of the callback object we were given. 4. Excel calls our RefreshData method, and receives a 2d SafeArray (row-major) containing the Topic ids in the 1st dim, and the topic values in the 2nd dim. 5. When not needed anymore, Excel will call our DisconnectData to unsubscribe from a topic. 6. When there are no more topics left, Excel will call our ServerTerminate method to kill us. Throughout, at undetermined periods, Excel will call our Heartbeat method to see if we're still alive. It must return a non-zero value, or we'll be killed. NOTE: By default, excel will at most call RefreshData once every 2 seconds. This is a setting that needs to be changed excel-side. To change this, you can set the throttle interval like this in the excel VBA object model: Application.RTD.ThrottleInterval = 1000 ' milliseconds r) ConnectDataDisconnectData Heartbeat RefreshData ServerStartServerTerminaterrcs&tt||j|_d|_i|_dS)Z ConstructorN)superr__init__ALIVEIsAlive_ExcelRTDServer__callbacktopicsself __class__>C:\Program Files\Certbot\pkgs\win32com\demos\excelRTDServer.pyrszExcelRTDServer.__init__cCs"|jdurtdd|jdS)zCUse the callback we were given to tell excel new data is available.NzCallback excel provided is NullZdesc)rrZ UpdateNotifyrrrr SignalExcels  zExcelRTDServer.SignalExcelc Csz|||j|<Wn2tyF}ztt|dWYd}~n d}~00d}|j|}|durld|jj}n|}||||fS)z6Creates a new topic out of the Strings excel gives us.rNTz# %s: Waiting for update) CreateTopicr Exceptionrstrr__name__GetValue OnConnectData)rTopicIDZStringsZ GetNewValueswhyresultrrrr s$  zExcelRTDServer.ConnectDatacCs*||||jvr&d|j|<|j|=dS)zDeletes the given topic.N)OnDisconnectDatarrr#rrrr s   zExcelRTDServer.DisconnectDatacCs|jS)z+Called by excel to see if we're still here.)rrrrrr szExcelRTDServer.HeartbeatcCsnt|j}|dg|dg|g}t|jD],\}}|\}}||d|<||d|<q4t||fS)aPacks up the topic values. Called by excel when it's ready for an update. Needs to: * Return the current number of topics, via the "ByRef" TopicCount * Return a 2d SafeArray of the topic data. - 1st dim: topic numbers - 2nd dim: topic values We could do some caching, instead of repacking everytime... But this works for demonstration purposes.Nrr)lenr OnRefreshData enumerateitemsr!tuple)rZ TopicCountresultsidxZ topicdataZtopicNumtopicrrrr s  zExcelRTDServer.RefreshDatacCs@|j|_|durtddtjjd}|||_||jS)zMExcel has just created us... We take its callback for later, and set up shop.Nz Excel did not provide a callbackrz&{A43788C1-D91B-11D3-8F39-00C04F3651B8}) rrrwin32comZclientZ CLSIDToClassZGetClassr OnServerStart)rZCallbackObjectZIRTDUpdateEventKlassrrrr s  zExcelRTDServer.ServerStartcCs|j|_|dS)z%Called when excel no longer wants us.N) NOT_ALIVErOnServerTerminaterrrrrszExcelRTDServer.ServerTerminateNcCs tddS)zTopic factory method. Subclass must override. Topic objects need to provide: * GetValue() method which returns an atomic value. Will raise NotImplemented if not overridden. zSubclass must implementNNotImplementedr TopicStringsrrrrszExcelRTDServer.CreateTopiccCsdS)z=Called when a new topic has been created, at excel's request.Nrr'rrrr"szExcelRTDServer.OnConnectDatacCsdS)z?Called when a topic is about to be deleted, at excel's request.Nrr'rrrr&szExcelRTDServer.OnDisconnectDatacCsdS)z7Called when excel has requested all current topic data.Nrrrrrr)szExcelRTDServer.OnRefreshDatacCsdS)z&Called when excel has instanciated us.Nrrrrrr1szExcelRTDServer.OnServerStartcCsdS)z)Called when excel is about to destroy us.Nrrrrrr3sz ExcelRTDServer.OnServerTerminate)N)r __module__ __qualname____doc__Z_com_interfaces_Z_public_methods_ pythoncomZCLSCTX_INPROC_SERVERZ _reg_clsctx_rr2rrr r r r r rrr"r&r)r1r3 __classcell__rrrrrHs(+   rcsHeZdZdZfddZddZddZdd Zd d Zd d Z Z S)RTDTopiczBase RTD Topic. Only method required by our RTDServer implementation is GetValue(). The others are more for convenience.cs$tt|||_d|_d|_dS)NF)rr=rr7_RTDTopic__currentValue_RTDTopic__dirtyr6rrrr szRTDTopic.__init__cCs tddS)zCalled by the RTD Server. Gives us a chance to check if our topic data needs to be changed (eg. check a file, quiz a database, etc).zsubclass must implementNr4)rsenderrrrUpdateszRTDTopic.UpdatecCs d|_dS)z6Call when this topic isn't considered "dirty" anymore.FNr?rrrrResetszRTDTopic.ResetcCs|jSN)r>rrrrr!szRTDTopic.GetValuecCsd|_||_dS)NT)r?r>)rvaluerrrSetValueszRTDTopic.SetValuecCs|jSrDrBrrrr HasChanged#szRTDTopic.HasChanged) r r8r9r:rrArCr!rFrGr<rrrrr=s r=csReZdZdZdZdZdZdZfddZdd Z d d Z d d Z dddZ Z S) TimeServeraDExample Time RTD server. Sends time updates back to excel. example of use, in an excel sheet: =RTD("Python.RTD.TimeServer","","seconds","5") This will cause a timestamp string to fill the cell, and update its value every 5 seconds (or as close as possible depending on how busy excel is). The empty string parameter denotes the com server is running on the local machine. Otherwise, put in the hostname to look on. For more info on this, lookup the Excel help for its "RTD" worksheet function. Obviously, you'd want to wrap this kind of thing in a friendlier VBA function. Also, remember that the RTD function accepts a maximum of 28 arguments! If you want to pass more, you may need to concatenate arguments into one string, and have your topic parse them appropriately. z&{EA7F2CF1-11A2-45E4-B2D5-68E240DB8CB1}zPython.RTD.TimeServerz8Python class implementing Excel IRTDServer -- feeds timeg?cs$tt|t|j|j|_dSrD)rrHr threadingTimerINTERVALrAtickerrrrrrNszTimeServer.__init__cCs|jdSrD)rLstartrrrrr1YszTimeServer.OnServerStartcCs|jjs|jdSrD)rLfinishedisSetcancelrrrrr3\s zTimeServer.OnServerTerminatecCszt|j|j|_zVt|jr\d}|jD]"}|||rFd}| q,|r\| W|j n |j 0dS)NFT) rIrJrKrArLr(rvaluesrGrCrrM)rrefreshr/rrrrA`s    zTimeServer.UpdateNcCst|S)zGTopic factory. Builds a TimeTopic object out of the given TopicStrings.) TimeTopicr6rrrrrszTimeServer.CreateTopic)N)r r8r9r:Z _reg_clsid_Z _reg_progid_Z _reg_desc_rKrr1r3rArr<rrrrrH.s rHcs0eZdZdZfddZddZddZZS)rSzExample topic for example RTD server. Will accept some simple commands to alter how long to delay value updates. Commands: * seconds, delay_in_seconds * minutes, delay_in_minutes * hours, delay_in_hours c stt||z|j\|_|_Wn4tyV}ztdt|WYd}~n d}~00t |j|_| |_ | t|j dS)NzInvalid topic strings: %s) rrSrr7cmddelayr ValueErrorrfloat timestamp checkpointrF)rr7Errrrs&  zTimeTopic.__init__cCs tjSrD)datetimenowrrrrrXszTimeTopic.timestampcCs|}||j}d}|jdkr2|j|jkrzd}nH|jdkrN|j|jkrzd}n,|jdkrj|j|jkrzd}n|d|j|r|t|||_dS)NFsecondsTminuteshoursz#Unknown command: ) rXrYrTr]rUr^r_rFr)rr@r\ZdeltarRrrrrAs        zTimeTopic.Update)r r8r9r:rrXrAr<rrrrrSws rS__main__)r:r[rIr;Zwin32com.clientr0rrZwin32com.server.exceptionrZEXCEL_TLB_GUIDZEXCEL_TLB_LCIDZEXCEL_TLB_MAJORZEXCEL_TLB_MINORZ EnsureModuleZRegisterInterfacesobjectrr=rHrSr Zwin32com.server.registerZserverregisterZUseCommandLinerrrrs6      @'I4