Groove Programming Tips & Tricks : Techniques to develop better tools in Groove
Updated: 1/21/2005; 10:19:42 AM.

 








Subscribe to "Groove Programming Tips & Tricks" in Radio UserLand.

Click to see the XML version of this web page.

 
 

Saturday, February 15, 2003

Release objects cached in GrooveRunTimeData when they are no longer needed

You can either call the RemoveItem method (to remove one item at a time) or you can call the RemoveAllItems method to accomplish this.
9:43:01 AM    comment []

Monday, November 04, 2002

Implement COM objects in script

Among the variety of powerful things that Groove's ScriptFreeThreaded component can do, one of the more interesting ones is the ability to implement CoCreate'able objects in script.  The Groove Platform GDK contains a sample called YourApp10 that shows how to do this, so I will just summarize the main points.  Note that if you don't know much about COM or writing IDL, go get this book and read it.

Write IDL for the COM object
To be a good citizen to early and late binding clients, you should define dual interfaces for non-event interfaces.  You should also have 2 flavors of event interfaces, 1 for early bound clients that derives from IUnknown and 1 for late bound clients that is a dispinterface.  You should also define a CoClass to publish the interfaces implemented by the COM object.  Note that [in, out] and [out] parameters are not supported for methods.

Define OSD so that the COM object can be CoCreate'd
<SOFTPKG NAME="com.yourcompany.xxx.YourCOMObject_GSL" VERSION="1,0,0,0">
   <IMPLEMENTATION>
      <CODEBASE HREF="http://components.yourcompany.com/xxx/YourCOMObject.gsl"/>
      <g:Install Type="Import To XSS" DatabaseURI="$TEMPLATESURI$" DocumentName="YourCOMObject.gsl" SchemaURI="$DEFAULTSCHEMA$"/>
     <g:Factory Name="Open" Type="XML Document" DatabaseURI="$TEMPLATESURI$" DocumentName="YourCOMObject.gsl"/>
     
     <g:Registry Command="Add" Hive="HKCR" Key="clsid\{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}" Value="" Data="Your COM Object" Type="String"/>
     <g:Registry Command="Add" Hive="HKCR" Key="clsid\{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}\InprocServer32" Value="" Data="$GROOVEBIN$\GrooveCommonComponents.dll" Type="String"/>
     <g:Registry Command="Add" Hive="HKCR" Key="clsid\{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}\InprocServer32" Value="ThreadingModel" Data="Both" Type="String"/>
     <g:Registry Command="Add" Hive="HKCR" Key="clsid\{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}\URL" Value="" Data="http://components.yourcompany.com/xxx/YourCOMObject.osd?Package=com.yourcompany.xxx.YourCOMObject_GSL&;amp;Version=1,0&amp;Factory=Open" Type="String"/>
     <g:Registry Command="Add" Hive="HKCR" Key="YourCOMObjects.YourCOMObjectProgID\CLSID" Value="" Data="{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}" Type="String"/>
    </IMPLEMENTATION>
</SOFTPKG>

Create a .gsl file for the COM object
This script file should import the type library for your COM object, as well as any other dependent type libraries.   You import type libraries by having the following statement:

<TYPELIB LIBID="{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFE}" NAME="YourCOMObjectTypeLibrary" MAJORVER="1" MINORVER="0"/>
Your script file should implement the interfaces as described by the coclass (at least).  You implement interfaces by having the following statement:

<IMPLEMENTS Default="1" IID="{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}" LIBID="{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFE}">
Note that the Default attribute should only be used for one of the implemented interfaces, and omitted from all other implemented interface.  Also note that to return HRESULT values, you should use the SetCurrentError method.

Global & instance data storage
You should not define/use global variables because of performance reasons and the fact that they are not thread safe/accessible.  Instead you should use GrooveRunTimeData and/or ScriptSharedObjectTables.
7:59:21 AM    comment []

Friday, September 27, 2002

Don't use JavaScript classes/objects for storage in ScriptFreeThreadedComponents

Any objects that are allocated by calling the "new" operator have thread affinity - this means that if the thread 1 creates an instance of a JavaScript class, only thread 1 can access/use it.  Instead use shared object tables for scalar types or COM objects implemented in script when instance method invocation is required.
8:50:03 AM    comment []

Thursday, September 12, 2002

Return HRESULTs from script languages that implement COM interfaces

Groove's script host provides an object called GrooveErrorFunctions that you can use call the SetCurrentError method with an HRESULT value and string description.  The effect is that an exception is thrown to the caller with the value/description, so the caller should have exception handling code around the method call.

Example
function FindPerson
      (
      i_FirstName,
      i_LastName
      )
   {
   if (i_FirstName == "")
      {
      //   Return E_INVALIDARG (hex value = 0x80000003, integral value = -2147024809) 
      GrooveErrorFunctions.SetCurrentError(-2147024809, "First name required!");
      return;
      }

   if (i_LastName == "")
      {
      //   Return E_INVALIDARG (hex value = 0x80000003, integral value = -2147024809) 
      GrooveErrorFunctions.SetCurrentError(-2147024809, "Last name required!");
      return;
      }

   var Person = null;

   try
      {
      //   Some code here to find person
      }
   catch (e)
      {
      //   Return E_FAIL (hex value = 0x80004005, integral value = -2147467259) 
      GrooveErrorFunctions.SetCurrentError(-2147467259, "Unexpected error!");
      return;
      }

   return Person;
   }
8:50:12 AM    comment []

Monday, September 09, 2002

Use globals in script sparingly, as it affects performance

Whenever a variable is referenced in script code, the context of the variable is determined first, which means some sort of lookup.  The use of a local variable reduces the surface area of the the lookup to the current function/method, while a global variable has the surface area of the entire CDATA section.

The following list of ways to store global data is prioritized, with the first item being the most performant and the last item being the least performant:
  1. GrooveRunTimeData (ScriptFreeThreadedComponent only)
  2. SharedObjectTable
  3. Global variables


8:25:32 AM    comment []

Thursday, September 05, 2002

Use the existence of properties/attributes as a boolean value rather than the actual value.

Instead of writing code like this:

   PropertyList.SetProperty("Initialized", true);
   .
   .
   var Initialized = false;
   if (PropertyList.PropertyExists("Initialized"))
      Initialized = PropertyList.OpenValue("Initialized");
   .
   .

Write code like this:

   PropertyList.SetProperty("Initialized", true);
   .
   .
   var Initialized = PropertyList.PropertyExists("Initialized");
   .
   .


8:56:00 AM    comment []

Tuesday, August 27, 2002

Watch out for redundant event subscriptions when using Groove's ScriptHost components

If you define a component connection for Groove's ScriptHost components, the events provided by the component are automatically subscribed to:

   <g:ComponentConnections>
      <g:Connection ConnectionID="0" Name="MyDataModelDelegate"/>
   </g:ComponentConnections>

In the case above, event handlers can be implemented in JavaScript by defining functions that use "MyDataModelDelegate_" as a prefix (e.g. "function MyDataModelDelegate_OnSomeEvent").

If you have JavaScript code defined in the code block that attempts to manually subscribe for events using the ConnectObject/Advise method, you will be providing the prefix for defining functions.

   function Initialize ()
      {
      var pITool = PropertyList.OpenProperty(PROPERTY_TOOL);
      var pIDelegateComponent = pITool.OpenDelegateComponent();
      var pIMyDataModelDelegate = pIDelegateComponent.IMyDataModelDelegate;
      ConnectObject(pIMyDataModelDelegate, "pIMyDataModelDelegate_", true);
      }

In the case above, event handlers can be implemented in JavaScript by defining functions that use "pIMyDataModelDelegate_" as a prefix (e.g. "function pIMyDataModelDelegate_OnSomeEvent").

The problem to watch out for is when you have both a component connection and code that manually subscribes for events from the same component - the ScriptHost component will always perform component connection based event subscriptions first.  Additionally, any subsequent attempts to subscribe for events will not actually do anything, and no errors or warnings will be given.  What this means is that if you only define an event handler for the manual subscription, those events will never get triggered.

9:41:23 AM    comment []

© Copyright 2005 Paresh Suthar.



Click here to visit the Radio UserLand website.
 


January 2005
Sun Mon Tue Wed Thu Fri Sat
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          
Feb   Feb