Blog Image

guivi

About the blog

In this blog I will keep track of projects I develop though out this year and may be in the future. For now it is juts a testing ground for developing the blog itself but I hope as I put more material it will become a good place for me to hold information.

OpenGL Things

C/C++ Programming Posted on 23 Aug, 2021 09:12:33

Nice tutorials on modern OpenGL version 3:
https://github.com/SonarSystems/Modern-OpenGL-Tutorials



Email sending with libcurl

C/C++ Programming Posted on 23 Aug, 2021 09:00:24

https://curl.se/libcurl/c/smtp-mail.html



Create a C# control from MFC one.

C/C++ Programming, Visual Studio Posted on 21 May, 2021 09:15:57

Making MFC controls available for WinForms through MFC subclassing

When trying to figure out how to use some of my MFC controls in a WinForms application, I came across this article by Rama Krishna Vavilala. As his article was targetting the .NET 1.1 framework, I decided to rework it for .NET 2.0. The main difference is the switch from using Managed Extension for C++ to using C++/CLI.

Static Win32 library for C3DMeterCtrl

As is the case in Rama’s article, I will also use Mark C. Malburg’s Analog Meter Control. So first, create a Win32 static library project with support for MFC and precompiled headers called “ControlS” (S stands for static). This will contain the MFC code for the existing 3DMeterCtrl control. Place the files 3DMeterCtrl.cpp, 3DMeterCtrl.h and MemDC.h in the “ControlS” project. Modify the 3DMeterCtrl.cpp file to remove the line #include “MeterTestForm.h”.

The .NET designer and runtime will call functions that try to talk to your MFC control even before its window handle is created. In case of the C3DMeterCtrl, I needed to add this function call at the beginning of the “UpdateNeedle” and “ReconstructControl” functions:

if (!GetSafeHwnd())
  return;

MFC library for the managed ‘ThreeDMeter’ control

To bridge the gap between MFC and .NET I’m going to use C++/CLI. This allows me to create a managed wrapper object around the MFC control.

Add an “MFC DLL” project, called “control”. Go to the project properties and enable the common language runtime support (/clr). Using the “Add Class” wizard add a new control and call it “ThreeDMeter”. Make these changes to the ThreeDMeter.h file:

  • #include the header file of the MFC control “..\ControlS\3DMeterCtrl.h”
  • Change the inheritance of the control to public System::Windows::Forms::Control
  • Add a private instance of C3DMeterCtrl to the class. Create it in the constructor and delete it in the finalizer. In “OnHandleCreated”, call its “SubclassWindow” method using the .NET controls window handle.

The file “ThreeDMeter.h” should now look like this:

#pragma once

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

#include "..\ControlS\3DMeterCtrl.h"

namespace Control {

public ref class ThreeDMeter : public System::Windows::Forms::Control
{
public:
ThreeDMeter(void)
{
  InitializeComponent();
  m_pCtrl = new C3DMeterCtrl();
}

protected:
//Finalizer
!ThreeDMeter()
{
  if (m_pCtrl != NULL)
  {
    delete m_pCtrl;
    m_pCtrl = NULL;
  }
}

//Destructor
~ThreeDMeter()
{
  if (components)
  {
    delete components;
  }

  //call finalizer to release unmanaged resources.
  this->!ThreeDMeter();
}

virtual void OnHandleCreated(EventArgs^ e) override
{
  System::Diagnostics::Debug::Assert(m_pCtrl->GetSafeHwnd() == NULL);

  m_pCtrl->SubclassWindow((HWND)Handle.ToPointer());

  Control::OnHandleCreated(e);
}

private:
System::ComponentModel::Container ^components;
C3DMeterCtrl* m_pCtrl;
};

In order to expose the properties of the MFC control in .NET, you need to implement them yourself. Add following code in the public section of the ThreeDMeter wrapper class.

event EventHandler^ OnValueChanged;

[property: System::ComponentModel::CategoryAttribute("Meter")]
property Color NeedleColor
{
  Color get()
  {
    if( m_pCtrl == NULL )
      throw gcnew ObjectDisposedException(ThreeDMeter::GetType()->ToString());
  
    return System::Drawing::ColorTranslator::FromWin32(m_pCtrl->m_colorNeedle);
  }
  
  void set(Color clr)
  {
    if (!m_pCtrl)
      throw gcnew ObjectDisposedException(ThreeDMeter::GetType()->ToString());
  
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
  
    m_pCtrl->SetNeedleColor(ColorTranslator::ToWin32(clr));
  }
}

[property: System::ComponentModel::CategoryAttribute("Meter")]
property String^ Units
{
  void set(String^ units)
  {
    if (!m_pCtrl)
      throw gcnew ObjectDisposedException(ThreeDMeter::GetType()->ToString());
  
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
  
    CString strUnits(units);
  
    m_pCtrl->SetUnits(strUnits);
  }
  
  String^ get()
  {
    if (!m_pCtrl)
      throw gcnew ObjectDisposedException(ThreeDMeter::GetType()->ToString());
  
    LPCTSTR szUnits = (m_pCtrl->m_strUnits);
  
    return gcnew String(szUnits);
  }
}

[property: System::ComponentModel::CategoryAttribute("Meter")]
property double Value
{
  double get()
  {
    if (!m_pCtrl)
      throw gcnew ObjectDisposedException(ThreeDMeter::GetType()->ToString());
  
    return m_pCtrl->m_dCurrentValue;
  }
  
  void set(double d)
  {
    if (!m_pCtrl)
      throw gcnew ObjectDisposedException(ThreeDMeter::GetType()->ToString());
  
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
  
    m_pCtrl->UpdateNeedle(d);
  
    OnValueChanged(this, EventArgs::Empty);
  }
}

.NET Test application

In order to test the managed ThreeDMeter control, add a .NET “Windows application” project to the solution in your favorite language. Put the Three3Meter control on the form and add a timer control

Public Class Form1
  Private Sub Timer1_Tick(ByVal sender As System.Object, 
                          ByVal e As system.EventArgs) Handles Timer1.Tick

    If Me.ThreeDMeter1.Value <= 4 Then
      Me.ThreeDMeter1.Value += (Me.Timer1.Interval / 1000)
    Else
      Me.ThreeDMeter1.Value = -5
    End If
  End Sub
End Class

Reference:

This is a copy past from another webpage. None of this is my work I just want to make sure I can access this as I found it very useful. The original can be found here:
http://bartjolling.blogspot.com/2008/11/developing-windows-forms-control-using.html



Simple Serial Data Parser Simulated

Arduino, C/C++ Programming Posted on 19 May, 2021 21:00:34
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//#define _DEBUG

const char data[] = "adssdfl;jk$OTAQ1#adssdfl;jk$OTAQ1#123,command,command"
"*FFFF1234\r\nadssdfl;jk$OTAQ1#adssdfl;jk$OTAQ1#123,command,command*FFFF1234";    // Simulated serial string.
const char initial_token = '$'; // Start token on the datastring for our formated string. The format is "$....*FFFF".
const int max_size = 64;        // Maximum niber of bytes which can be part of a message.
char buffer[256];               // Temporary buffer to keep track of date from the serial port.
//char mesage[256];               // Message if any is found with the structure as described above.
bool initial_flag = false;      // Flag to indicate if an initial token has been found.
int counter = 0;                // counter to keep trak of the position in the buffer.

// Parses the messge into its components
void Parse(char* message)
{
    char limits[] = "$#,*";     // Use '$', '#', ',' and '*' are the parsing. 
    char* token = strtok(message, limits);
    while (token != NULL)
    {
        printf("%s\r\n", token);
        token = strtok(NULL, limits);
    }
}

// Identify the message from the strings of char's
void ReadMessage(char c)
{
    // if initialization flag is true then add teh character to teh buffer
        if (initial_flag)
        {
            buffer[counter] = c;    // Add the current character to the buffer.
            counter++;              // increase counter.
            char sum[5] = {0};
            char message[256] = {0};
#ifdef _DEBUG
            printf("%s\r\n", buffer);
#endif
            if(sscanf(buffer, "$%[^*]*%4s", message, sum) == 2){
                int _size  = strlen(sum);
#ifdef _DEBUG 
                printf("number of chars in sum %d\r\n", _size);
#endif
                if (_size == 4) // We have dound some data with the desired format.
                {    
                    // Do something with the string
                    printf("Check sum is: %s\r\n", buffer);
                    printf("Message is: %s\r\n", message);
                    Parse(buffer);
                    initial_flag = false;
                }
            }
        }
        // Check if enconter initial chracter. If this is found at any time reinitialize buffer. and set flag accordingly.
        if (c == initial_token)
        {
            printf("Initial token encounter\r\n");
            initial_flag = true;        // Set initialisation flag to true.s
            memset(buffer, 0, 255);     // Setbuffer data to 0.
            buffer[0] = initial_token;  // Put initial toekn in the buffer.
            counter = 1;                // initialize counter to 1 as 0 zero position has already been initialized.
        }
        if (counter >= max_size)        // If number of character in buffer is maximum the de-initialize the flag.
            initial_flag = false;
}

// Main
int main()
{
    int length = strlen(data);              // Get the dta length on the "serial" buffer. Is just for simulation.
    printf("Reading %d from data string\r\n", length);  // Print the length of data for awareness.
    for (size_t i = 0; i < length; i++) {   // Simulated readint one one caracter at the time from the serial port.
        char c = data[i];                   // Get the char form the buffer.
        ReadMessage(c);                     // Add the char to the message buffer and check it it can be parsed.
    }

}


List Video and Audio capture devices

C/C++ Programming, OpenCV & C++ Posted on 30 Apr, 2021 12:47:35
static HRESULT EnumerateDevices(REFGUID category, IEnumMoniker **ppEnum)
{
	// Create the System Device Enumerator.
	ICreateDevEnum *pDevEnum;
	HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
		CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum));

	if (SUCCEEDED(hr))
	{
		// Create an enumerator for the category.
		hr = pDevEnum->CreateClassEnumerator(category, ppEnum, 0);
		if (hr == S_FALSE)
		{
			hr = VFW_E_NOT_FOUND;  // The category is empty. Treat as an error.
		}
		pDevEnum->Release();
	}
	return hr;
}

std::vector<CString> UpdatecameraLists()
{
	IMoniker *pMoniker = NULL;
	CString str;
	LPCTSTR buf;
	HRESULT hr;
	IEnumMoniker *pEnum;
	IPropertyBag *pPropBag;
	VARIANT var;


	hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);

	hr = EnumerateDevices(CLSID_VideoInputDeviceCategory, &pEnum);
	std::vector<CString> _camlist;

	if (SUCCEEDED(hr))
	{
		while (pEnum->Next(1, &pMoniker, NULL) == S_OK)
		{
			hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));
			if (FAILED(hr))
			{
				pMoniker->Release();
				continue;
			}

			VariantInit(&var);

			// Get description or friendly name.
			hr = pPropBag->Read(L"Description", &var, 0);
			if (FAILED(hr))
			{
				hr = pPropBag->Read(L"FriendlyName", &var, 0);
			}
			if (SUCCEEDED(hr))
			{
				str.Format(L"%ls\n", var.bstrVal);
				buf = str;
				_camlist.push_back(str);
				//m_cameras.AddString(buf);
				VariantClear(&var);
			}

			hr = pPropBag->Write(L"FriendlyName", &var);

			// WaveInID applies only to audio capture devices.
			hr = pPropBag->Read(L"WaveInID", &var, 0);
			if (SUCCEEDED(hr))
			{
				printf("WaveIn ID: %d\n", var.lVal);
				VariantClear(&var);
			}

			hr = pPropBag->Read(L"DevicePath", &var, 0);
			if (SUCCEEDED(hr))
			{
				// The device path is not intended for display.
				printf("Device path: %S\n", var.bstrVal);
				VariantClear(&var);
			}

			pPropBag->Release();
			pMoniker->Release();
		}
		pEnum->Release();
	}
	CoUninitialize();

	return _camlist;
}


Check Available Serial Pots

C/C++ Programming Posted on 30 Jan, 2021 23:02:24
void CDialog::SelectComPort()
{
	TCHAR lpTargetPath[5000]; // buffer to store the path of the COMPORTS
	DWORD test;
	bool gotPort = 0; // in case the port is not found
	m_serialList.ResetContent();

	for (int i = 0; i < 255; i++) // checking ports from COM0 to COM255
	{
		CString str;
		str.Format(_T("%d"), i);
		CString ComName = CString("COM") + CString(str); // converting to COM0, COM1, COM2

		test = QueryDosDevice(ComName, lpTargetPath, 5000);

		// Test the return value and error if any
		if (test != 0) //QueryDosDevice returns zero if it didn't find an object
		{
			m_serialList.AddString((CString)ComName); // add to the ComboBox
			
			gotPort = 1; // found port
		}

		if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
		{
			lpTargetPath[10000]; // in case the buffer got filled, increase size of the buffer.
			continue;
		}

	}

	if (!gotPort) // if not port
		m_serialList.AddString((CString)"No Active Ports Found"); // to display error message incase no ports found

}


On Device Arrived/Removed

C/C++ Programming Posted on 30 Jan, 2021 23:01:31
BEGIN_MESSAGE_MAP(CDialog, CDialogEx)
	ON_WM_DEVICECHANGE()
END_MESSAGE_MAP()

BOOL CDialog::OnDeviceChange( UINT wParam, DWORD_PTR  lParam)
{

}


Adding folder to Dll in Visual studio Win32 apps

C/C++ Programming, Visual Studio Posted on 08 Jan, 2021 22:19:01
  1. Go to project properties (Alt+F7)
  2. Under Debugging, look to the right
  3. There’s an Environment field.
  4. Add your relative path there (relative to vcproj folder) i.e. ..\some-framework\lib by appending PATH=%PATH%;$(ProjectDir)\some-framework\lib or prepending to the path PATH=C:\some-framework\lib;%PATH%
  5. Hit F5 (debug) again and it should work.


Next »