How to send parameter to my device using libcam.dll in delphi

0

I have a code in Delphi I using the it to get picture from my 2D Reader, I am using 'camlib.dll' to set parameter of the Image in the device the code:

unit Test_Cam;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TByteArr = array of byte;
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    ComboBox1: TComboBox;



    procedure Button1Click(Sender: TObject);
    procedure Doconnect;
    procedure CamOpen;
    Function StrToByte(const Value: String): TByteArr;
  private
    { Private declarations }


  public
  published
    property ObjectMenuItem;
    { Public declarations }
  end;
  TconfigPort = record
    BaudRate:Integer; // baud rate
    ByteSize:Integer; // number of bits/byte, 4-8
    Parity:Integer; // 0-4=no,odd,even,mark,space
    StopBits:Integer; // 0,1,2 = 1, 1.5, 2
    fOutxCtsFlow:Integer; // CTS Flow Control
  end;

  TPROGRESS_FUNC = procedure (blocks_total,blocks_done:Integer) of Object;

var
  Form1: TForm1;

  Function MetrocomEnterImageUpl(nport:Integer):Boolean; external 'metrocom.dll';
  procedure MetrocomAcquireFullFrame(nport:Integer); external 'metrocom.dll';


  Function MetrocomUploadJpeg(nPort:Integer; PROGRESS_FUNC:Tprogress_func; szFileName:string; nSubsampling:integer):Boolean; stdcall; external 'metrocom.dll';
  Function MetrocomExitImageUpl(nPort:Integer):Boolean; stdcall; external 'metrocom.dll';
  Function MetrocomInitCommunication(nPort:Integer; const  COMMPORTCONFIG:TconfigPort):Boolean;stdcall; external 'metrocom.dll';
  Function MetrocomEndCommunication(nPort:Integer):Boolean; stdcall; external 'metrocom.dll';
  Function camSetImageCompression(cam_handle:Integer; quality:Integer; method:Integer):Integer;stdcall; external 'Camlib.dll';
  Function camSetCenteredWOI(cam_handle:Integer;img_width:Integer;img_height:Integer):Integer; stdcall; external 'Camlib.dll';
  Function camInit(dev_interface:Integer):Integer;  stdcall; external 'Camlib.dll';
  Function camOpenEx2(device_name:TByteArr;ctl_bus_name:TByteArr;Var p_dev_type:Integer; ctl_bus_type:integer; camera_type:integer;dev_bus_type:Integer):Integer; stdcall; external 'Camlib.dll';
  Function camClose(cam_handle:Integer):Integer; stdcall; external 'Camlib.dll';
  Function camFree:Integer; stdcall; external 'Camlib.dll';
  Function camGetOperatingMode(cam_handle:Integer; var mode:Integer):Integer; stdcall; external 'Camlib.dll';

var
  Config_port: TconfigPort;
  m_bConnect:Boolean = false;
  tt,m_nPort,m_nInit,nPort,i,j,m_camHandle:integer;
  nDeviceType:Integer = 0;
  device_name:string;
  szDeviceName:TByteArr;

implementation

{$R *.dfm}

function TForm1.StrToByte(const Value: String): TByteArr;
var
    I: integer;
begin
    SetLength(Result, Length(Value));
    for I := 0 to Length(Value) - 1 do
        Result[I] := ord(Value[I + 1]) ;
end;

procedure Tform1.DoConnect;
begin
 m_nPort := StrToInt(ComboBox1.Text) - 1;
 Config_port.BaudRate := 9600;
 Config_port.ByteSize := 8;
 Config_port.Parity := 0;
 Config_port.StopBits := 0;
 m_bConnect := MetrocomInitCommunication(m_nPort , Config_port);
end;

procedure TForm1.CamOpen;
begin
 m_nInit := camInit(0);
 if m_nInit < 0  then
    ShowMessage('Fail to camInit.');
 nPort := m_nPort + 1;
 device_name := 'COM' + IntToStr(nPort) + ' baud=' + IntToStr(Config_port.BaudRate) + ' parity=' + IntToStr(Config_port.Parity) + ' data=' + IntToStr(Config_port.ByteSize) + ' stop=' + IntToStr(Config_port.StopBits);
 szDeviceName := strtobyte(device_name);
 for i := 0 to 4 do
  begin
   for j := 0 to 4 do
    begin
     m_camHandle := camOpenEx2(szDeviceName, nil ,  nDeviceType, 0, 1, 16);
     if m_camHandle > 0 then break;
    end;
   if m_camHandle > 0 then break;
  end;

end;


procedure TForm1.Button1Click(Sender: TObject);
begin
 DoConnect;
 CamOpen;
 tt := camSetImageCompression(m_camHandle, 30, 2);
 camSetCenteredWOI(m_camHandle, 500, 220);

end;

end.

I get an Erorr in this line and the error occurred after the tow functions is compiled I get an error that 'access violation at 0x000001f4:read of address 0x000001f4' and then opend the CPU debuging in delphi:

 tt := camSetImageCompression(m_camHandle, 30, 2);
 camSetCenteredWOI(m_camHandle, 500, 220);

the description of the function in camlib.dll is:

camSetImageCompression 
This function sets the image compression parameters.
Prototype:
int camSetImageCompression (int cam_handle, int quality, int method);
Parameters:
cam_handle - [in] handle to the camera device returned by the camOpen function.
quality - [in] allowable value of image quality after compression: 1(worst) - 100(best)
method - [in] allowable compression method. Currently, this parameter can be one of the
following values:
CAMLIB_COMPRESS_NONE  no compression;
CAMLIB_COMPRESS_SUBSAMPLE  image resampling down;
CAMLIB_COMPRESS_JPEG  JPEG compression;
CAMLIB_COMPRESS_ANY  any method of compression;
Return Value:
0: Success; -1: Failure

camSetCenteredWOI
This function sets the window of interest (WOI) of the given size centered horizontally and vertically in the
field of view of the camera.
Prototype:
int camSetCenteredWOI (int cam_handle, int img_width, int img_height);
Parameters:
cam_handle - [in] handle to the camera device returned by the camOpen function.
img_width - [in] image width, in pixels.
img_height - [in] image height, in rows.
Return Value:
0: Success; -1: Failure

camOpenEx2
This function establishes communication with the specified camera device.
Prototype:
int camOpenEx2 (char *device_name, char *ctl_bus_name, int *p_dev_type, int ctl_bus_type,
intcamera_type, int dev_bus_type);
Parameters:
device_name   - [in] camera communication device name optionally followed by a device-control
string that contains communication parameters. Currently, the device name must
be a valid serial port. For example, the following string specifies the COM1
communication port, a baud rate of 9600, no parity, 8 data bits, and 1 stop bit:
COM1: baud=9600 parity=N data=8 stop=1. If the communication device is USB
then the device_name parameter should be 0.
ctl_bus_name  - [in] should be NULL.
p_dev_type - [out] (optional) pointer to the location where the function returns the type of image
sensor used in the camera. Currently, this value can only be
CAM_IMG_SENSOR_MT9M001C or CAM_IMG_SENSOR_VC5602 (or
CAM_IMG_SENSOR_UNKNOW N if the sensor type could not be automatically
identified).
ctl_bus_type - [in] should be 0.
camera_type - [in] camera type. Currently, this value can only be
CAMLIB_CAMERATYPE_FOCUS, CAMLIB_CAMERATYPE_ORBIT3 or
CAMLIB_CAMERATYPE_VUQUEST.
dev_bus_type - [in] device bus type. Currently, this value can only be CAMLIB_BUSTYPE_RS232
or CAMLIB_BUSTYPE_USB20.
Return Value:
If positive  handle to the camera device, or (-1) in case of error. The handle must be used in all
consequent calls to CamLib APIs to identify the camera device on which an operation is requested
to be performed.

in C# it is working fine:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Reflection;

namespace Sample
{
    public partial class frmMain : Form
    {
        public struct COMMPORTCONFIG
        {
            public int BaudRate; // baud rate
            public int ByteSize; // number of bits/byte, 4-8
            public int Parity; // 0-4=no,odd,even,mark,space
            public int StopBits; // 0,1,2 = 1, 1.5, 2
            int fOutxCtsFlow; // CTS Flow Control
        }

        [DllImport(@"C:\WINDOWS\metrocom.dll", EntryPoint = "MetrocomEnterImageUpl")]
        extern public static bool MetrocomEnterImageUpl(int nPort);

        [DllImport(@"C:\WINDOWS\metrocom.dll", EntryPoint = "MetrocomAcquireFullFrame")]
        extern public static void MetrocomAcquireFullFrame(int nPort);

        public delegate void PROGRESS_FUNC(int blocks_total, int blocks_done);
        [DllImport(@"C:\WINDOWS\metrocom.dll", EntryPoint = "MetrocomUploadJpeg")]
        extern public static bool MetrocomUploadJpeg(int nPort, PROGRESS_FUNC p_progress_func, char[] szFileName, int nSubsampling);

        [DllImport(@"C:\WINDOWS\metrocom.dll", EntryPoint = "MetrocomExitImageUpl")]
        extern public static bool MetrocomExitImageUpl(int nPort);

        [DllImport(@"C:\WINDOWS\metrocom.dll", EntryPoint = "MetrocomInitCommunication")]
        extern public static bool MetrocomInitCommunication(int nPort, ref COMMPORTCONFIG p_config);

        [DllImport(@"C:\WINDOWS\metrocom.dll", EntryPoint = "MetrocomEndCommunication")]
        extern public static bool MetrocomEndCommunication(int nPort);

        [DllImport(@"C:\WINDOWS\Camlib.dll", EntryPoint = "camSetImageCompression")]
        extern public static int camSetImageCompression(int cam_handle, int quality, int method);

        [DllImport(@"C:\WINDOWS\Camlib.dll", EntryPoint = "camSetCenteredWOI")]
        extern public static int camSetCenteredWOI(int cam_handle, int img_width, int img_height);

        [DllImport(@"C:\WINDOWS\Camlib.dll", EntryPoint = "camInit")]
        extern public static int camInit(int dev_interface);

        [DllImport(@"C:\WINDOWS\Camlib.dll", EntryPoint = "camOpenEx2")]
        public extern static int camOpenEx2(byte[] device_name, byte[] ctl_bus_name, ref int p_dev_type, int ctl_bus_type, int camera_type, int dev_bus_type);

        [DllImport(@"C:\WINDOWS\Camlib.dll", EntryPoint = "camClose")]
        extern public static int camClose(int cam_handle);

        [DllImport(@"C:\WINDOWS\Camlib.dll", EntryPoint = "camFree")]
        extern public static int camFree();

        [DllImport(@"C:\WINDOWS\Camlib.dll", EntryPoint = "camGetOperatingMode")]
        extern public static int camGetOperatingMode(int cam_handle, ref int mode);

        //[DllImport(@"C:\WINDOWS\Camlib.dll", EntryPoint = "camReadData")]
        //extern public static int camReadData (int cam_handle, int ibus,
        //    char *buf,int cb_to_read, int *cb_read,int *fcancel, long ms_timeout,  long ms_idle_timeout);

        [DllImport(@"C:\WINDOWS\metrocom.dll", EntryPoint = "MetrocomReadData")]
        extern public static bool MetrocomReadData(long i_port, string buf, long dw_bufsize, long fcancel,
        long wait_timeout, long read_timeout);

        [DllImport(@"C:\WINDOWS\GetSN.dll", EntryPoint = "CheckValid")]
        extern public static bool CheckValid();

        int m_nPort = -1;
        COMMPORTCONFIG p_config = new COMMPORTCONFIG();
        int m_camHandle = -1;
        int m_nInit = -1;
        bool m_bConnect = false;
        string m_strPath = System.IO.Directory.GetCurrentDirectory();
        int m_nMode = -1;

        public frmMain()
        {
            InitializeComponent();
        }

        private void Connect_Click(object sender, EventArgs e)
        {
            if (Connect.Text.Trim() == "connect")
            {
                DoConnect();
                CamOpen();

                IsConnet();

                camSetImageCompression(m_camHandle, 30, 0x002);
                camSetCenteredWOI(m_camHandle, 500, 220);
                Shapshot.Enabled = true;
                textBox1.Focus();
                //Shapshot_Click(sender, e);
            }
            else
            {
                DoDisconnect();
                CamCloe();
            }
        }

        private void Shapshot_Click(object sender, EventArgs e)
        {
            if (textBox1.Text.Trim() == "")
            {
                MessageBox.Show("chose the name please");
                textBox1.Focus();
            }
            else
            {
                GetOperatingMode();

                if (m_nMode == 0)
                {
                    PROGRESS_FUNC test = new PROGRESS_FUNC(progress_function);
                    bool bResult = MetrocomEnterImageUpl(m_nPort);
                    MetrocomAcquireFullFrame(m_nPort);

                    //string strPath = Application.ExecutablePath;
                    string strFileName = m_strPath + "\\" + textBox1.Text + "1.jpg";

                    char[] szFileName = strFileName.ToCharArray(0, strFileName.Length);
                    bool bTemp = false;

                    if (bResult)
                        bTemp = MetrocomUploadJpeg(m_nPort, test, szFileName, 0);
                }
                MetrocomExitImageUpl(m_nPort);
                if (MessageBox.Show("another Side ", "Take picture",
                    MessageBoxButtons.OKCancel, MessageBoxIcon.Question)
                    == DialogResult.OK)
                {
                    GetOperatingMode();

                    if (m_nMode == 0)
                    {
                        PROGRESS_FUNC test = new PROGRESS_FUNC(progress_function);
                        bool bResult = MetrocomEnterImageUpl(m_nPort);
                        MetrocomAcquireFullFrame(m_nPort);

                        //string strPath = Application.ExecutablePath;
                        string strFileName = m_strPath + "\\" + textBox1.Text + "2.jpg";

                        char[] szFileName = strFileName.ToCharArray(0, strFileName.Length);
                        bool bTemp = false;

                        if (bResult)
                            bTemp = MetrocomUploadJpeg(m_nPort, test, szFileName, 0);

                    }
                    textBox1.Text = "";
                }
            }
        }

        private void frmMain_Load(object sender, EventArgs e)
        {
            string[] szArray = new string[256];
            for (int i = 0; i < szArray.Length; i++)
            {
                szArray[i] = "Com" + i;
            }

            cmbPort.DataSource = szArray;
            cmbPort.SelectedIndex = 3;
            bool valid = CheckValid();
            if (valid == false)
            {

             Application.Exit();
            }

        }

        private void DoConnect()
        {
            string strTemp = cmbPort.Text.Trim();
            string[] parts = strTemp.Split('m');
            m_nPort = Convert.ToInt16(parts[1]) - 1;

            p_config.BaudRate = 9600;
            p_config.ByteSize = 8;
            p_config.Parity = 0;
            p_config.StopBits = 0;

            m_bConnect = MetrocomInitCommunication(m_nPort, ref p_config);
        }

        private void CamOpen()
        {
            m_nInit = camInit(0);

            if (m_nInit < 0)
                MessageBox.Show("Fail to connect");

            int nPort = m_nPort + 1;
            string device_name;
            device_name = "COM" + nPort + " baud=" + p_config.BaudRate + " parity=" + p_config.Parity + " data=" + p_config.ByteSize + " stop=" + p_config.StopBits;
            int nDeviceType = 0;
            int i, j;
            byte[] szDeviceName = System.Text.Encoding.Default.GetBytes(device_name);

            for (i = 0; i < 5; i++)
            {
                for (j = 0; j < 5; j++)
                {
                    m_camHandle = camOpenEx2(szDeviceName, null, ref nDeviceType, 0, 1, 0x0010);
                    if (m_camHandle > 0)
                        break;
                }
                if (m_camHandle > 0)
                    break;
            }

        }

        private void CamCloe()
        {
            if (m_camHandle >= 0)
                camClose(m_camHandle);

            if (m_nInit == 0)
                camFree();
        }

        private void DoDisconnect()
        {
            if (m_bConnect)
                MetrocomEndCommunication(m_nPort);

            Connect.Text = "connect";
            cmbPort.Enabled = true;
        }

        private void IsConnet()
        {
            if (!m_bConnect || m_camHandle <= 0)
                MessageBox.Show("Fail to connect to Fcous.", "UnitechVision");
            else
            {
                cmbPort.Enabled = false;
                Connect.Text = "connected";
            }
        }

        private int GetOperatingMode()
        {
            camGetOperatingMode(m_camHandle, ref m_nMode);

            return m_nMode;
        }

        void progress_function(int blocks_total, int blocks_done)
        {
            blocks_total = 30;
            blocks_done = 50;
        }

        private void frmMain_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (m_camHandle > 0)
                camClose(m_camHandle);

            if (m_nInit == 0)
                camFree();

            if (m_bConnect)
                MetrocomEndCommunication(m_nPort);
        }


        private void button1_Click(object sender, EventArgs e)
        {
            string s = @"d:\12\1.jpg";
            pictureBox1.Load(s);

        }


    }
}
delphi
winapi
delphi-2006
asked on Stack Overflow Oct 2, 2013 by hytham • edited Oct 2, 2013 by hytham

1 Answer

1

Your translations of camSetImageCompression and camSetCenteredWOI are accurate. There is nothing wrong there.

The problem is camOpenEx2. There you use a Delphi managed dynamic array type. That's not valid for interop. Now, we cannot tell for sure what the C declaration for camOpenEx2 should be, but the name of your global variable szDeviceName suggests very strongly that the text parameters are char*, that is pointers to null-terminated arrays of 8 bit characters.

In which case you declare camOpenEx2 like this:

Function camOpenEx2(
  device_name: PAnsiChar;
  ctl_bus_name: PAnsiChar;
  Var p_dev_type: Integer; 
  ctl_bus_type: Integer; 
  camera_type: Integer;
  dev_bus_type: Integer
): Integer; stdcall; external 'Camlib.dll';

And you call it like this:

m_camHandle := camOpenEx2(PAnsiChar(DeviceName), nil,  nDeviceType, 0, 1, 16);

Note that I am assuming that the rest of your declaration is correct. I cannot check because you did not show the C declaration of camOpenEx2.

I also cannot be sure that passing nil for the second parameter is valid. Perhaps you are expected to pass an empty string, in which case you would pass ''. Update: The C# code seems to indicate that passing nil is acceptable.

Note also that I am assuming you use a pre-Unicode Delphi. But if not, that is if you have Delphi 2009 or later, then you need to declare DeviceName to be AnsiString rather than string.

Now, there may be other errors than this. This is interop and that requires a human to ensure that both sides of the interop interface match. You showed the other side for camSetImageCompression and camSetCenteredWOI and for sure your translations are accurate. For sure a dynamic array is incorrect for interop. But I cannot check any more than that since I can only see one side of the interop interface.

Update

The C# clears things up a little, but that code is wrong too. Specifically its use of byte and char arrays cannot be correct. I guess by chance the .net framework is allocating memory that happens to have null-terminators off the ends of the arrays.

I think that MetrocomUploadJpeg looks dubious. That char[] doesn't seem plausible. But you are not calling it so let's not get hung up on it. As for the rest of the imports, they match the p/invokes. Well, once you change camOpenEx2 as described above.

The C# code looks very flimsy to me. Frankly I think you are better working from the original documentation, and a C++ example. I've no idea where that C# code came from, but it's not well done.

answered on Stack Overflow Oct 2, 2013 by David Heffernan • edited Oct 2, 2013 by David Heffernan

User contributions licensed under CC BY-SA 3.0