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);

        }


    }
}
hytham
  • 53
  • 1
  • 6
  • Please can you take a look at your previous question. I spent time on it, answered your question. But you did not acknowledge that. I can see plenty of things wrong in this question, but feel disinclined to help. – David Heffernan Oct 02 '13 at 16:06
  • you tell me to make a new question when I get to the next step – hytham Oct 02 '13 at 16:19
  • All external calls to a dll should of course be `stdcall`. (unless the dll's doc says otherwise). – Johan Oct 02 '13 at 16:19
  • @hytham, No, you need to either accept the answer to the previous question, or give feedback as to why it did not work. David is complaining that you keep on asking what is effectively the same question in a different form. Asking a new question makes things worse. – Johan Oct 02 '13 at 16:21
  • ok I am sorry I don't know what to do, what I must to do in the last question? – hytham Oct 02 '13 at 16:27
  • @David Heffernan in the last question I thanks you for your effort and I update the code as you tell me but I get the same error in the next step and you roolback my question and asked me to ask new question – hytham Oct 02 '13 at 16:29
  • I accept the answer in the last question – hytham Oct 02 '13 at 16:33
  • I answered the question that you asked. That much is clear since you use the same declaration that I gave you here, and your call to `MetrocomInitCommunication` now works. The fact that the rest of your code does not work yet does not mean that the question you asked was not answered. – David Heffernan Oct 02 '13 at 16:35
  • @Johan I updated the function by deleting the stdcall and it is work fine now but I need to complete my project, should I ask in this question or in another one? – hytham Oct 02 '13 at 16:35
  • @David Heffernan Ok thanks for you I understand now what you say to me and I am sorry that I didn't know the role. – hytham Oct 02 '13 at 16:37
  • What do you mean "deleting the stdcall"? You don't want to do that. Are you still not 100% sure what the calling convention is? – David Heffernan Oct 02 '13 at 16:38
  • You meant to say "added" right? And to be honest you are a master at obfuscation: first you say "it's working fine" then you say I have more questions. This is not how SO works. You ask a question -> you get an answer. This is not a **lets debug your whole project** kind of site. If however you have a new unrelated problem then you should ask a new question. Never should you alter the original question in such a way as to change its meaning. – Johan Oct 02 '13 at 17:39

1 Answers1

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.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • oops you mean that I am using wrong code by converting from string to byte – hytham Oct 02 '13 at 16:48
  • I am using Delphi 2006 – hytham Oct 02 '13 at 16:50
  • I mean that you cannot use a dynamic array for interop. As it happens, your code may actually almost work if it null-terminated the array. If you want a definitive answer, show the declaration for `camOpenEx2`. – David Heffernan Oct 02 '13 at 16:50
  • it is not working the same error I tried the suggest of you and didn't work also I used the '' instead of nil and still send me access violation and when I delete the stdcall in the tow functions it work without error but it give value -1 that it is failure function – hytham Oct 02 '13 at 18:41
  • @David Heffernan I have an code in c# work fine I will post it in my question – hytham Oct 02 '13 at 18:43