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