0

我在 Delphi 中有一个代码,我使用它从我的 2D 阅读器中获取图片,我正在使用“camlib.dll”来设置设备中图像的参数代码:

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.

我在这一行得到一个错误,并且在编译两个函数后发生错误我得到一个错误“0x000001f4的访问冲突:读取地址0x000001f4”,然后在delphi中打开CPU调试:

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

camlib.dll 中函数的描述是:

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.

在 C# 中它工作正常:

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

        }


    }
}
4

1 回答 1

1

您对camSetImageCompression和的翻译camSetCenteredWOI是准确的。那里没有错。

问题是camOpenEx2。在那里,您使用 Delphi 托管的动态数组类型。这对互操作无效。现在,我们无法确定 C 声明camOpenEx2应该是什么,但是您的全局变量的名称szDeviceName非常强烈地表明文本参数是char*,即指向以空字符结尾的 8 位字符数组的指针。

在这种情况下,您可以这样声明camOpenEx2

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

你这样称呼它:

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

请注意,我假设您声明的其余部分是正确的。我无法检查,因为您没有显示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.

于 2013-10-02T16:33:36.110 回答