3DxWareSDK in a DLL

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

Moderator: Moderators

Post Reply
tmichel
Posts: 3
Joined: Thu Feb 09, 2017 3:05 am

3DxWareSDK in a DLL

Post by tmichel » Thu Feb 09, 2017 3:25 am

Hello,

we've been using the 3d mouse in our project for quite some time, and now a new requirement has come up by which we need to be able to control our 3D view even when the application doesn't have th focus. So when some other GUI has the focus and we operate the 3D mouse, we still need the input from the 3d mouse to be send to our 3d application, if that makes sense. The GUI is not full screen but it will most of the time be on top of the 3d application and have the focus most of the time.

I'm not a winapi wizard but my research showed that if I want to do this, I need to make a DLL where I put the hook function so that I can catch the windows messages on a global scope. That is if I do
SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)MessageHookCB, GetModuleHandle(NULL), NULL)
it will not work, we need to have this MessageHookCB in a new DLL. Fine, let's do that then.

First of all, we are basically making a plugin for some 3d engine, this plugin is a DLL and essentially what we were doing before was something like this:

Code: Select all

bool vrvSpaceMouseDevice::Init(HWND a_hwnd, std::string& a_initResultMessage)
{
  // init the 3DxWare input library 
  if (SiInitialize() == SPW_DLL_LOAD_ERROR)
  {
    a_initResultMessage = "Space Mouse initialization error ! Are you sure drivers are installed ?";
    return false;
  }

  // Init Windows platform specific data
  SiOpenWinInit(&m_oData, a_hwnd);

  // Open data, which will check for device type and return the device handle to be used by this function
  m_hdl = SiOpen("3DxStealth", SI_ANY_DEVICE, SI_NO_MASK, SI_EVENT, &m_oData);
  if (m_hdl == NULL)
  {
    a_initResultMessage = "Space Mouse opening error ! Are you sure device is connected ? ";
    SiTerminate();  // Shut down the SpaceWare input library
    return false;
  }
  else
  {
    m_bSpaceMouseFound = true;
  }

  // Attach Windows Message Pump Hook Callback. 
  if (SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)MessageHookCB, GetModuleHandle(NULL), GetCurrentThreadId()) == NULL)
  {
    a_initResultMessage = "Space Mouse handling error : Unable to setup Message Hook Callback !";
    SiTerminate();  // Shut down the SpaceWare input library
    return false;
  }

  a_initResultMessage = "Space Mouse Initialization successful";
  return true;
}
and the MessageHookCB was in turn essentially calling this:

Code: Select all

  void vrvSpaceMouseDevice::HandleWindowsMessage(MSG* a_lpmsg)
  {
    SiSpwEvent     Event;    // SpaceWare Event
    SiGetEventData eData;    // SpaceWare Event Data
    
    // init Window platform specific data for a call to SiGetEvent
    SiGetEventWinInit(&eData, a_lpmsg->message, a_lpmsg->wParam, a_lpmsg->lParam);

    // check whether msg was a 3D mouse event and process it  
    if (SiGetEvent(m_hdl, 0, &eData, &Event) == SI_IS_EVENT)
    {
      // Axis Motion events
      if (Event.type == SI_MOTION_EVENT)
      {
        m_SpaceMouseData.setAxisData(0, Event.u.spwData.mData[SI_TX] / m_fMaxAxisValue);
        m_SpaceMouseData.setAxisData(1, Event.u.spwData.mData[SI_TY] / m_fMaxAxisValue);
        m_SpaceMouseData.setAxisData(2, Event.u.spwData.mData[SI_TZ] / m_fMaxAxisValue);
        m_SpaceMouseData.setAxisData(3, Event.u.spwData.mData[SI_RX] / m_fMaxAxisValue);
        m_SpaceMouseData.setAxisData(4, Event.u.spwData.mData[SI_RY] / m_fMaxAxisValue);
        m_SpaceMouseData.setAxisData(5, Event.u.spwData.mData[SI_RZ] / m_fMaxAxisValue);
      }

      if (Event.type == SI_ZERO_EVENT)
      {
        m_SpaceMouseData.setAxisData(0, 0);
        m_SpaceMouseData.setAxisData(1, 0);
        m_SpaceMouseData.setAxisData(2, 0);
        m_SpaceMouseData.setAxisData(3, 0);
        m_SpaceMouseData.setAxisData(4, 0);
        m_SpaceMouseData.setAxisData(5, 0);
      }

      // Button Events
      if (Event.type == SI_BUTTON_EVENT)
      {
        int            num;      // number of button pressed
        if ((num = SiButtonPressed(&Event)) != SI_NO_BUTTON)
        {
          switch (num)
          {
          case V3DK_MENU:
            m_SpaceMouseData.setButtonData(0, true);
            break;
          case V3DK_FIT:
            m_SpaceMouseData.setButtonData(1, true);
            break;
          default:
            break;
          }
        }

        if ((num = SiButtonReleased(&Event)) != SI_NO_BUTTON)
        {
          switch (num)
          {
          case V3DK_MENU:
            m_SpaceMouseData.setButtonData(0, false);
            break;
          case V3DK_FIT:
            m_SpaceMouseData.setButtonData(1, false);
            break;
          default:
            break;
          }
        }
      }

      // Disconnection event
      if (Event.type == SI_DEVICE_CHANGE_EVENT)
      {
        switch (Event.u.deviceChangeEventData.type)
        {
        case SI_DEVICE_CHANGE_CONNECT:
          break;
        case  SI_DEVICE_CHANGE_DISCONNECT:
          m_SpaceMouseData.setAxisData(0, 0);
          m_SpaceMouseData.setAxisData(1, 0);
          m_SpaceMouseData.setAxisData(2, 0);
          m_SpaceMouseData.setAxisData(3, 0);
          m_SpaceMouseData.setAxisData(4, 0);
          m_SpaceMouseData.setAxisData(5, 0);
          break;
        default:
          break;
        }
      }
    }
  }
and we had basically those 5 functions that we use to get the Tx, Ty and all those values, which we were calling in order to change the view in our 3d app:

Code: Select all

		
                static float GetTx() { return m_SpaceMouseData.getAxisData(0); }
		static float GetTy() { return m_SpaceMouseData.getAxisData(1); }
		static float GetTz() { return m_SpaceMouseData.getAxisData(2); }
		static float GetRx() { return m_SpaceMouseData.getAxisData(3); }
		static float GetRy() { return m_SpaceMouseData.getAxisData(4); }
		static float GetRz() { return m_SpaceMouseData.getAxisData(5); }
awesome, and this has been working fine. Now my idea was to move all the initialization (and de-initialization) code and the HandleWindowsMessage in a new DLL, as well as also the above GetTx(), GetTy(), functions, and then from my plugin just call those exported GetTx(), GetTy() from that new DLL.

and in our plugin, do something like this: (removed error checking for simplicity's sake)

Code: Select all

HWND hdll = LoadLibrary("3dmouse.dll");
DefaultProc initProc = (DefaultProc)GetProcAddress(hDll, "init");
initProc();
LPGetMsgProc pfnProc = (LPGetMsgProc)GetProcAddress(hDll, "GetMsgProc");
HHOOK hHook = SetWindowsHookEx(WH_GETMESSAGE, pfnProc, hDll, 0);
all this stuff seems to be doing mostly what I want, so the hook seems to be installed properly. The only problem I'm facing at the moment with this approach is that this line fails:
m_hdl = SiOpen("3DxStealth", SI_ANY_DEVICE, SI_NO_MASK, SI_EVENT, &m_oData);

I'm not very familiar with the 3DxWareSDK, this was implemented by someone else in the past, who no longer works for us. So all I know is that m_hdl is NULL but I don't know why this is happening. The exact same code was working fine when I was calling it from the plugin's dll.
any idea what could be going wrong here?

Cheers,

Thomas

jwick
Moderator
Moderator
Posts: 2803
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Re: 3DxWareSDK in a DLL

Post by jwick » Thu Feb 09, 2017 10:05 am

Hello Thomas,

Before you go to all that work, you may be able to use an API function, SiGrabDevice. It tells the driver to send events to you regardless of who has kb focus.

Let us know if this works for you.

tmichel
Posts: 3
Joined: Thu Feb 09, 2017 3:05 am

Re: 3DxWareSDK in a DLL

Post by tmichel » Fri Feb 10, 2017 1:02 am

awesome, that does work and it is also a lot easier :D

Thanks!

Post Reply