Solved

Problems with Explicit Access of C++ dll from Delphi

Posted on 2008-10-08
4
885 Views
Last Modified: 2013-12-14
I have a C++ dll that I have created an import unit for and can sucessfully call two of the procedures
     CG4_Main_GetConnectedScanner
     CG4_GetApiVersion

The other two listed procedures return error code -616 which is means scanner type is not supported even though the scanner type is taken from the call to CG4_Main_GetConnectedScanner.  The code acts as it should in C++ - what am I missing??

I have pasted the import unit, the Delphi code, and a piece of C++ code that works below
*****************************************************************
Here is the import unit code I created (edited several other functions not relevant)
unit CG4ESSENTIALSAPI;

interface
uses
{$IFDEF WIN32}
  Windows;
{$ELSE}
  Wintypes, WinProcs;
{$ENDIF}

//{$INCLUDE "windows.h"}



const
  CG4_MAX_STR_LEN = 128; {///< Required buffer length for string parameters}


{///////////////////////////////////////////////////////////////////////////////// }
{/// struct & enum }


{//// Container to hold version information. }
type
  CG4ApiVersion = record
    Product: Array[0..CG4_MAX_STR_LEN-1] of Char;
    SdkVer: Array[0..CG4_MAX_STR_LEN-1] of Char;
    MosaicVer: Array[0..CG4_MAX_STR_LEN-1] of Char;
  end {tagCG4ApiVersion};

{/// Connected scanner }
type
  CG4ScannerExist = record
    nDevConnected: Integer;
    bCS500i: Bool;
    bCS500e: Bool;
    bCSD450: Bool;
    bCSD330: Bool;
    bCSD200: Bool;
  end {tagCG4ScannerExist};


{/// Scanner type }
type
  tagCG4ScannerType = (
    CG4_SCANNER_ONE_FINGER {= 300},
    CG4_SCANNER_CSD301 {= CG4_SCANNER_ONE_FINGER+1},
    CG4_SCANNER_CSD330 {= CG4_SCANNER_ONE_FINGER+2},
    CG4_SCANNER_CSD200 {= CG4_SCANNER_ONE_FINGER+3},
    CG4_SCANNER_TWO_FINGER {= 400},
    CG4_SCANNER_CSD450 {= CG4_SCANNER_TWO_FINGER+1},
    CG4_SCANNER_FOUR_FINGER {= 500},
    CG4_SCANNER_CS500I {= CG4_SCANNER_FOUR_FINGER+1},
    CG4_SCANNER_CS500E {= CG4_SCANNER_FOUR_FINGER+2},
    CG4_SCANNER_PALM {= 600},
    {/// ...  );



{///////////////////////////////////////////////////////////////////////////////// }
{/// Interface }

{///------------------------------------------------------------------- }
{/// Function name: CG4_Main_GetConnectedScanner }
{/// Parameter: }
{/// input: }
{/// output: }
{/// in/out: info - connected scanner; memory provided by caller! }
{/// Return: }
{/// CG4_STATUS_OK }
{/// CG4_ERR_INVALID_PARAM_VALUE }
{/// Description: Get connected scanner. }
{///------------------------------------------------------------------- }

function CG4_Main_GetConnectedScanner(var scannerExist: CG4SCANNEREXIST): Integer {$IFDEF WIN32} stdcall {$ENDIF};

{///------------------------------------------------------------------- }
{/// Function name: CG4_Main_GetAPIVersion }
{/// Parameter: }
{/// input: }
{/// output: }
{/// in/out: info - API version information; memory provided by caller! }
{/// Return: }
{/// CG4_STATUS_OK }
{/// CG4_ERR_INVALID_PARAM_VALUE }
{/// Description: Get DLL version information. }
{///------------------------------------------------------------------- }

function CG4_Main_GetAPIVersion(var info: CG4APIVERSION): Integer {$IFDEF WIN32} stdcall {$ENDIF};

{///------------------------------------------------------------------- }
{/// Function name: CG4_Main_Initialize }
{/// Parameter: }
{/// input: ScannerType - scanner type; default value is CG_SCANNER_CS500I }
{/// output: }
{/// in/out: }
{/// Return: }
{/// CG4_STATUS_OK }
{/// CG4_ERR_IS_INITIALIZED }
{/// CG4_ERR_DEVICE_IO }
{/// Description: Initialize scanner. }
{///------------------------------------------------------------------- }

function CG4_Main_Initialize(ScannerType: CG4SCANNERTYPE=CG4_SCANNER_CS500I): Integer {$IFDEF WIN32} stdcall {$ENDIF};

{///------------------------------------------------------------------- }
{/// Function name: CG4_Main_DeInitialize }
{/// Parameter: }
{/// input: }
{/// output: }
{/// in/out: }
{/// Return: }
{/// CG4_STATUS_OK }
{/// Description: DeInitialize scanner. }
{///------------------------------------------------------------------- }

function CG4_Main_FastStartup(ScannerType: CG4SCANNERTYPE=CG4_SCANNER_CS500I): Integer {$IFDEF WIN32} stdcall {$ENDIF};

{///------------------------------------------------------------------- }
{/// Function name: CG4_Main_StandBy }
{/// Parameter: }
{/// input: }
{/// output: }
{/// in/out: }
{/// Return: }
{/// CG4_STATUS_OK }
{/// Description: StandBy scanner. }
{///------------------------------------------------------------------- }

{///////////////////////////////////////////////////////////////////////////////// }

implementation

function CG4_Main_GetConnectedScanner; external 'CG4ESSENTIALSAPI.DLL';
function CG4_Main_GetAPIVersion; external 'CG4ESSENTIALSAPI.DLL';
function CG4_Main_Initialize; external 'CG4ESSENTIALSAPI.DLL';
function CG4_Main_FastStartup; external 'CG4ESSENTIALSAPI.DLL';

end.

************************************************************************
Here is a test Delphi code

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    Button2: TButton;
    Edit2: TEdit;
    Button3: TButton;
    Edit3: TEdit;
    Button4: TButton;
    Edit4: TEdit;
    Button5: TButton;
    Edit5: TEdit;
    Button6: TButton;
    Edit6: TEdit;
    Button7: TButton;
    Edit7: TEdit;
    Button8: TButton;
    Edit8: TEdit;
    Button0: TButton;
    Edit0: TEdit;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button8Click(Sender: TObject);
    procedure Button0Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  se:tCG4ScannerExist;
  st:tCG4ScannerType;
  sa:tCG4ApiVersion;

implementation

{$R *.dfm}



procedure TForm1.Button0Click(Sender: TObject);
  var
    i:integer;
    t:string;
  begin
    i:=CG4_Main_GetConnectedScanner(se);
    t:=IntToStr(se.nDevConnected)+' Scanner(s) connected - ';
    if se.bCS500i then
      begin
        st:=CG4_SCANNER_CS500I;
        t:=t+'500i, ';
      end;
    if se.bCS500e then
      begin
        st:=CG4_SCANNER_CS500E;
        t:=t+'500e, ';
      end;
    if se.bCSD450 then
      begin
        st:=CG4_SCANNER_CSD450;
        t:=t+'450, ';
      end;
    if se.bCSD330 then
      begin
        st:=CG4_SCANNER_CSD330;
        t:=t+'300, ';
      end;
    if se.bCSD200 then
      begin
        st:=CG4_SCANNER_CSD200;
        t:=t+'200, ';
      end;
    Edit0.Text:=t;
  end;

procedure TForm1.Button1Click(Sender: TObject);
  var
    i:integer;
  begin
    i:=CG4_Main_GetApiVersion(sa);
    Edit1.Text:=IntToStr(i)+', '+sa.Product+', '+sa.SdkVer+', '+sa.MosaicVer;
  end;

procedure TForm1.Button2Click(Sender: TObject);
  var
    i:integer;
  begin
    i:=CG4_Main_Initialize(st);
    Edit2.Text:=IntToStr(i)
  end;

procedure TForm1.Button8Click(Sender: TObject);
  var
    i:integer;
  begin
    i:=CG4_Main_DeInitialize;
    Edit8.Text:='Attempted DeInitialize '+IntToStr(i)
  end;

end.

*************************************************************************
here is the working C++ code
void CDlgMainFunctions::OnBtnInitialize()
{
    int nRc = 0;
    FunctionStatus fs( m_pMainFrame, "Initialize()", nRc );

    m_pMainFrame->SetBusy();
    UpdateData();

    // get connected scanner
    CG4ScannerExist tScannerExist;
    nRc = CG4_Main_GetConnectedScanner(&tScannerExist);
    if (nRc != CG4_STATUS_OK || tScannerExist.nDevConnected != 1)
    {
        m_pMainFrame->ShowResult( "CG4_Main_GetConnectedScanner failed, returned code: %d", nRc );
        return;
    }

    RECT rect;

    if (tScannerExist.bCS500i)
    {
        m_ScannerType = CG4_SCANNER_CS500I;
        rect.left = 10; rect.right = 410; rect.top = 10; rect.bottom = 385;
    }
    else if (tScannerExist.bCS500e)
    {
        m_ScannerType = CG4_SCANNER_CS500E;
        rect.left = 10; rect.right = 410; rect.top = 10; rect.bottom = 385;
    }
    else if (tScannerExist.bCSD450)
    {
        m_ScannerType = CG4_SCANNER_CSD450;
        rect.left = 10; rect.right = 410; rect.top = 10; rect.bottom = 385;
    }
    else if (tScannerExist.bCSD330)
    {
        m_ScannerType = CG4_SCANNER_CSD330;
        rect.left = 10; rect.right = 260; rect.top = 10; rect.bottom = 260;
    }
    else if (tScannerExist.bCSD200)
    {
        m_ScannerType = CG4_SCANNER_CSD200;
        rect.left = 10; rect.right = 170; rect.top = 10; rect.bottom = 250;
    }
    m_pMainFrame->SetPreviewRect(rect);

    // init device
    nRc = CG4_Main_Initialize(m_ScannerType);
    if (nRc != CG4_STATUS_OK)
    {
        m_pMainFrame->ShowResult( "CG4_Main_Initialize failed, returned code: %d", nRc );
        return;
    }

}



0
Comment
Question by:tjmadden
  • 2
  • 2
4 Comments
 
LVL 21

Assisted Solution

by:developmentguru
developmentguru earned 150 total points
Comment Utility
One of the first things I look at when having issues importing functions from DLLs is whether or not the functions are declared as STDCALL.  Try that and let me know how it goes.
0
 

Author Comment

by:tjmadden
Comment Utility
All functions are declared as STDCALL (as in sample code).  I also tries CDECL with no luck.  The two functions that I have not been able to get working have defaults for the arguments - I am not sure if this needs to be handled differently?
0
 
LVL 21

Assisted Solution

by:developmentguru
developmentguru earned 150 total points
Comment Utility
I think your intuition is probably correct on the defaults.  Try taking off the default value and make a different function that takes no parameters as the one that uses the default (overload if possible).
0
 

Accepted Solution

by:
tjmadden earned 0 total points
Comment Utility
I figured it out - simple mistake in the type definitions that took me forever to figure out :(  feeling a little stupid - thanks for the help
0

Featured Post

Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

Join & Write a Comment

In our object-oriented world the class is a minimal unit, a brick for constructing our applications. It is an abstraction and we know well how to use it. In well-designed software we are not usually interested in knowing how objects look in memory. …
Jaspersoft Studio is a plugin for Eclipse that lets you create reports from a datasource.  In this article, we'll go over creating a report from a default template and setting up a datasource that connects to your database.
This tutorial covers a step-by-step guide to install VisualVM launcher in eclipse.
The viewer will learn how to use NetBeans IDE 8.0 for Windows to connect to a MySQL database. Open Services Panel: Create a new connection using New Connection Wizard: Create a test database called eetutorial: Create a new test tabel called ee…

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now