C++ with Touchless

Aug 24, 2009 at 3:28 PM

Hello to all, i need to use touchless sdk in one of my school project.

 

I wonder is it possible to use C++ with Touchless sdk rather than C#.

 

Thanks.

Aug 25, 2009 at 8:37 PM

Well,my first Visual C++ program ever... *g*

You can of course use the TouchlessLib project from (visual) C++...

Open the Touchless solution and add a new Visual C++ windows forms application and replace the contents of Form1.h with the code below.

Add a (project) reference to the TouchlessLib project and start your new application.

Place a marker inside the red circle in the camera image and press the "add marker" button. The textbox below the camera picture shows the current marker name, representative color, location and area size.

Hope this helps a bit, maybe someone with more experience in VC++ can make it better and contribute a patch for michael to include in the codeplex project files?


 

#pragma once


namespace touchlessDemo_cpp {

	using namespace System;
	using namespace System::ComponentModel;
	using namespace System::Collections;
	using namespace System::Windows::Forms;
	using namespace System::Data;
	using namespace System::Drawing;

	/// 
	/// Summary for Form1
	///
	/// WARNING: If you change the name of this class, you will need to change the
	///          'Resource File Name' property for the managed resource compiler tool
	///          associated with all .resx files this class depends on.  Otherwise,
	///          the designers will not be able to interact properly with localized
	///          resources associated with this form.
	/// 
	public ref class Form1 : public System::Windows::Forms::Form
	{
	public:
		Form1(void)
		{
			InitializeComponent();
			//
			//TODO: Add the constructor code here
			//
		}

	protected:
		/// 
		/// Clean up any resources being used.
		/// 
		~Form1()
		{
			if (components)
			{
				delete components;
			}
		}
	private: System::Windows::Forms::Label^  label1;
	private: System::Windows::Forms::PictureBox^  pictureBox1;
	private: System::Drawing::Bitmap^ currentCamImage;
	private: System::Windows::Forms::Button^  button1;
	private: TouchlessLib::TouchlessMgr ^mgr;
	private: int markerNum;

	protected: 

	private:

		/// 
		/// Required designer variable.
		/// 
		System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
		/// 
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// 
		void InitializeComponent(void)
		{
			this->label1 = (gcnew System::Windows::Forms::Label());
			this->pictureBox1 = (gcnew System::Windows::Forms::PictureBox());
			this->button1 = (gcnew System::Windows::Forms::Button());
			(cli::safe_cast(this->pictureBox1))->BeginInit();
			this->SuspendLayout();
			// 
			// label1
			// 
			this->label1->Dock = System::Windows::Forms::DockStyle::Bottom;
			this->label1->Location = System::Drawing::Point(0, 286);
			this->label1->Name = L"label1";
			this->label1->Size = System::Drawing::Size(413, 57);
			this->label1->TabIndex = 0;
			this->label1->Text = L"label1";
			// 
			// pictureBox1
			// 
			this->pictureBox1->Dock = System::Windows::Forms::DockStyle::Fill;
			this->pictureBox1->Location = System::Drawing::Point(0, 0);
			this->pictureBox1->Name = L"pictureBox1";
			this->pictureBox1->Size = System::Drawing::Size(413, 286);
			this->pictureBox1->TabIndex = 1;
			this->pictureBox1->TabStop = false;
			this->pictureBox1->Paint += gcnew System::Windows::Forms::PaintEventHandler(this, &Form1::pictureBox1_Paint);
			// 
			// button1
			// 
			this->button1->Dock = System::Windows::Forms::DockStyle::Top;
			this->button1->Location = System::Drawing::Point(0, 0);
			this->button1->Name = L"button1";
			this->button1->Size = System::Drawing::Size(413, 35);
			this->button1->TabIndex = 2;
			this->button1->Text = L"add marker";
			this->button1->UseVisualStyleBackColor = true;
			this->button1->Click += gcnew System::EventHandler(this, &Form1::button1_Click);
			// 
			// Form1
			// 
			this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
			this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
			this->ClientSize = System::Drawing::Size(413, 343);
			this->Controls->Add(this->button1);
			this->Controls->Add(this->pictureBox1);
			this->Controls->Add(this->label1);
			this->Name = L"Form1";
			this->Text = L"Form1";
			this->Load += gcnew System::EventHandler(this, &Form1::Form1_Load);
			this->FormClosed += gcnew System::Windows::Forms::FormClosedEventHandler(this, &Form1::Form1_FormClosed);
			(cli::safe_cast(this->pictureBox1))->EndInit();
			this->ResumeLayout(false);

		}
#pragma endregion
	private: System::Void Form1_Load(System::Object^  sender, System::EventArgs^  e) {
				 this->mgr = gcnew TouchlessLib::TouchlessMgr();

				 this->mgr->CurrentCamera = mgr->Cameras[0];

				 /* this is useful for me, you may need other values */
				 this->mgr->CurrentCamera->RotateFlip = RotateFlipType::RotateNoneFlipX;

				 this->mgr->CurrentCamera->OnImageCaptured += gcnew System::EventHandler(this, &Form1::Cam_NewImage);				 
			 }

	private: System::Void Cam_NewImage(System::Object^  sender, TouchlessLib::CameraEventArgs^  e) {
				 this->currentCamImage = e->Image;
				 this->pictureBox1->Invalidate();
			}

	private: System::Void Marker_Changed(System::Object^  sender, TouchlessLib::MarkerEventArgs^  e) {
				 if (!this->IsDisposed)
				 {
					 if (this->InvokeRequired)
					 {
						 try
						 {
							 /* TODO: ObjectDisposedException occurs here when marker is visible and the program is terminated, but why? */
							 this->Invoke(gcnew EventHandler(this, &Form1::Marker_Changed), sender, e);
						 }
						 catch (Exception^ ex)
						 {
							 /* never mind, the app will be terminated */
						 }
					 }
					 else
					 {
						 Color color = e->EventMarker->RepresentativeColor;
						 
						 if (e->EventData.Present)
						 {
							 this->label1->Text = "Marker " + e->EventMarker->Name +
								 Environment::NewLine +
								 "Color: " + color.ToString() +
								 Environment::NewLine +
								 "Pos (" + e->EventData.X.ToString("0.00") + ", " + e->EventData.Y.ToString("0.00") + ")" +
								 Environment::NewLine +
								 "Area: " + e->EventData.Area.ToString("0.00") + "px";
						 }
						 else
						 {
							 this->label1->Text = "Marker " + e->EventMarker->Name +
								 Environment::NewLine +
								 "Color: " + color.ToString() +
								 Environment::NewLine +
								 "marker is not visible.";
						 }
					 }
				 }
			 }

	private: System::Void pictureBox1_Paint(System::Object^  sender, System::Windows::Forms::PaintEventArgs^  e) {
				 if (!this->IsDisposed)
				 {
					 if (this->currentCamImage != nullptr)
					 {
						Graphics^ g = e->Graphics;

						this->currentCamImage->SetResolution(g->DpiX, g->DpiY);
						int radius = this->currentCamImage->Height / 10;

						g->DrawImage(this->currentCamImage,0,0);

						g->DrawEllipse(Pens::Red, (int)(this->currentCamImage->Width - radius) / 2,
							(int)(this->currentCamImage->Height - radius) / 2, (int)radius, (int)radius);

						g->Flush();
					 }
				 }
			 }

private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
			 
			 if (this->currentCamImage != nullptr)
			 {
				 if (this->mgr->MarkerCount > 0)
				 {
					this->mgr->Markers[0]->OnChange -= gcnew System::EventHandler(this, &Form1::Marker_Changed);
					this->mgr->RemoveMarker(0);
				 }

				 /* generate marker form image center with 10% area (this is only dummy code, user should select the area to use!) */
				 TouchlessLib::Marker^ marker = mgr->AddMarker("marker #" + (++this->markerNum).ToString(),
						 this->currentCamImage,
						 System::Drawing::Point(this->currentCamImage->Width / 2, this->currentCamImage->Height /2),
						 this->currentCamImage->Height / 10);

				 marker->Active = true;
				 marker->OnChange += gcnew System::EventHandler(this, &Form1::Marker_Changed);
			 }
		 }

private: System::Void Form1_FormClosed(System::Object^  sender, System::Windows::Forms::FormClosedEventArgs^  e) {
			 this->mgr->CurrentCamera->OnImageCaptured -= gcnew System::EventHandler(this, &Form1::Cam_NewImage);
			 
			 if (this->mgr->MarkerCount > 0)
			 {
				 this->mgr->Markers[0]->OnChange -= gcnew System::EventHandler(this, &Form1::Marker_Changed);
				this->mgr->RemoveMarker(0);
			 }

			 this->mgr->CurrentCamera = nullptr;
			 this->mgr = nullptr;
		 }
};

}
Aug 27, 2009 at 9:27 AM

Thanks for your post. I wonder it works on C++ and not Visual C++ because i need tp use other library too such as QT or VOIP library.

 

Thanks.

Aug 27, 2009 at 2:47 PM

This is an interesting question for me, too, because I have some legacy C++ projects that currently use a COM-DLL to interop with managed (c#) code.

If you find a way one can directly access managed assemblies from C++ (maybe using a VisualC++ wrapper?) I would greatly appreciate you sharing your solution here...

Aug 28, 2009 at 11:27 AM
Edited Aug 28, 2009 at 11:40 AM

[quote]COM-DLL to interop with managed (c#) code. [/quote]

I think i not asking to access C# dll directly from C++. AFAIK, COm interoperability or PInvoke is the only method.

Can you help ?

Thanks.

http://stackoverflow.com/questions/1046499/how-do-i-call-managed-net-code-from-my-un-managed-c-code-in-windows-and-vice-v

http://www.codeproject.com/KB/dotnet/DllExporter.aspx

http://tigerang.blogspot.com/2008/09/reverse-pinvoke.html

#include"stdafx.h"
 
#import"..\bitlocker\bin\debug\BitLocker.tlb" raw_interfaces_only
usingnamespace BitLocker;
 
int _tmain(int argc, _TCHAR* argv[])
{
  HRESULT hr = CoInitialize(NULL);
 
  try
  {
    //Create the interface pointer.
    IBitLockerOpsPtr pIBitLocker(__uuidof(BitLockerOps));
 
    //Call the method
    long iResult = 5000;
    pIBitLocker->GetBitLockerStatus(&iResult);
  }
  catch( _com_error& ex )
  {
    ATLTRACE( _T("%s\n"), ex.ErrorMessage );
  }
 
  CoUninitialize();
  return 0;
}

 

http://support.microsoft.com/kb/828736

 

 

I got bunch of link from google and i haven't doing any deep research yet.

 

COM Interoperability

http://www.codeproject.com/KB/cs/ManagedCOM.aspx?msg=2538501

CoInitialize(NULL);   //Initialize all COM Components


// <namespace>::<InterfaceName>

MyInterop::IMyDotNetInterfacePtr pDotNetCOMPtr;

// CreateInstance parameters

// e.g. CreateInstance (<namespace::CLSID_<ClassName>)

HRESULT hRes =
pDotNetCOMPtr.CreateInstance(MyInterop::CLSID_MyDotNetClass);
if (hRes == S_OK)
{
BSTR str;
pDotNetCOMPtr->ShowCOMDialog ();
//call .NET COM exported function ShowDialog ()

}

CoUninitialize (); //DeInitialize all COM Components

http://blogs.msdn.com/cbrumme/archive/2003/04/15/51325.aspx
http://bytes.com/topic/c-sharp/answers/229924-dll-development-c-exporting-functions

for that you have to know basic of COM.
then It is very simple to call c# dll in the vc++.
You have to make .TLB (Type Library file) of your original c# DLL and use that
.TLB library in the VC++ code. For that you have to register .TLB file on your pc as well as it is neccessary to import that .TLB file in your vc++ apllication.
When you write C# DLL remember to use interfaces that would be implemented in the class.

 

http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/5345a27a-a614-4a74-9f6d-ea7a999ddf83

http://support.microsoft.com/kb/828736

http://www.codeproject.com/Messages/3022727/How-to-use-Csharp-Managed-DLL-into-my-VCplusplus-Application-DLL.aspx

I hope someone have better approach. 

Anyone can help. I looks for easier approach.

Thanks.

Sep 3, 2009 at 11:04 AM

Thanks for the feedback and sorry for the long delay,

We currently do use the COM approach, but I know how you can do without now (but also not directly):

You can write a managed C++ class library that directly uses the managed c# library and wraps any the function you need.

You have less effort than with COM, you are "out of COM hell" but you have to  write the wrapper that in fact does nothing but call the managed functions and return their results.

Maybe you can find an automatic wrapper generator? this would be great news...

Sep 5, 2009 at 8:21 AM
Thanks for your reply.

I decided to go for CCV library.
Feb 10, 2010 at 11:56 AM

Hi,

I have problem with the code form this thread. I get error:

error C3352: 'void TouchlessTest::Form1::Cam_NewImage(System::Object ^,TouchlessLib::CameraEventArgs ^)' : the specified function does not match the delegate type 'void (System::Object ^,System::EventArgs ^)'

Can someone help?

Feb 13, 2010 at 2:30 PM

Well, the Event handler declaration (and the others and their invocation in my sample, too) use the base class type "EventArgs" instead of the concrete EventArgs class, you should

replace the gcnew EventHandler(...)  with EventHandler<TouchlessLib::CameraEventArgs^>(...) and EventHandler<TouchlessLib::MarkerEventArgs^>(...)  in the code above.

 

HTH,
Florian

Feb 15, 2010 at 12:09 PM

thanks, now it's correct

 

but when i'm trying run my program i have error. is something wrong with my code or .dll ?

See the end of this message for details on invoking
just-in-time (JIT) debugging instead of this dialog box.

************** Exception Text **************
System.EntryPointNotFoundException: Unable to find an entry point named 'Initialize' in DLL 'WebCamLib.dll'.
   at TouchlessLib.NativeMethods.WebCamInitialize()
   at TouchlessLib.TouchlessMgr..ctor()
   at TouchlessTest.Form1.Form1_Load(Object sender, EventArgs e) in e:\mojedokumenty\visual studio 2008\projects\touchlesstest\touchlesstest\form1.h:line 91
   at System.Windows.Forms.Form.OnLoad(EventArgs e)
   at System.Windows.Forms.Form.OnCreateControl()
   at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
   at System.Windows.Forms.Control.CreateControl()
   at System.Windows.Forms.Control.WmShowWindow(Message& m)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
   at System.Windows.Forms.ContainerControl.WndProc(Message& m)
   at System.Windows.Forms.Form.WmShowWindow(Message& m)
   at System.Windows.Forms.Form.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)


************** Loaded Assemblies **************
mscorlib
    Assembly Version: 2.0.0.0
    Win32 Version: 2.0.50727.3603 (GDR.050727-3600)
    CodeBase: file:///C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/mscorlib.dll
----------------------------------------
TouchlessTest
    Assembly Version: 1.0.3698.25289
    Win32 Version:
    CodeBase: file:///E:/MojeDokumenty/Visual%20Studio%202008/Projects/TouchlessTest/Debug/TouchlessTest.exe
----------------------------------------
msvcm90d
    Assembly Version: 9.0.21022.8
    Win32 Version: 9.00.21022.8
    CodeBase: file:///C:/WINDOWS/WinSxS/x86_Microsoft.VC90.DebugCRT_1fc8b3b9a1e18e3b_9.0.21022.8_x-ww_597c3456/msvcm90d.dll
----------------------------------------
System
    Assembly Version: 2.0.0.0
    Win32 Version: 2.0.50727.3053 (netfxsp.050727-3000)
    CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System/2.0.0.0__b77a5c561934e089/System.dll
----------------------------------------
System.Windows.Forms
    Assembly Version: 2.0.0.0
    Win32 Version: 2.0.50727.3053 (netfxsp.050727-3000)
    CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Windows.Forms/2.0.0.0__b77a5c561934e089/System.Windows.Forms.dll
----------------------------------------
System.Drawing
    Assembly Version: 2.0.0.0
    Win32 Version: 2.0.50727.3053 (netfxsp.050727-3000)
    CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Drawing/2.0.0.0__b03f5f7f11d50a3a/System.Drawing.dll
----------------------------------------
System.Configuration
    Assembly Version: 2.0.0.0
    Win32 Version: 2.0.50727.3053 (netfxsp.050727-3000)
    CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Configuration/2.0.0.0__b03f5f7f11d50a3a/System.Configuration.dll
----------------------------------------
System.Xml
    Assembly Version: 2.0.0.0
    Win32 Version: 2.0.50727.3082 (QFE.050727-3000)
    CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Xml/2.0.0.0__b77a5c561934e089/System.Xml.dll
----------------------------------------
TouchlessLib
    Assembly Version: 1.0.0.0
    Win32 Version: 1.0.0.0
    CodeBase: file:///E:/MojeDokumenty/Visual%20Studio%202008/Projects/TouchlessTest/Debug/TouchlessLib.DLL
----------------------------------------

************** JIT Debugging **************
To enable just-in-time (JIT) debugging, the .config file for this
application or computer (machine.config) must have the
jitDebugging value set in the system.windows.forms section.
The application must also be compiled with debugging
enabled.

For example:

<configuration>
    <system.windows.forms jitDebugging="true" />
</configuration>

When JIT debugging is enabled, any unhandled exception
will be sent to the JIT debugger registered on the computer
rather than be handled by this dialog box.

Feb 16, 2010 at 9:47 PM

this sounds like the webcamlib project isn't built. try replacing the reference to the webcamlib project with a reference to the webcamlib in the binaries folder or enable the build for the webcamlib project (I think I remember that the webcamlib project was "unloaded" for me when I tried it the first time, simply right-click and select "load" may help, but I think there were some problems concerning the directX sdk... however, the reference changing will help in that case, too...

Apr 20, 2010 at 9:44 PM

What those errors mean:

TouchlessTest.obj : error LNK2028: unresolved token (0A000020) "extern "C" void __stdcall keybd_event(unsigned char,unsigned char,unsigned long,unsigned long)" (?keybd_event@@$$J216YGXEEKK@Z) referenced in function __catch$?Marker_Changed@Form1@TouchlessTest@@$$FA$AAMXP$AAVObject@System@@P$AAVMarkerEventArgs@TouchlessLib@@@Z$0
TouchlessTest.obj : error LNK2019: unresolved external symbol "extern "C" void __stdcall keybd_event(unsigned char,unsigned char,unsigned long,unsigned long)" (?keybd_event@@$$J216YGXEEKK@Z) referenced in function __catch$?Marker_Changed@Form1@TouchlessTest@@$$FA$AAMXP$AAVObject@System@@P$AAVMarkerEventArgs@TouchlessLib@@@Z$0
Visual Studio 2008\Projects\TouchlessTest\Debug\TouchlessTest.exe : fatal error LNK1120: 2 unresolved externals

I'm trying to use keybd_event(VK_RIGHT, 0, 0, 0); in this program.