 |
BorlandTalk.com Borland discussion newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Zebedee Guest
|
Posted: Fri Feb 27, 2004 8:08 pm Post subject: Delphi DLL problems |
|
|
I'm trying to run a Delphi DLL I've written. I'm not sure I've written it
correctly. Can somebody have a look and tell me where I'm going wrong? It's
probably something very simple. This is the calling code:
procedure TAgencyController.Button6Click(Sender: TObject);
var LibHandle :THandle;
begin
LibHandle := LoadLibrary('DatabaseP.dll');
if LibHandle = 0 then ShowMessage('Aaarggghh');
TDataBase.LoadLibrary('');
FreeLibrary(LibHandle);
end;
This is the DLL code.
library DatabaseP;
uses
SysUtils,Classes,DateUtils;
{$R *.res}
// procedure list
Type
TDataBase = class(TObject)
{$ifdef DataBase}
public
Function LoadDataBase(LocationAndName:ShortString):Boolean;
Procedure SaveDataBase(LocationAndName: ShortString);
Procedure AddNew(EmailAddress:ShortString);
Procedure Delete(EmailAddress:ShortString);
Procedure Return(EmailAddress:ShortString; var FirstMailed, FirstReplied,
LastMailed, LastReplied,
FirstCVSent, LastCVSent : ShortString; TimesMailed, TimesReplied,
SillyReplies : Integer; Deleted:Boolean);
Procedure MarkMailed(EmailAddress:ShortString);
Procedure MarkCVSent(EmailAddress:ShortString);
Function HowManyRecords: Integer;
Function HowManyDeleted: Integer;
Function NextDeleted: ShortString;
Function HowManyNotCVd: Integer;
Function HowManyNotReplied: Integer;
Function HowManyNotContacted: Integer;
Function AddressPresent(EmailAddress :ShortString): Boolean;
Function CheckPresentOrDeleted(EmailAddress : ShortString): Boolean;
Function ClearOutDeleted : Integer;
Function IsAddressPresent(EmailAddress: ShortString): boolean;
Function IsAddressDeleted(EmailAddress: ShortString): boolean;
Procedure Rewind;
// return records
Procedure NextFull(EmailAddress:ShortString; var FirstMailed, FirstReplied,
LastMailed, LastReplied,
FirstCVSent, LastCVSent : ShortString; TimesMailed, TimesReplied,
SillyReplies : Integer; Deleted:Boolean);
Function NextNotFirstMailed : ShortString; // returns email address or ''
for no more
Function NextNotFirstCV: ShortString; // returns email address or '' for no
more
Function NextMailedButNotReplied: ShortString; // returns address of people
emailed but who haven't replied
Function NextSevenDaySilence: ShortString;// returns address of people
who've not responded for 7 days.
Function NextFourteenDaySilence: ShortString;// returns address of people
who've not responded for 14 days
Function NextTwentyOneDaySilence: ShortString;// returns address of people
who've not responded for 21 days
Function NextMonthSilence: ShortString;// returns address of people who've
not responded for a month
Function NextTwoMonthSilence: ShortString;// returns address of people
who've not responded for two months
Function NextThreeMonthSilence: ShortString;// returns address of people
who've not responded for two months
Function NextFourMonthSilence: ShortString;// returns address of people
who've not responded for two months
Function NextFiveMonthSilence: ShortString;// returns address of people
who've not responded for two months
Function NextSixMonthSilence: ShortString;// returns address of people
who've not responded for two months
end;
var
DateOfFirstSendingList, DateOfLastSendingList, NumberOfSendingsList,
DateOfFirstReplyList,
DateOfLastReplyList, NumberOfRepliesList, DateOfLastCVSentList,
DateOfFirstCVSentList,
NumberofCVsSentList, NoOfSillyRepliesList, EmailAddressList, DeletedList:
TStringList;
FirstAddressListCounter : integer;
// actual procedures
Function TDataBase.LoadDataBase(LocationAndName:ShortString):boolean;
var
MailingList : Packed Record
DateOfFirstSending : Double;
DateOfLastSending : Double;
NumberOfSendings : integer;
DateOfFirstReply : Double;
DateOfLastReply : Double;
NumberOfReplies : integer;
DateOfLastCVSent : Double;
DateOfFirstCVSent : Double;
NumberofCVsSent : integer;
NoOfSillyReplies : integer;
EmailAddress : ShortString;
RecordDeleted : Boolean;
end;
MyDataFile : TFileStream;
TotalCount : Integer;
DataListCount: Integer;
FileLength : integer;
begin
DateOfFirstSendingList := TStringList.Create;
DateOfLastSendingList := TStringList.Create;
NumberOfSendingsList := TStringList.Create;
DateOfFirstReplyList := TStringList.Create;
DateOfLastReplyList := TStringList.Create;
NumberOfRepliesList := TStringList.Create;
DateOfLastCVSentList := TStringList.Create;
DateOfFirstCVSentList := TStringList.Create;
NumberofCVsSentList := TStringList.Create;
NoOfSillyRepliesList := TStringList.Create;
EmailAddressList := TStringList.Create;
DeletedList := TStringList.Create;
if Not FileExists(LocationAndName) then
begin
Result := False;
Exit;
end;
// so the datafile exists
MyDataFile := TFileStream.Create(LocationAndName,fmOpenRead);
// load the existing database
TotalCount := 0;
DataListCount := 0;
FileLength := MyDataFile.Size;
while DataListCount < FileLength do
begin
TotalCount := TotalCount + 1;
MyDataFile.Position := DataListCount;
MyDataFile.ReadBuffer(MailingList,sizeof(MailingList));
DataListCount := DataListCount + sizeof(MailingList);
EmailAddressList.Add(MailingList.EmailAddress);
NumberOfSendingsList.Add(IntToStr(MailingList.NumberOfSendings));
if MailingList.DateOfLastSending = 0 then DateOfLastSendingList.Add('-')
else
DateOfLastSendingList.Add(DateToStr(ModifiedJulianDateToDateTime(MailingList
..DateOfLastSending)));
if MailingList.DateOfFirstSending = 0 then
DateOfFirstSendingList.Add('-') else
DateOfFirstSendingList.Add(DateToStr(ModifiedJulianDateToDateTime(MailingLis
t.DateOfFirstSending)));
if MailingList.DateOfLastReply = 0 then DateOfLastReplyList.Add('-') else
DateOfLastReplyList.Add(DateToStr(ModifiedJulianDateToDateTime(MailingList.D
ateOfLastReply)));
if MailingList.DateOfFirstReply = 0 then DateOfFirstReplyList.Add('-')
else
DateOfFirstReplyList.Add(DateToStr(ModifiedJulianDateToDateTime(MailingList.
DateOfFirstReply)));
NumberOfRepliesList.Add(IntToStr(MailingList.NumberOfReplies));
if MailingList.DateOfLastCVSent = 0 then DateOfLastCVSentList.Add('-')
else
DateOfLastCVSentList.Add(DateToStr(ModifiedJulianDateToDateTime(MailingList.
DateOfLastCVSent)));
if MailingList.DateOfFirstCVSent = 0 then DateOfFirstCVSentList.Add('-')
else
DateOfFirstCVSentList.Add(DateToStr(ModifiedJulianDateToDateTime(MailingList
..DateOfFirstCVSent)));
NumberofCVsSentList.Add(IntToStr(MailingList.NumberofCVsSent));
NoOfSillyRepliesList.Add(IntToStr(MailingList.NoOfSillyReplies));
DeletedList.Add(BoolToStr(MailingList.RecordDeleted));
end;
MyDataFile.Free;
Result := True;
end;
Procedure TDataBase.SaveDataBase(LocationAndName: ShortString);
var
MailingList : Packed Record
DateOfFirstSending : Double;
DateOfLastSending : Double;
NumberOfSendings : integer;
DateOfFirstReply : Double;
DateOfLastReply : Double;
NumberOfReplies : integer;
DateOfLastCVSent : Double;
DateOfFirstCVSent : Double;
NumberofCVsSent : integer;
NoOfSillyReplies : integer;
EmailAddress : ShortString;
RecordDeleted : Boolean;
end;
MyDataFile : TFileStream;
Count : Integer;
begin
MyDataFile := TFileStream.Create(LocationAndName,fmCreate);
// now go through TStringLists and save data
for Count := 0 to EmailAddressList.Count -1 do
begin
if DateOfFirstSendingList.Strings[Count] = '-' then
MailingList.DateOfFirstSending := 0
else MailingList.DateOfFirstSending :=
DateTimeToModifiedJulianDate(StrToDate(DateOfFirstSendingList.Strings[Count]
));
if DateOfLastSendingList.Strings[Count] = '-' then
MailingList.DateOfLastSending := 0
else MailingList.DateOfLastSending :=
DateTimeToModifiedJulianDate(StrToDate(DateOfLastSendingList.Strings[Count])
);
MailingList.NumberOfSendings :=
StrToInt(NumberOfSendingsList.Strings[Count]);
if DateOfFirstReplyList.Strings[Count] = '-' then
MailingList.DateOfFirstReply := 0
else MailingList.DateOfFirstReply :=
DateTimeToModifiedJulianDate(StrToDate(DateOfFirstReplyList.Strings[Count]))
;
if DateOfLastReplyList.Strings[Count] = '-' then MailingList.DateOfLastReply
:= 0
else MailingList.DateOfLastReply :=
DateTimeToModifiedJulianDate(StrToDate(DateOfLastReplyList.Strings[Count]));
MailingList.NumberOfReplies :=
StrToInt(NumberOfRepliesList.Strings[Count]);
if DateOfFirstCVSentList.Strings[Count] = '-' then
MailingList.DateOfFirstCVSent := 0
else MailingList.DateOfFirstCVSent :=
DateTimeToModifiedJulianDate(StrToDate(DateOfFirstCVSentList.Strings[Count])
);
if DateOfLastCVSentList.Strings[Count] = '-' then
MailingList.DateOfLastCVSent := 0
else MailingList.DateOfLastCVSent :=
DateTimeToModifiedJulianDate(StrToDate(DateOfLastCVSentList.Strings[Count]))
;
MailingList.NumberofCVsSent :=
StrToInt(NumberofCVsSentList.Strings[Count]);
MailingList.NoOfSillyReplies :=
StrToInt(NoOfSillyRepliesList.Strings[Count]);
MailingList.EmailAddress := EmailAddressList.Strings[Count];
MailingList.RecordDeleted := StrToBool(DeletedList.Strings[Count]);
MyDataFile.Write(MailingList,sizeof(MailingList));
end;
MyDataFile.Free;
// now free the memory
DateOfFirstSendingList.Free;
DateOfLastSendingList.Free;
NumberOfSendingsList.Free;
DateOfFirstReplyList.Free;
DateOfLastReplyList.Free;
NumberOfRepliesList.Free;
DateOfLastCVSentList.Free;
DateOfFirstCVSentList.Free;
NumberofCVsSentList.Free;
NoOfSillyRepliesList.Free;
EmailAddressList.Free;
DeletedList.Free;
end;
exports
// procedures to export
DataBase;
{$endif};
end.
--
Yours
Zebedee
(Claiming asylum in an attempt
to escape paying his debts to
Dougal and Florence)
|
|
| Back to top |
|
 |
Duncan McNiven Guest
|
Posted: Fri Feb 27, 2004 8:15 pm Post subject: Re: Delphi DLL problems |
|
|
On Fri, 27 Feb 2004 20:08:11 -0000, "Zebedee" <abuse (AT) 127 (DOT) 0.0.1> wrote:
| Quote: | I'm trying to run a Delphi DLL I've written. I'm not sure I've written it
correctly. Can somebody have a look and tell me where I'm going wrong?
|
What are we looking FOR? What are the symptoms? What makes you think there is something
wrong? This is a lot of code to look through without a clue what we are looking for.
--
Duncan
|
|
| Back to top |
|
 |
Zebedee Guest
|
Posted: Fri Feb 27, 2004 8:58 pm Post subject: Re: Delphi DLL problems |
|
|
Well, It's two things.
Firstly, I was expecting the TDataBase to be included in the code so that
when I enter commands in the TForm Event handlers, I would Type DataBase.
and be given a list of available commands within the TDataBase unit.
Basically, it's an inclusion problem. How do I include it?
Also, have I coded the DLL correctly in terms of exporting the gubbins in
such a way as it would perform in code like any other TComponent?
--
Yours
Zebedee
(Claiming asylum in an attempt
to escape paying his debts to
Dougal and Florence)
|
|
| Back to top |
|
 |
Rob Kennedy Guest
|
Posted: Fri Feb 27, 2004 10:30 pm Post subject: Re: Delphi DLL problems |
|
|
Zebedee wrote:
| Quote: | I'm trying to run a Delphi DLL I've written.
|
You don't happen to be Rhys Sage, do you? Someone by that name was
asking about exporting a "DataBase" from a DLL on the Borland newsgroups
a few hours ago.
| Quote: | I'm not sure I've written it
correctly. Can somebody have a look and tell me where I'm going wrong? It's
probably something very simple.
|
Could you give us a hint? Is there something in particular about your
DLL that isn't working correctly? What is it doing now, and what is it
supposed to be doing instead?
| Quote: | This is the calling code:
procedure TAgencyController.Button6Click(Sender: TObject);
var LibHandle :THandle;
begin
LibHandle := LoadLibrary('DatabaseP.dll');
if LibHandle = 0 then ShowMessage('Aaarggghh');
|
That's really lousy error checking. If LoadLibrary returns 0, call
GetLastError to find out why. You can also call RaiseLastWin32Error
instead, which turns the error code into an easy-to-catch exception.
| Quote: | TDataBase.LoadLibrary('');
|
What's a TDataBase? What does its LoadLibrary method do?
| Quote: | FreeLibrary(LibHandle);
|
After you call FreeLibrary, everything in the DLL should be considered
inaccessible. If your DLL has loaded any files, or if you've created any
objects from code in the DLL, then the DLL *must* remain in memory until
you're finished with those files or objects.
| Quote: | library DatabaseP;
uses
SysUtils,Classes,DateUtils;
{$R *.res}
// procedure list
|
I see no procedure list. I see a class declaration and a handful of
method implementations. The implementations are quite lengthy, and I
suspect that they really have nothing to do with whatever your problem is.
Your first goal should be getting a basic DLL that compiles. Make it
export a function, event if that function doesn't do anything related to
databases yet. Then get so you can load that DLL in your EXE and call
the function. Once you have all that working, *then* worry about making
the DLL manage the database.
| Quote: | exports
// procedures to export
DataBase;
|
Undeclared identifier: DataBase.
When the conditional compilation symbol is not defined, the compiler
will interpret your DLL source code like this:
library DatabaseP;
uses
SysUtils,Classes,DateUtils;
{$R *.res}
// procedure list
Type
TDataBase = class(TObject)
end.
Since that isn't even compilable code, is that really what you intended?
Delphi does not allow you to export classes, variables, or methods. The
only things you can export are procedures and functions -- the
standalone kind, not the kind that belong to classes.
--
Rob
|
|
| Back to top |
|
 |
Duncan McNiven Guest
|
Posted: Fri Feb 27, 2004 11:12 pm Post subject: Re: Delphi DLL problems |
|
|
On Fri, 27 Feb 2004 20:58:30 -0000, "Zebedee" <abuse (AT) 127 (DOT) 0.0.1> wrote:
| Quote: |
Well, It's two things.
Firstly, I was expecting the TDataBase to be included in the code so that
when I enter commands in the TForm Event handlers, I would Type DataBase.
and be given a list of available commands within the TDataBase unit.
Basically, it's an inclusion problem. How do I include it?
Also, have I coded the DLL correctly in terms of exporting the gubbins in
such a way as it would perform in code like any other TComponent?
|
I can only endorse what Rob has said. The problem isn't something simple which can quickly
be explained, it is a whole host of things. What it all boils down to, though, is that you
have bitten off more than you can chew. Rob's advice about starting with 1 very simple
function and getting that working in a DLL is a good one. Another technique I think would
be worthwhile for you is to get your functions working properly in an EXE first, before
moving them to a DLL. This will make your debugging much easier, and also when you do move
to the DLL it will only be the DLL stuff you need to worry about.
Incidentally, why are you coding this as a DLL at all?
--
Duncan
|
|
| Back to top |
|
 |
Zebedee Guest
|
Posted: Fri Feb 27, 2004 11:21 pm Post subject: Re: Delphi DLL problems |
|
|
Why as a DLL? Simply because it gets called by several different programs. I
didn't want to do an extra unit and stick the unit in each program. I
figured a DLL would handle the task better.
I'd wanted to put the different methods into a class structure simply to
make it easier to handle. I gather it's not possible with a Delphi DLL so
I'll have to go back to the old way of doing things and just make the method
names longer, prefixing them all with DataBase.
--
Yours
Zebedee
(Claiming asylum in an attempt
to escape paying his debts to
Dougal and Florence)
"Duncan McNiven" <duncan (AT) mcniven (DOT) net> wrote
| Quote: | Incidentally, why are you coding this as a DLL at all?
--
Duncan
|
|
|
| Back to top |
|
 |
Duncan McNiven Guest
|
Posted: Fri Feb 27, 2004 11:56 pm Post subject: Re: Delphi DLL problems |
|
|
On Fri, 27 Feb 2004 23:21:26 -0000, "Zebedee" <abuse (AT) 127 (DOT) 0.0.1> wrote:
| Quote: | Why as a DLL? Simply because it gets called by several different programs. I
didn't want to do an extra unit and stick the unit in each program. I
figured a DLL would handle the task better.
|
OK
| Quote: | I'd wanted to put the different methods into a class structure simply to
make it easier to handle.
|
Normally a good idea, but not with a DLL.
| Quote: | I gather it's not possible with a Delphi DLL
|
Not just a Delphi DLL, any DLL. A DLL written in one language can be called by programs
written in another language, so anything which goes over that EXE/DLL boundary should not
be language specific. (Actually it is possible to get around this, but I wouldn't recomend
it).
| Quote: | so
I'll have to go back to the old way of doing things and just make the method
names longer, prefixing them all with DataBase.
|
OK. These things are a matter of style, and long names are normally preferable. In your
code, though, I found the names too long, to the extent that they got in the way of
understanding the code. YMMV.
--
Duncan
|
|
| Back to top |
|
 |
Rob Kennedy Guest
|
Posted: Sat Feb 28, 2004 8:07 am Post subject: Re: Delphi DLL problems |
|
|
Zebedee wrote:
| Quote: | I'd wanted to put the different methods into a class structure simply to
make it easier to handle. I gather it's not possible with a Delphi DLL so
I'll have to go back to the old way of doing things and just make the method
names longer, prefixing them all with DataBase.
|
You can't export a class, but you can export a function that returns a
class. It's best to have the function return either an interface
reference or a reference to an abstract base class. That simplifies the
class declarations in the EXE.
type
IDatabase = interface
[{guid-goes-here}]
function LoadDatabase(LocationAndName: PChar): Boolean;
procedure SaveDatabase(LocationAndName: PChar);
procedure AddNew(EMailAddress: PChar);
// etc.
end;
function MakeNewDatabase: IDatabase;
begin
Result := TDatabaseImpl.Create as IDatabase;
end;
exports
MakeNewDatabase;
end.
--
Rob
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|