Page 1 of 3 123 LastLast
Results 1 to 10 of 21

Thread: How to create a C++ COM object for StreetDeck

  1. #1
    Raw Wave god_of_cpu's Avatar
    Join Date
    Jan 2004
    Location
    SilverSpring Maryland
    Posts
    2,960

    How to create a C++ COM object for StreetDeck

    The StreetDeck development enviornment will let you load any standard COM object into it using VB Scripts CreateObject function.

    Alternatively, you may prefer to create a COM addin that StreetDeck can use directly and does not require you to use the scripting engine at all. See Building a .Net Addin for StreetDeck for more information.

    This tutorial will show you how to use Microsoft Visual Studio 2003 to create a COM object that can be loaded by the StreetDeck scripting engine.

    Once created and registered, you can simply load the COM object in StreetDeck by calling CreateObject with the registered name of the object you created and immediatly call methods in it.

    For this tutorial, we will be writing the object in C++ using ATL. You can write this object using a variety of different methods, but for the purposes of this tutorial, we will only be using ATL which greatly simplfies reference counting and other mundane tasks required without it.

    Creating a New Project
    1. Create a new ATL Project in Visual Studio
    Name:  NewProject.JPG
Views: 5133
Size:  40.8 KB



    2. Specify the application settings for the project
    Name:  ApplicationSettings.JPG
Views: 5159
Size:  34.8 KB



    3. Switch to the class view, then right click on "SDCOMObject" and select Add->Class, then select ATL COM+ 1.0 Component.
    Name:  COM+.JPG
Views: 5116
Size:  37.4 KB



    4. Call the object "ExampleObject"
    Name:  ExampleObject.JPG
Views: 5145
Size:  45.0 KB



    5. Click finish and the class will be generate for you.


    6. Make sure you can see the class view then, then...
    • Right click on your IExampleObject interface.
    • Choose Add->Add Method...
    • Call the method "MsgBox"
    • Add a BSTR input parameter called "Description"
    • Add a second BSTR input parameter called "Caption"
    • Click Finish to have the wizard generate the function stub for you

    Name:  AddMethod.JPG
Views: 5140
Size:  36.4 KB



    7. Implement the MsgBox method in ExampleObject.cpp by adding the following code which will show a windows message box (BTW, this is a bad example since you should NEVER show a windows dialog in a real project made for use with StreetDeck Its only being used here for ease of understanding)
    Code:
    STDMETHODIMP CExampleObject::MsgBox(BSTR Description, BSTR Caption)
    {
    	MessageBox(NULL, CString(Description), CString(Caption), MB_OK);
    
    	return S_OK;
    }

    8. Notice the use of CString in the previous code, to use this class, we should include #include <atlstr.h> in our stdafx.h file.



    9. Your object is now complete and ready for testing, compile the project.


    10. Before starting up StreetDeck, we should first get the ProgId of our function that will be used in the CreateObject function called from the development enviornment. To find this id, look in the ExampleObject.rgs file for a line called VersionIndependantProgID, it should look something like this:
    Code:
    VersionIndependentProgID = s 'SDCOMObject.ExampleObject'
    SDCOMObject.ExampleObject is the ProgId to use in the call to CreateObject
    StreetDeck.com Developer (I am Chuck)
    Get StreetDeck at http://www.streetdeck.com
    The Official StreetDeck Forums have moved, please visit us at http://www.streetdeck.com/forum for official support for Streetdeck.

  2. #2
    Raw Wave god_of_cpu's Avatar
    Join Date
    Jan 2004
    Location
    SilverSpring Maryland
    Posts
    2,960

    Using a COM Object from StreetDeck

    1. Startup the StreetDeck development enviornment by going click the shortcut at "Programs | StreetDeck | Tools | Development Enviornment"

    2. Create a new script project by going to "File | New | Script Project"

    3. Create a new scripted module by going to "File | New | Scripted Module". Call it HelloWorld

    4. Goto the toolbox, then double click on "button" and click ok to add it to the module.

    5. Switch to design mode "Panels | Design Mode"

    6. Double click on the new button, it should add a new OnMouseClick event.

    7. At the top of the script editor, select the "Module" component, then choose the OnFirstEnter event to add the event to the script. Now find the OnDestroy event and choose it to add that event to the script.

    8. At the very top of the script, in the global scope, add the following line:
    Code:
    Dim oCOMObject
    9. In the OnFirstEnter event, add the following code to instantiate the COM object the first time the module is viewed (Notice the ProgId from our C++ com object is used):
    Code:
    Set oCOMObject = CreateObject("SDCOMObject.ExampleObject")

    10. In the OnMouseClick event add the following code to call the 1 method we implemented in our COM object:
    Code:
    oCOMObject.MsgBox "Hello World!", "StreetDeck Rules!"
    11. In the OnDestroy event add the following code:
    Code:
    Set oCOMObject = Nothing
    12. You are done, the module should now work and call the MsgBox method of our COM object when you click the button. To test it, goto "Script Project | Start Project"



    Below is the code in its entirety for the HelloWorld.vbs module:
    Code:
    Dim oCOMObject
    
    '*******************************************************************************
    'Button_OnMouseClick
    'DESC: event OnMouseClick - Called when the left mouse button is pressed and released within the panel
    '*******************************************************************************
    Function Button_OnMouseClick(x, y)
    	oCOMObject.MsgBox "Hello World!", "StreetDeck Rules!"
    End Function
    
    
    '*******************************************************************************
    'Module_OnFirstEnter
    'DESC: Called the first time the module is shown
    '*******************************************************************************
    Function Module_OnFirstEnter()
    	Set oCOMObject = CreateObject("SDCOMObject.ExampleObject")	
    End Function
    
    '*******************************************************************************
    'Module_OnDestroy
    'DESC: event OnDestroy - Called when the panel is destroyed
    '*******************************************************************************
    Function Module_OnDestroy()
    	Set oCOMObject = Nothing
    End Function
    StreetDeck.com Developer (I am Chuck)
    Get StreetDeck at http://www.streetdeck.com
    The Official StreetDeck Forums have moved, please visit us at http://www.streetdeck.com/forum for official support for Streetdeck.

  3. #3
    Raw Wave god_of_cpu's Avatar
    Join Date
    Jan 2004
    Location
    SilverSpring Maryland
    Posts
    2,960

    Installing your DigitalMod and COM object on another machine

    Currently, there is limited support for automatically registering a COM object on another machine when the DigitalMod is installed. To distribute your DigitalMod with COM object after making it, you should make sure the COM dll you are using is in the path containing your skin ("Script Project | Browse Project Folder"), then goto "Script Project | Package for Distribution" to create an SDZ package that can be imported by other for StreetDeck.

    After that you must give explicit instructions for the user to run "regsvr32 <Name of your COM file>.dll" to register the COM object before importing the SDZ package.

    Automatic registration of COM object is possible in version 1.0.5.5 of StreetDeck and later. To use this feature, you should create a COM sub folder in your DigitalMod's sub directory. Any dll files found in this sub directory will have regsvr32.exe run on it to register it after the sdz package has been extracted to the user's script directory. i.e. Place all your COM objects in "My Documents\StreetDeck\Scripts\<Your DigitalMod GUID>\COM" to have them register automatically with packaging.
    StreetDeck.com Developer (I am Chuck)
    Get StreetDeck at http://www.streetdeck.com
    The Official StreetDeck Forums have moved, please visit us at http://www.streetdeck.com/forum for official support for Streetdeck.

  4. #4
    Raw Wave god_of_cpu's Avatar
    Join Date
    Jan 2004
    Location
    SilverSpring Maryland
    Posts
    2,960

    Sending Events From your COM Object

    There is currently no direct way to send event calls to VBScript. You can, however, manually trigger events from your COM object by using the GetRef method of VBScript which basically gives you a function pointer, but you have to jump through a bunch of hoops to get it to your COM object and be able to call it.

    If you call GetRef from VBScript, it will try to look up the name of the sub you put in as a parameter and check that it is a valid sub procedure defined in your script it will then create a new IDispatch object which has a default method that points to the sub procedure you passed in. Once you have this object, all you have to do is get it to your COM object and store it so every time you need to fire an event you just have to Invoke the default method of the object.

    To add event calling capability to our previous example
    1. Make sure you can see the class view
    • Right click on your IExampleObject interface
    • Choose Add->Add Method
    • Call the method "SetEventObject"
    • Add a IDispatch* parameter called pDispatch
    • Click Finish to have the wizard generate the function stub for you


    Name:  Adding Events.JPG
Views: 4921
Size:  36.1 KB


    2. Add a private CComPtr<IDispatch> member variable to the CExampleObject. This will store our object interface that we recieve from GetRef in VBScript that points to the sub procedure we want to call when the event fires.
    Code:
    CComPtr<IDispatch> m_pEventObject;

    3. Implement the SetEventMethod to set the event object pointer to reference the passed in IDispatch parameter.
    Code:
    STDMETHODIMP CExampleObject::SetEventMethod(IDispatch* pDispatch)
    {
    	m_pEventObject = pDispatch;
    
    	return S_OK;
    }

    4. To call the event from someplace in the COM object, simply call the Invoke method of the IDispatch event object for the default method. For our example, we will change the message box to a MB_YESNO message box and call our event after we recieve a response from the user. The event will have a single integer argument with the result from the message box.

    Code:
    STDMETHODIMP CExampleObject::MsgBox(BSTR Description, BSTR Caption)
    {
    	int iRetVal = MessageBox(NULL, CString(Description), CString(Caption), MB_YESNO);
    
    	if (m_pEventObject.p != NULL)
    	{
    		VARIANT var;
    		DISPPARAMS dp;
    
    		// Allocate memory for the rgvarg member of the DISPPARAMS struct.
    		dp.rgvarg = new VARIANTARG[1];
    
    		dp.rgvarg[0] = CComVariant((long)iRetVal);
    		// set cArgs to the total number of arguments passed.
    		dp.cArgs = 1;
    		dp.cNamedArgs = 0;
    		HRESULT hr = m_pEventObject->Invoke(0, IID_NULL, LOCALE_USER_DEFAULT,
    					DISPATCH_METHOD,&dp, &var, NULL, NULL);
    		// Delete the memory we allocated above for dp.rgvarg.
    		delete[] dp.rgvarg;
    	}
    
    	return S_OK;
    }

    5. Compile the code and then startup the StreetDeck Development Enviornment and add the following code to the script after the CreateObject function to register the sub as an event with our COM object.
    Code:
    	Set oCOMObject = CreateObject("SDCOMObject.ExampleObject")
    	oCOMObject.SetEventMethod GetRef("TestEvent")

    6. Add the following sub procedure to the script that will be called whenever our event is fired.
    Code:
    Sub TestEvent(iRetVal)
    	Module.MsgBox "Return Value = " & iRetVal, "TestEvent Fired!"
    End Sub
    StreetDeck.com Developer (I am Chuck)
    Get StreetDeck at http://www.streetdeck.com
    The Official StreetDeck Forums have moved, please visit us at http://www.streetdeck.com/forum for official support for Streetdeck.

  5. #5
    Newbie bgallagher's Avatar
    Join Date
    Jul 2006
    Location
    Oceanside, CA.
    Posts
    5

    Unable to create object

    Chuck,

    I seem to have difficutly creating an object using the 'CreateObject' function. I was able to create and register my .NET COM component and it was successfully registered (confirmed with regedit) but an error is thrown when trying to instantiate it. I listed the C# and VBScript code for completing these tasks and hopefully you can verify if I have something set wrong.

    C# Code:

    using System;
    using System.Runtime.InteropServices; // necessary library to use COM attributes

    namespace STIC
    {
    [GuidAttribute("EFDD602A-685A-4e60-BEEB-6D380011EA32")]
    /// <summary>
    /// Class used to adjust the height of the vehicle based upon the user selection
    /// </summary>
    public class HeightCommands
    {
    public HeightCommands()
    {
    }

    /// <summary>
    /// Method used to adjust the rear of the vehicle to the pre-set height(s)
    /// </summary>
    [DispId(1)]
    public static void AdjustRear()
    {
    Globals.KillCurrentCommandAndWait();
    Globals.CurrentCommand = new RearSetCommand();
    }

    /// <summary>
    /// Method used to adjust the front of the vehicle to the pre-set height(s)
    /// </summary>
    [DispId(2)]
    public static void AdjustFront()
    {
    Globals.KillCurrentCommandAndWait();
    Globals.CurrentCommand = new FrontSetCommand();
    }

    /// <summary>
    /// Method used to adjust the vehicle to the pre-set heights
    /// </summary>
    [DispId(3)]
    public static void AdjustAll()
    {
    Globals.KillCurrentCommandAndWait();
    Globals.CurrentCommand = new AllSetCommand();
    }

    VBScript Code:

    Dim obj
    '************************************************* ******************************
    'Control_OnMouseClick
    'DESC: event OnMouseClick - Called when the left mouse button is pressed and released within the panel
    '************************************************* ******************************
    Function Control_OnMouseClick(x, y)
    Set obj = CreateObject(STIC.HeightCommands)
    End Function

    Error Thrown:

    Object Required: 'STIC'

  6. #6
    Raw Wave god_of_cpu's Avatar
    Join Date
    Jan 2004
    Location
    SilverSpring Maryland
    Posts
    2,960
    You should put "STIC.HeightCommands" in quotes
    StreetDeck.com Developer (I am Chuck)
    Get StreetDeck at http://www.streetdeck.com
    The Official StreetDeck Forums have moved, please visit us at http://www.streetdeck.com/forum for official support for Streetdeck.

  7. #7
    Newbie bgallagher's Avatar
    Join Date
    Jul 2006
    Location
    Oceanside, CA.
    Posts
    5
    Thanks for reviewing the code. It always seems to be the simplest mistakes.

  8. #8
    Newbie bgallagher's Avatar
    Join Date
    Jul 2006
    Location
    Oceanside, CA.
    Posts
    5

    Subscribing to .NET Events

    ************************************************** *******
    Then you should just have to call it in vbscript with
    Set oCOMObject = CreateObject("SDCOMObject.ExampleObject")
    Set oCOMObject.OnEvent = GetRef("SDCOMObject_OnEvent")
    ************************************************** *******
    Chuck, after reviewing the article you provided in regards to exposing .NET events to COM clients, I've been unsuccessful referencing them. Here are the steps and code I implemented into the .NET event(s) in my component to expose them:

    1. Created an interface that contained the method names and signatures of
    my .NET events.
    2. Used the InterfaceType attribute to mark the interface as an IDispatch
    interface.
    3. Used the ComSourceInterfaces attribute on my .NET object to define the
    interface as the "source" interface for COM events.

    Code in C#:
    namespace STIC
    {
    [Guid("33577CD0-785C-4a35-A969-48C7F69985EF")]
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatc h)]
    public interface IAirRideEvents
    {
    [DispId(1)]
    void PositionChanged();
    }

    [ComSourceInterfaces(typeof(IAirRideEvents))]
    public class AirBag
    {
    public delegate void PositionChangedEventHandler();
    public event PositionChangedEventHandler PositionChanged;
    }
    }

    VBScript Code:

    Set pos = CreateObject("STIC.AirBag")
    Set pos.PositionChanged = GetRef("STIC_PositionChanged")

    The error thrown is, "Object does not support this method or property". Am I calling the GetRef function wrong in the script to subscribe to the event?

    -Brian

  9. #9
    Newbie
    Join Date
    Aug 2006
    Posts
    51
    I can't figure out how to receive com events either..

  10. #10
    Raw Wave god_of_cpu's Avatar
    Join Date
    Jan 2004
    Location
    SilverSpring Maryland
    Posts
    2,960
    Code to add events to the example have been added above
    StreetDeck.com Developer (I am Chuck)
    Get StreetDeck at http://www.streetdeck.com
    The Official StreetDeck Forums have moved, please visit us at http://www.streetdeck.com/forum for official support for Streetdeck.

Page 1 of 3 123 LastLast

Similar Threads

  1. Open Source Skin Editor for RR
    By lbooker in forum Road Runner
    Replies: 66
    Last Post: 04-16-2007, 01:51 AM
  2. found in fperrorlog
    By 510SX in forum FP Bug Reports
    Replies: 3
    Last Post: 09-21-2006, 08:01 AM
  3. Access 2003 help needed
    By veedubya in forum Off Topic
    Replies: 2
    Last Post: 05-31-2006, 06:49 PM
  4. Bug Reports 1.09
    By frodobaggins in forum FrodoPlayer
    Replies: 279
    Last Post: 10-22-2004, 10:24 PM
  5. Bug Reports
    By frodobaggins in forum FrodoPlayer
    Replies: 168
    Last Post: 10-16-2004, 12:25 AM

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •