ActiveX - CREATEOBJECT and singleton pattern

ActiveX - CREATEOBJECT and singleton pattern

Postby metro2 » Tue Sep 28, 2021 9:50 am

I need to connect the POS device TPS900 to a POS application that is done with FWH / xHarbour. The TPS900 vendor has created a software interface as a COM component with functions to communicate with the TPS900 (C #).
So far, I have used the CREATEOBJECT function very successfully for account fiscalization as well.

Example, how I used CREATEOBJECT.

Class1.cs (c#)
Code: Select all  Expand view  RUN
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyTest
{

    public class HelloWord
        {
        public String SayHello(string test)
            {
            return test;  
            }
        }
}
 


register.bat
C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm /codebase C:\Users\Dubravko\source\repos\MyTest\MyTest\bin\Debug\MyTest.dll

Code: Select all  Expand view  RUN

       //Test.prg
      //==========================================  My Test ActiveX
      Public oPOS
      Local ret := ““

      oPOS   := CREATEOBJECT("MyTest.HelloWord")             //    namespace->MyTest  public class->HelloWord

      alert(valtype(oPOS))                                                            // "O"

      ret := oPOS:SayHello("I'm here !!!!!!")

      alert( ret )                                                                             // -> " I'm here !!!!!!"
     
      //==========================================

 



I received an email from the equipment supplier saying that they use a singleton pattern to manage and control instances of Bluetooth connections and suggest that I use the factory method BluetoothConnector.GetInstance (string serviceGuid)

[ Mail ] Greeting,
I am sending a reworked dll, it should work now. The problem was probably that COM registration required the class to have a public default constructor, and since we use a singleton pattern (to manage and control instances of Bluetooth connections), the constructor was private. In any case, do not use the constructor for the BluetoothConnector class (there is only for COM registration), but instead use the factory method BluetoothConnector.GetInstance (string serviceGuid) to create, and retrieve an instance of BluetoothConnector.


Can anyone help me how to use CREATEOBJECT for factory method
BluetoothConnector.GetInstance (string serviceGuid)

e.g:
oPOS := CREATEOBJECT("BluetoothConnector.GetInstance('TestConnectionDLL()' ) or something ?


Thanks for any help

Regards,

( TestConnectionDLL () is a built-in function in BluetoothConnector.cs
Returns what we sent as an argument. )

BluetoothConnector.cs
Code: Select all  Expand view  RUN

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using InTheHand.Net;
using InTheHand.Net.Bluetooth;
using InTheHand.Net.Sockets;
using Newtonsoft.Json;

namespace PaymentService
{
  public class BluetoothConnector
  {
    private static BluetoothConnector _instance = null;
    private static readonly object lockObj = new object();

    private BluetoothClient _client;
    private List<BluetoothDeviceInfo> _availableDevices = new List<BluetoothDeviceInfo>();
    private BluetoothDeviceInfo _selectedDevice = null;
    private string _serviceGuid;

    BluetoothConnector()
    {
      this._client = new BluetoothClient();
    }

    private string ServiceGuid
    {
      set
      {
        this._serviceGuid = value;
      }
    }

    public static BluetoothConnector GetInstance(string serviceGuid)
    {
      if (_instance == null)
      {
        lock (lockObj)
        {
          if (_instance == null)
          {
            _instance = new BluetoothConnector();
            _instance.ServiceGuid = serviceGuid;
          }
        }
      }
      return _instance;
    }

    /// <summary>
    /// Looks up for all available bluetooth devices near by.
    /// </summary>
    /// <returns>Returns a list of devices found.</returns>
    public IReadOnlyCollection<PaymentDevice> FindAvailableDevices()
    {
      List<PaymentDevice> devicesList = new List<PaymentDevice>();
      var devices = this._client.DiscoverDevices();
      foreach (var dev in devices)
      {
        _availableDevices.Add(dev);

        PaymentDevice d = new PaymentDevice()
        {
          DeviceName = dev.DeviceName,
          Authenticated = dev.Authenticated,
          DeviceAddress = dev.DeviceAddress.ToUInt64()
        };

        devicesList.Add(d);
      }

      return devicesList.AsReadOnly();
    }

    /// <summary>
    /// Attempts pairing process with the POS terminal device.
    /// </summary>
    /// <param name="device">Device information.</param>
    /// <returns>Returns <b>true</b> if pairing succeeded.</returns>
    public bool Pair(PaymentDevice device)
    {
      bool result = false;

      if (!device.Authenticated)
      {
        result = BluetoothSecurity.PairRequest(device.DeviceAddress, null);
      }
      else
        result = true;

      BluetoothDeviceInfo deviceInfo = _availableDevices.FirstOrDefault(d => d.DeviceAddress.ToUInt64() == device?.DeviceAddress);
      this._selectedDevice = deviceInfo;
      deviceInfo?.Refresh();

      return result;
    }

    /// <summary>
    /// Executes payment transaction against the POS terminal device.
    /// </summary>
    /// <param name="amount">Transaction amount.</param>
    /// <param name="currency">Transaction currency. This parameter is optional and if omitted, "HRK" is used as default.</param>
    /// <returns>Transaction execution result details.</returns>
    public ResponsePay Pay(decimal amount, string currency = "HRK")
    {
      this.ConnectClient();

      var stream = _client.GetStream();
      StreamWriter sw = new StreamWriter(stream, System.Text.Encoding.UTF8);

      ResponsePay responseObject = null;

      try
      {
        var obj = new
        {
          requestId = Guid.NewGuid().ToString().ToLower(),
          method = "pay",
          parameters = new { amount, currency }
        };
        var objectJson = JsonConvert.SerializeObject(obj);
        sw.WriteLine(objectJson);
        sw.Flush();

        string response;

        if (stream.CanRead)
        {
          using (StreamReader sr = new StreamReader(stream))
          {
            response = sr.ReadLine();
            responseObject = JsonConvert.DeserializeObject<ResponsePay>(response);
          }
        }
      }
      catch (Exception ex)
      {
        throw new InvalidOperationException(ex.Message);
      }

      return responseObject;
    }

    /// <summary>
    /// Executes payment transaction against the POS terminal device.
    /// </summary>
    /// <param name="transactionId">Transaction identifier.</param>
    /// <returns>Transaction cancellation execution result details.</returns>
    public ResponsePay Cancel(string transactionId)
    {
      this.ConnectClient();

      var stream = _client.GetStream();
      StreamWriter sw = new StreamWriter(stream, System.Text.Encoding.UTF8);

      ResponsePay responseObject = null;

      try
      {
        var obj = new
        {
          requestId = Guid.NewGuid().ToString().ToLower(),
          method = "cancel",
          parameters = new { transactionId }
        };
        var objectJson = JsonConvert.SerializeObject(obj);
        sw.WriteLine(objectJson);
        sw.Flush();

        string response;

        if (stream.CanRead)
        {
          using (StreamReader sr = new StreamReader(stream))
          {
            response = sr.ReadLine();
            responseObject = JsonConvert.DeserializeObject<ResponsePay>(response);
          }
        }
      }
      catch (Exception ex)
      {
        throw new InvalidOperationException(ex.Message);
      }

      return responseObject;
    }

    /// <summary>
    /// Tests a bluetooth connection against the paired device and its registered service.
    /// </summary>
    /// <returns>Response with the test result.</returns>
    public Response TestConnection()
    {
      this.ConnectClient();

      var stream = _client.GetStream();
      StreamWriter sw = new StreamWriter(stream, System.Text.Encoding.UTF8);

      Response responseObject = null;

      try
      {
        var obj = new
        {
          requestId = Guid.NewGuid().ToString().ToLower(),
          method = "test",
          parameters = new { data = "testData" }
        };
        var objectJson = JsonConvert.SerializeObject(obj);
        sw.WriteLine(objectJson);
        sw.Flush();

        string response;

        if (stream.CanRead)
        {
          using (StreamReader sr = new StreamReader(stream))
          {
            response = sr.ReadLine();
            responseObject = JsonConvert.DeserializeObject<Response>(response);
          }
        }
      }
      catch (Exception ex)
      {
        throw new InvalidOperationException(ex.Message);
      }

      return responseObject;
    }

    private void ConnectClient()
    {
      if (!_client.Connected)
      {
        _client.Connect(_selectedDevice.DeviceAddress, Guid.Parse(_serviceGuid));
      }
      if (!_client.Connected || _client.PairedDevices.Count() == 0)
      {
        throw new InvalidOperationException("Niste spojeni na niti jedan uređaj. Pokrenite spajanje/uparivanje.");
      }
    }
  }
}

 
metro2
 
Posts: 12
Joined: Tue Sep 07, 2021 4:34 am
Location: Croatia

Re: ActiveX - CREATEOBJECT and singleton pattern

Postby Antonio Linares » Tue Sep 28, 2021 11:16 am

Please build FWH\samples\olebrow.prg and inspect the DLL OLE class that you want to use and paste here what you get

Example:
Image
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42117
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: ActiveX - CREATEOBJECT and singleton pattern

Postby metro2 » Tue Sep 28, 2021 12:40 pm

Thank you for the quick response

I hope that's what you were looking for

Image


Registry
Image
metro2
 
Posts: 12
Joined: Tue Sep 07, 2021 4:34 am
Location: Croatia

Re: ActiveX - CREATEOBJECT and singleton pattern

Postby Antonio Linares » Tue Sep 28, 2021 3:52 pm

Please double click on the highligthed (blue) line to show its info
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42117
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: ActiveX - CREATEOBJECT and singleton pattern

Postby metro2 » Tue Sep 28, 2021 4:14 pm

Image
metro2
 
Posts: 12
Joined: Tue Sep 07, 2021 4:34 am
Location: Croatia

Re: ActiveX - CREATEOBJECT and singleton pattern

Postby Antonio Linares » Tue Sep 28, 2021 4:18 pm

We need the complete list

Please click on Print or Excel to get it
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42117
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain


Re: ActiveX - CREATEOBJECT and singleton pattern

Postby Giovany Vecchi » Wed Sep 29, 2021 1:03 am

Download this utility to see the registered classes of activex and olecom components.

https://www.mitec.cz/Downloads/OLExp.zip
User avatar
Giovany Vecchi
 
Posts: 223
Joined: Mon Jun 05, 2006 9:39 pm
Location: Brasil

Re: ActiveX - CREATEOBJECT and singleton pattern

Postby metro2 » Wed Sep 29, 2021 6:05 am

Thank you
Yes, all 4 classes are visible



http://www.inteh-app.com/app/ActiveX_scr4.png
metro2
 
Posts: 12
Joined: Tue Sep 07, 2021 4:34 am
Location: Croatia

Re: ActiveX - CREATEOBJECT and singleton pattern

Postby Antonio Linares » Wed Sep 29, 2021 7:38 am

metro2 wrote:Image


Is Invoke() the latest entry in the list ? The scrollbar seems to have more to show
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42117
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: ActiveX - CREATEOBJECT and singleton pattern

Postby metro2 » Wed Sep 29, 2021 8:24 am

Yes, invoke is the last entry in the list

Image
metro2
 
Posts: 12
Joined: Tue Sep 07, 2021 4:34 am
Location: Croatia

Re: ActiveX - CREATEOBJECT and singleton pattern

Postby Antonio Linares » Wed Sep 29, 2021 9:35 am

Please try this:

local o1 := CreateObject( "PaymentService.BuetoothConnector" )
local o2 := o1:GetInstance()

MsgInfo( ValType( o1 ) )
MsgInfo( ValType( o2 ) )
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42117
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: ActiveX - CREATEOBJECT and singleton pattern

Postby Antonio Linares » Wed Sep 29, 2021 9:40 am

Also please try:

local o2 := o1:Invoke( "GetInstance" )
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42117
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: ActiveX - CREATEOBJECT and singleton pattern

Postby metro2 » Wed Sep 29, 2021 10:21 am

prg:
////////////////////////////////////////////
o1 := CREATEOBJECT("PaymentService.BluetoothConnector") // ok
MsgInfo( ValType( o1 ) ) // -> "O"

o2 := o1:GetInstance() // error

MsgInfo( ValType( o2 ) )
////////////////////////////////////////////

error.log
Application
===========
Path and name: G:\FWH_PRG\MetroTRG\metrotrg.exe (32 bits)
Size: 3,663,872 bytes
Time from start: 0 hours 0 mins 10 secs
Error occurred at: 29.09.2021, 12:16:07
Error description: Error PaymentService.BluetoothConnector/0 S_OK: GETINSTANCE
Args:

Stack Calls
===========
Called from: => TOLEAUTO:GETINSTANCE(0)
Called from: kasa001.prg => KASASTART(65)
Called from: G:\FWH_PRG\metroTRG\main.prg => (b)MAIN(298)
Called from: btnbmp.prg => TBTNBMP:CLICK(463)
Called from: btnbmp.prg => TBTNBMP:LBUTTONUP(658)
Called from: => TWINDOW:HANDLEEVENT(0)
Called from: .\source\classes\CONTROL.PRG => TCONTROL:HANDLEEVENT(1483)
Called from: btnbmp.prg => TBTNBMP:HANDLEEVENT(1437)
Called from: .\source\classes\WINDOW.PRG => _FWH(3391)
Called from: => WINRUN(0)
Called from: .\source\classes\WINDOW.PRG => TWINDOW:ACTIVATE(976)
Called from: clas_metro.prg => TMETRO:ACTIVATE(55)
Called from: G:\FWH_PRG\metroTRG\main.prg => MAIN(380)

System
======
CPU type: Intel(R) Core(TM) i7-3610QM CPU @ 2.30GHz -137438 Mhz
Hardware memory: 2048 megs

Free System resources: 90 %
GDI resources: 90 %
User resources: 90 %

Compiler version: xHarbour build 1.2.1 Intl. (SimpLex) (Rev. 9382)
Windows version: 6.2, Build 9200
metro2
 
Posts: 12
Joined: Tue Sep 07, 2021 4:34 am
Location: Croatia

Re: ActiveX - CREATEOBJECT and singleton pattern

Postby metro2 » Wed Sep 29, 2021 10:27 am

////////////////////////////////////////////
o1 := CREATEOBJECT("PaymentService.BluetoothConnector") // ok
MsgInfo( ValType( o1 ) ) // -> "O"

local22 := o1:Invoke( "GetInstance" )

MsgInfo( ValType( local22 ) ) // N

MsgInfo( str( local22 ) ) // 244252684

o2 := o1:GetInstance() // error

MsgInfo( ValType( o2 ) )


////////////////////////////////////////////
metro2
 
Posts: 12
Joined: Tue Sep 07, 2021 4:34 am
Location: Croatia

Next

Return to FiveWin for Harbour/xHarbour

Who is online

Users browsing this forum: No registered users and 49 guests