C++ Builder: a few problems

Post questions, comments and feedback to our 3Dconnexion Windows Development Team.

Moderator: Moderators

Post Reply
PiotreX
Posts: 7
Joined: Tue Mar 11, 2008 5:36 am

C++ Builder: a few problems

Post by PiotreX »

Hi there!

I'm trying to implement the code used in your SDK Visual C++ files into my program in Borland C++ Builder 6 to communicate with a Space Navigator. I've been on it for a week now. I'll write about the problems I've encountered and maybe you can help me out.

The first try was using the new SDK and just copying the code, copying the ATL files from Visual C++. Of course this didn't work, as the libraries wouldn't compile in C++ Builder.

The second try was using the old static siapp.lib and fellows. The program works, but does not initialize communication with the device. SiOpen returns NULL.

Today's try I used the new SDK libraries after brushing up my knowledge on COM communication, and I have the same problem as with the second try.

Code: Select all

hr = _3DxDevice.CoCreateInstance(__uuidof(Device));
returns a FAILED.

I also have a problem with

Code: Select all

#import "progid:TDxInput.Device.1" no_namespace
as I get " Unable to open import file 'progid:TDxInput.Device.1' ". How does this work in Visual C++, maybe I'll be able to change it to work accordingly.

If you can help me out in any way, please :) I'd be glad if you could point me to someone who's already done this in C++ Builder. I've heard it's been done and posted somewhere but I haven't found it in a week so I'm starting to lose hope...

Cheers,
PiotreX
ngomes
Moderator
Moderator
Posts: 3458
Joined: Mon Nov 27, 2006 7:22 am
Contact:

Post by ngomes »

Hi PiotreX,

TDxInput is a COM server, nothing more. To develop a solution on your project, you need to import the type information.

Can you find anything on importing a COM "type library" on the doc for Builder? For example, you may have an "import" feature for the project itself, rather compiler directives as in Visual C++.
Nuno Gomes
PiotreX
Posts: 7
Joined: Tue Mar 11, 2008 5:36 am

Post by PiotreX »

I have imported the Type Library. Builder made some files from the original dll and I have these included in the project.

I've done something like this:

Code: Select all

Variant Server = Server.CreateObject("TDxInput.Device");
and it seems to have been successful, but i have no idea where to take this next. I'm trying not to use the ATL's because they don't work with Builder(won't compile). Please point me to a direction of thought. I feel depleted at the moment.

Someone told me that the forum used to have a description of how to implement communication in Builder, but i can't seem to find it.

Thanks for the help.
ngomes
Moderator
Moderator
Posts: 3458
Joined: Mon Nov 27, 2006 7:22 am
Contact:

Post by ngomes »

Hi PiotreX,

I think you should (need?) to keep away from the ATL if you're using Builder.

If you're able to instantiate the "device" object, the next steps are to set up the event handlers and to call "connect" to start receiving data. Check the documentation (the PDF file) available on our SDK web page.

Setting up event handlers is again something specific for the dev tool that you use. See if you can find something about IConnectionPoint support in the Builder doc.
PiotreX
Posts: 7
Joined: Tue Mar 11, 2008 5:36 am

Post by PiotreX »

Thanks a lot. I'll look into it tomorrow and come back with more problems ;-)

Cheers!
PiotreX
Posts: 7
Joined: Tue Mar 11, 2008 5:36 am

Eureka!

Post by PiotreX »

I'll start from the top.

For the Space Navigator to work in C++ Builder I suggest the following:

1. Project->Import Type Library->TDxinput.dll and copy the created files to your program dir. include TDxInput_TLB.h

2. Add the SN objects via New->ActiveX->Com Object. Add SimpleDevice, Keyboard, Sensor, Vector3D and AngleAxis. Include the <object>Impl.h files (all five)

3. Declare your objects. Mine are:

Code: Select all

TCOMISimpleDevice Mysz;
TCOMISensor Czujnik;
TCOMIVector3D Wektor;
TCOMIAngleAxis Kat;
TCOMIKeyboard Klaw;
4. Creating the devices and using their properties. This is called by Button1Click which connects the Device, checks if all is OK, and gets the mouse type. The last line writes the Sensor pointer to the Czujnik variable.

Code: Select all

HRESULT hr;
Mysz = CoDevice::Create();
hr = Mysz.Connect();
if (hr==S_OK) Label1->Caption="yes";
else Label1->Caption="no";
Label2->Caption = IntToStr(Mysz.get_Type());
Mysz.get_Sensor(&Czujnik);
5. Don't forget to disconnect after use. OnFormDestroy is probably fine, I'm still using Button2Click:

Code: Select all

bool yes;
HRESULT hr;
if (Mysz)
{
   yes = Mysz.get_IsConnected();
   if (yes==true)
   {
      hr = Mysz.Disconnect();
      if (hr==S_OK) Label1->Caption = "no";
      else Label1->Caption = "yes";
   }
}
This checks if the SN exists, checks if it's connencted, and disconnects it.

End :-)

I'm still trying to figure out how to put in an effective loop, or OnSensorInput event and why get_x is returns 0 whatever the input.
ngomes
Moderator
Moderator
Posts: 3458
Joined: Mon Nov 27, 2006 7:22 am
Contact:

Post by ngomes »

Good stuff, PiotreX. Thanks for reporting back to us. I think the information will be very helpful to other developers using Builder.
PiotreX
Posts: 7
Joined: Tue Mar 11, 2008 5:36 am

Post by PiotreX »

What are the fundamentals for getting info from the Navigator? Do I need to be in a loop with a timer? Because all I seem to get is 0 and 0. in debugger mode when I preview the Vector3D object I get something like:
{X:???; Y:???; Z:???; Length:??? ...} with just Intf:01116F20 and the rest of the properties also ???. What could I be doing wrong? All the objects are correctly initialized.

No rush with this. I'll be back on Monday. Have a nice weekend! Thanks for the help.
ngomes
Moderator
Moderator
Posts: 3458
Joined: Mon Nov 27, 2006 7:22 am
Contact:

Post by ngomes »

Hi PiotreX,

You can either poll (which means you need to be in a loop) or you can set up a handler to listen for events from the "sensor" object.

Which is better?

It really depends on what you're doing. If you already have an animation going on (which means you have a loop), then I suggest the polling method. Otherwise, the event mechanism is the most effecient solution.

As before we have samples on the SDK page -- no Builder proects, unfortunately -- and you can check the doc on the polling mechanism (par of the simple device approach in TDxLib).
PiotreX
Posts: 7
Joined: Tue Mar 11, 2008 5:36 am

Finished

Post by PiotreX »

So I changed a bit of the code, but I got everything in working order. From my last recollection, points 1-3 stay the same. Here's the rest:

4. Initializing and Deinitializing the mouse and it's basic objects:

Code: Select all

void __fastcall TForm1::FormCreate(TObject *Sender)
{
      HRESULT hr;
      Mysz = CoDevice::Create();

      hr = Mysz.Connect();
         if (hr==S_OK) StatusBar1->Panels->Items[0]->Text = "3D mouse connected";
      hr = Mysz.get_Sensor(&Czujnik);
      hr = Mysz.get_Keyboard(&Klaw);
}

Code: Select all

void __fastcall TForm1::FormDestroy(TObject *Sender)
{
     bool yes;
     HRESULT hr;
     if (Mysz)
     {
        yes = Mysz.get_IsConnected();
        if (yes==true)
        {
           hr = Mysz.Disconnect();
           if (hr==S_OK) Label1->Caption = "no";
           else Label1->Caption = "yes";
           Klaw.Release();
           Czujnik.Release();
           Mysz.Release();
        }
     }
}
5. Creating an Idle Loop

Code: Select all

__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
   Application->OnIdle = IdleLoop;
}

Code: Select all

void __fastcall TForm1::IdleLoop(TObject*, bool& done)
{
   done = false;
   if(Klaw)
      {
         try
         {
            VARIANT_BOOL ispressed;
            ispressed = Klaw->IsKeyDown(31);
            if (ispressed == VARIANT_TRUE)
               {
                  Label1->Caption = "Fit";
               }
            else {Label1->Caption = ""; }
         }
         catch (...)
         {
         }
      }
   if(Czujnik)
      {
         try
         {
            Wektor = Czujnik->Translation;
            Kat = Czujnik->Rotation;
            double dlugosc, angle, tx, ty, tz, rx, ry, rz;
            //Getting values:
            //translation vector length
               dlugosc = Wektor->get_Length();
            //rotation angle
               angle = Kat->get_Angle();
            //translation values
               tx = Wektor->get_X();
               ty = Wektor->get_Y();
               tz = Wektor->get_Z();
            //rotation vector values
               rx = Kat->get_X();
               ry = Kat->get_Y();
               rz = Kat->get_Z();

            Label2->Caption = dlugosc;
            Label3->Caption = angle;
            Label10->Caption = tx;
            Label11->Caption = ty;
            Label12->Caption = tz;
            Label13->Caption = rx;
            Label14->Caption = ry;
            Label15->Caption = rz;
         }
         catch (...)
         {}
      }
}

Now on to greater deeds. Implementing OpenGL and trying to rotate objects :-)

Thanks for all the help!
Seabra
Posts: 13
Joined: Thu Feb 28, 2008 10:32 am

Visual C++ 2005 Express Edition

Post by Seabra »

Hi PiotreX,

Do you know what I need to do to set up the libraries needed to read the data from Space Navigator in Visual C++ 2005 Express Edition?

I am developing a similar application like "Puzzle Demo". Do you could help me by providing any source code example? What libraries I need add in my project?

Thanks,

Seabra.
Mark Heaton
Posts: 9
Joined: Sat Jul 26, 2008 4:35 am
Location: Cornwall, UK

Any idea how to do Step 2 under C++ Builder 2007?

Post by Mark Heaton »

Dear PiotrX,
Under C++Builder 2007, when I do Step 2:
2. Add the SN objects via New->ActiveX->Com Object. Add SimpleDevice, Keyboard, Sensor, Vector3D and AngleAxis. Include the <object>Impl.h files (all five)
TAT TWAM ASI
Mark Heaton
Posts: 9
Joined: Sat Jul 26, 2008 4:35 am
Location: Cornwall, UK

cntd

Post by Mark Heaton »

the system creates all sorts of ATL stuff. The 'New' in question is the 'File/New', yes?
TAT TWAM ASI
Mark Heaton
Posts: 9
Joined: Sat Jul 26, 2008 4:35 am
Location: Cornwall, UK

cont 2

Post by Mark Heaton »

I do 'File/New/Other', select ActiveX and COM Object, and click OK. A window opens asking for: CoClass Name: (where I put TCOMSimpleDevice), then it wants a Threading Model, offering Single/Apartment/Free/Both/Neutral (I tried both Apartment (the default) and Single). 'Implemented Inteface:' is filled automatically with the CoClass Name preceded by an 'I', and then 2 buttons 'Generate Event Support Code' and 'Mark Interface Oleautomation' (both of which I unchecked). Does this equate in any way to what you did with C++ Builder Version 6? Any help would be much appreciated;maybe I can return the favour as I have developed an OpenGl system under C++ Builder.
TAT TWAM ASI
Mark Heaton
Posts: 9
Joined: Sat Jul 26, 2008 4:35 am
Location: Cornwall, UK

progress with C++ Builder

Post by Mark Heaton »

Dear Piotrex,
Got all the rest of your code working fine, giving a 'Yes' to Mysz.Connect(), and a '6' from Mysz.get_Type(). It's just on doing 'Mysx.get_Sensor(&Czujnik);' or ''Klav.Release();' or 'Czujnik.Release();' that I get an 'Assertion failed: intf==0,....', presumably cos I haven't managed to install the SimpleDevice etc ActiveX COM Object devices.
Regards,
Mark.
TAT TWAM ASI
Post Reply