Board index » delphi » Delphi & DLL's - Invalid Pointer Operation

Delphi & DLL's - Invalid Pointer Operation

Hi,
I am having a problem with an application I've been working on that throws a
EInvalidPointer error with the message, "Invalid Pointer Operation" on
exiting the app.  I've traced and traced through this app and for the life
of me I can't find the problem.
I decided that I didn't know enough about COM and DLL's so I got out my
Mastering Delphi 4 book (the one by Marco Cantu) and started working through
the examples presented in chapter 16.  As I worked through the second
example, passing Pascal strings and PChar strings to and from the DLL, I
began to encounter the same Invalid Pointer error that the big program has
been hurling...go figure.
I did more testing and discovered that if I include the ShareMem unit in the
uses clause of the EXE program, then the Pascal string function works just
fine, but then the app blows up with the Invalid Pointer error upon exiting
the application.  If I remove ShareMem, then the Pascal string function
generates the same error - not on the function call, but rather on assigning
the result from the function call to a memo component on the form (even
though it ends up displaying the correct result).  Also, if ShareMem is
being referenced, the app will blow up on exit regardless of whether any
functions have been performed or not!  I'm beginning to think that there's a
bigger bug buried in Delphi than any I may have created here myself...any
ideas?
TIA,
Dan

Source code:

---------------------
DLL:
---------------------
library TestDLL;

uses
  ShareMem,
  SysUtils,
  Classes;

//--------------------------------------------------------------------------
----
function DoubleString(pS: string; pSeparator: Char): string; stdcall;
begin
  Result := pS + pSeparator + pS;
end;

//--------------------------------------------------------------------------
----
function DoublePChar(pBufferIn, pBufferOut: PChar;
                                   pBufferOutLen: Integer;
                                   pSeparator: Char): LongBool; stdcall;
var
  lSepStr: array [0..1] of Char;
begin
   Result := False;

   // If the buffer is large enough...
   if pBufferOutLen >= Trunc((StrLen(pBufferIn) * 2 + 2)) then
   begin
     // Copy the string from the input buffer to the output buffer
     StrCopy(pBufferOut, pBufferIn);
     // Build the separator
     lSepStr[0] := pSeparator;
     lSepStr[1] := #0;

     // Append the separator
     StrCat(pBufferOut, lSepStr);

     // Append the string from the input buffer again
     StrCat(pBufferOut, pBufferIn);

     Result := True;
   end;
end;

//--------------------------------------------------------------------------
----
exports
  DoubleString, DoublePChar;

//--------------------------------------------------------------------------
----
end.

----------------------------
Calling Application Source:
----------------------------
DPR:
---------------------
program CallTest;

uses
  Forms,
  CallTestU in 'CallTestU.pas' {frmCallDLL};

{$R *.RES}

begin
  Application.Initialize;
  Application.CreateForm(TfrmCallDLL, frmCallDLL);
  Application.Run;
end.

----------------------
Unit:
----------------------
unit CallTestU;

interface

uses
  ShareMem, // <--- Remove this and the program exits cleanly,
                     // but fails on the call to DoubleString -
                     // (actually on the assignment statement AFTER the
call).
                     // WITH it, the call to DoubleString succeeds without
errors,
                     // but the program fails on exit.
  Windows, Messages, SysUtils, Classes,
  Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls, Buttons;

type
  TfrmCallDLL = class(TForm)
    lblTextString: TLabel;
    edtTextSource: TEdit;
    btnDoubleString: TBitBtn;
    btnDoublePChar: TBitBtn;
    mmoOutput: TMemo;
    edtSeparator: TEdit;
    lblSeparator: TLabel;
    btnClearMemo: TBitBtn;

    procedure btnDoubleStringClick(Sender: TObject);
    procedure btnDoublePCharClick(Sender: TObject);
    procedure btnClearMemoClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  frmCallDLL: TfrmCallDLL;

implementation

{$R *.DFM}

// DLL
Functions ---------------------------------------------------------------
function DoubleString(pS: string; pSeparator: Char):
  string; stdcall; external 'TESTDLL.DLL';
function DoublePChar(pBufferIn, pBufferOut: PChar;
                     pBufferOutLen: Integer;
                     pSeparator: Char):
  LongBool; stdcall; external 'TESTDLL.DLL';
//--------------------------------------------------------------------------
----

//--------------------------------------------------------------------------
----
procedure TfrmCallDLL.btnDoubleStringClick(Sender: TObject);
var lS : string;
    lC : Char;
begin
  lS := edtSeparator.Text;
  lC := lS[1];
  lS := DoubleString(edtTextSource.Text, lC);
  mmoOutput.Clear;
  mmoOutput.Text := lS; // <--- Invalid Pointer occurs here
  // I have tried several variations of this procedure - making the
assignment
  // directly from the function call, and breaking it up like this so that I
could
  // confirm that it's not the function call causing the error.
end;

//--------------------------------------------------------------------------
----
procedure TfrmCallDLL.btnDoublePCharClick(Sender: TObject);
var lBuffer : string;
    lS : string;
    lC : Char;
begin
  lS := edtSeparator.Text;
  lC := lS[1];
  // Make the buffer large enough
  SetLength(lBuffer, 1000);
  // Call the DLL function
  if DoublePChar(PChar(edtTextSource.Text), PChar(lBuffer), 1000, lC) then
  begin
    mmoOutput.Clear;
    mmoOutput.Text := lBuffer;
  end;
end;

//--------------------------------------------------------------------------
----
procedure TfrmCallDLL.btnClearMemoClick(Sender: TObject);
begin
  mmoOutput.Clear;
end;

//--------------------------------------------------------------------------
----
end.

----------------------
DFM (Form as Text)
----------------------
object frmCallDLL: TfrmCallDLL
  Left = 380
  Top = 253
  Width = 334
  Height = 190
  Caption = 'Calling Delphi DLL Functions'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  Position = poScreenCenter
  PixelsPerInch = 96
  TextHeight = 13
  object lblTextString: TLabel
    Left = 12
    Top = 10
    Width = 51
    Height = 13
    Caption = 'Text String'
  end
  object lblSeparator: TLabel
    Left = 16
    Top = 34
    Width = 46
    Height = 13
    Caption = 'Separator'
  end
  object edtTextSource: TEdit
    Left = 66
    Top = 6
    Width = 241
    Height = 21
    TabOrder = 0
    Text = 'Four score and seven years ago'
  end
  object btnDoubleString: TBitBtn
    Left = 232
    Top = 60
    Width = 75
    Height = 25
    Caption = '&Double String'
    TabOrder = 1
    OnClick = btnDoubleStringClick
  end
  object btnDoublePChar: TBitBtn
    Left = 16
    Top = 60
    Width = 75
    Height = 25
    Caption = 'Double &PChar'
    TabOrder = 2
    OnClick = btnDoublePCharClick
  end
  object mmoOutput: TMemo
    Left = 14
    Top = 90
    Width = 293
    Height = 57
    TabOrder = 3
  end
  object edtSeparator: TEdit
    Left = 66
    Top = 30
    Width = 29
    Height = 21
    TabOrder = 4
    Text = '|'
  end
  object btnClearMemo: TBitBtn
    Left = 125
    Top = 60
    Width = 75
    Height = 25
    Caption = 'Clear Memo'
    TabOrder = 5
    OnClick = btnClearMemoClick
  end
end

 

Re:Delphi & DLL's - Invalid Pointer Operation


<<Dan Lovett:
program CallTest;

uses
  Forms,
  CallTestU in 'CallTestU.pas' {frmCallDLL};

Quote

ShareMem has to be first in your /project's/ uses clause,
not just the unit's.

--
Deborah Pate (TeamB) http://delphi-jedi.org

  Use Borland servers; TeamB don't see posts via ISPs
  http://www.borland.com/newsgroups/genl_faqs.html

Re:Delphi & DLL's - Invalid Pointer Operation


Well, that figures.

Quoting from Mr. Cantu's book, 'The solution to the problem is to include
the ShareMem system unit both in the DLL and in the program using it.  This
unit must be included as the first unit of each of the projects."
Now that I realize that he meant the DPR (project) file, it reads that way,
but I thought he meant in the UNIT file that called the DLL functions.

Thanks Deborah - you're a sweetie.
Now if I can just figure out why the big app keeps barfing out this same
error...  :)
D

"Deborah Pate (TeamB)" <d.p...@cableinet.co.not-this-bit.uk> wrote in
message news:VA.00000a02.0033d382@cableinet.co.not-this-bit.uk...

Quote
> <<Dan Lovett:
> program CallTest;

> uses
>   Forms,
>   CallTestU in 'CallTestU.pas' {frmCallDLL};

> ShareMem has to be first in your /project's/ uses clause,
> not just the unit's.

> --
> Deborah Pate (TeamB) http://delphi-jedi.org

>   Use Borland servers; TeamB don't see posts via ISPs
>   http://www.borland.com/newsgroups/genl_faqs.html

Re:Delphi & DLL's - Invalid Pointer Operation


what can I do if I want to use the dll to let other programers (c++, vb)
use the dll, should I give them special instructions, or do I have to go
about writing the dll the hard way?
Quote
"Deborah Pate (TeamB)" wrote:

> <<Dan Lovett:
> program CallTest;

> uses
>   Forms,
>   CallTestU in 'CallTestU.pas' {frmCallDLL};

> ShareMem has to be first in your /project's/ uses clause,
> not just the unit's.

> --
> Deborah Pate (TeamB) http://delphi-jedi.org

>   Use Borland servers; TeamB don't see posts via ISPs
>   http://www.borland.com/newsgroups/genl_faqs.html

Other Threads