 |
BorlandTalk.com Borland discussion newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Gord Cross Guest
|
Posted: Mon Sep 27, 2004 8:53 pm Post subject: Re: Access Violation in DLL |
|
|
Hello,
I am trying to call a DLL (C++ Builder) from PB and I keep getting access
violations. The thing is, it will work for a few times then crap out. Does
anyone have any ideas? I think something is either locking or freeing
memory after the first time the DLL is called.
C++ Builder Code
~~~~~~~~~~~~~~
in header file ....
extern "C" __declspec(dllexport) bool __stdcall ShowEditor(char *);
in source file ...
bool __stdcall ShowEditor(char *ls_body)
{
int retCode = 0;
MainForm = new TMainForm(NULL);
//Create a memory stream to convert the string recieved from PowerBuilder
TMemoryStream *ms = new TMemoryStream();
ms->Write(ls_body,strlen(ls_body)+1);
ms->Position=0;
//Load the RTE
MainForm->RichEdit1->Lines->LoadFromStream(ms);
//Clear the Memory Stream to prepare for return trip
ms->Clear();
//Use editor
MainForm->ShowModal();
//Get All text from RTE
MainForm->RichEdit1->Lines->SaveToStream(ms);
ms->Position=0;
//Write Encoded text to string for PB
retCode = ms->Read(ls_body, ms->Size + 1);
delete MainForm;
delete ms;
return retCode;
}
Power Builder (the caller)
~~~~~~~~~~~~~~~~~~~
local external function declaration:
Public Function boolean ShowEditor(ref string lb_body) Library
"F:ProgrammingricheditDLLRichEditDLL.dll"
in onclick handler ...
string ls_body
boolean lb_retCode
//allocate space for the string
ls_body = space(10000)
lb_retCode = ShowEditor(ls_body)
if (lb_retCode) then
mle_1.text = ls_body
end if
//visual check to ensure we're within array bounds.
MessageBox("PB",string(rte_note))
Anyways, any comments would be greatly appreciated. I've aged over this ...
Gordon Cross
[email]gcross (AT) allnorth (DOT) com[/email]
|
|
| Back to top |
|
 |
Remy Lebeau (TeamB) Guest
|
Posted: Mon Sep 27, 2004 9:59 pm Post subject: Re: Access Violation in DLL |
|
|
"Gord Cross" <g.cross (AT) allnorth (DOT) com> wrote
| Quote: | ms->Write(ls_body,strlen(ls_body)+1);
|
You are not checking for ls_body to be NULL. If ls_body() is NULL, that
code will fail since strlen() will return 0 and you will be trying to access
more data then is actually available. In fact, you should get rid of the +1
altogether since the stream does not need to have the null terminator to
begin with.
| Quote: | //Load the RTE
MainForm->RichEdit1->Lines->LoadFromStream(ms);
|
What is the value of the RichEdit's PlainText property? If it is set to
true, then you don't need the stream at all, you could assign ls_body to the
RichEdit directly:
MainForm->RichEdit1->Text = ls_body;
| Quote: | //Write Encoded text to string for PB
retCode = ms->Read(ls_body, ms->Size + 1);
|
That is not a good way to handle things. For one thing, you are trying to
read more data then the stream actually has stored in it. Also, how are you
guaranteeing that the stored stream data won't exceed the size of ls_body's
allocated memory? I would strongly suggest that you add an additional
parameter to the function that specifies how large ls_body actually is, ie:
extern "C" __declspec(dllexport) bool __stdcall ShowEditor(char *, int);
#include <memory>
#include <algorithm>
bool __stdcall ShowEditor(char *ls_body, int max_body)
{
if( ls_body == NULL )
return false;
//Create a memory stream to convert the string recieved from
PowerBuilder
std::auto_ptr<TMemoryStream> ms(new TMemoryStream);
ms->Write(ls_body, strlen(ls_body));
ms->Position = 0;
//Load the RTE
std::auto_ptr<TMainForm> MainForm(new TMainForm(NULL));
MainForm->RichEdit1->Lines->LoadFromStream(ms.get());
//Clear the Memory Stream to prepare for return trip
ms->Clear();
//Use editor
MainForm->ShowModal();
//Get All text from RTE
MainForm->RichEdit1->Lines->SaveToStream(ms.get());
ms->Position = 0;
//Write Encoded text to string for PB
int retCode = ms->Read(ls_body, std::min(ms->Size, max_body));
if( retCode < max_body )
memset(&ls_body[retCode], 0, max_body-retCode);
return (retCode > 0);
}
Alternatively (depending on your needs):
extern "C" __declspec(dllexport) bool __stdcall ShowEditor(char *, int);
#include <memory>
#include <algorithm>
#include <stdio.h>
bool __stdcall ShowEditor(char *ls_body, int max_body)
{
if( ls_body == NULL )
return 0;
//Load the RTE
std::auto_ptr<TMainForm> MainForm(new TMainForm(NULL));
MainForm->RichEdit1->Text = ls_body;
//Use editor
MainForm->ShowModal();
//Write Encoded text to string for PB
int max = std::min(MainForm->RichEdit1->GetTextLen(), max_body);
return strncpy(ls_body, MainForm->RichEdit1->Text.c_str(), max);
}
Then you can call it like this (I don't know PB so this is a guess):
Public Function boolean ShowEditor(ref string lb_body, val int lb_max)
Library "F:ProgrammingricheditDLLRichEditDLL.dll"
lb_retCode = ShowEditor(ls_body, 10000)
Gambit
|
|
| Back to top |
|
 |
Gord Cross Guest
|
Posted: Tue Sep 28, 2004 4:43 pm Post subject: Re: Access Violation in DLL (Case Solved ...) |
|
|
Remy,
First a thanks for your help. I have been trying your suggestions. The
problems I was having were because I was whacking the null terminator for
the char * passed to the dll. I was overwriting it with my messy TMemory
stream calls (thanks).
Further, when writing the char * back I was using strncpy(char *dest, char
*src, MAX_LEN) - shame on me. If MAX_LEN is set to the actual max length of
the string - wups, there goes the NULL terminator for my char * again
leaving powerbuilder to float off into space when it tried to read the
string upon return (aka Access Violation). Should have been
strncpy(char *dest, char *src, MAX_LEN - 1);
And a final note. Something bizarre with the RichTextEdit->Text = "test";
it does not populate the control with the word 'test'. I've read about
problems with the Text property.
Anyways, Thanks for the help.
"Remy Lebeau (TeamB)" <no.spam (AT) no (DOT) spam.com> wrote
| Quote: |
"Gord Cross" <g.cross (AT) allnorth (DOT) com> wrote in message
news:41587de3$1 (AT) newsgroups (DOT) borland.com...
ms->Write(ls_body,strlen(ls_body)+1);
You are not checking for ls_body to be NULL. If ls_body() is NULL, that
code will fail since strlen() will return 0 and you will be trying to
access
more data then is actually available. In fact, you should get rid of the
+1
altogether since the stream does not need to have the null terminator to
begin with.
//Load the RTE
MainForm->RichEdit1->Lines->LoadFromStream(ms);
What is the value of the RichEdit's PlainText property? If it is set to
true, then you don't need the stream at all, you could assign ls_body to
the
RichEdit directly:
MainForm->RichEdit1->Text = ls_body;
//Write Encoded text to string for PB
retCode = ms->Read(ls_body, ms->Size + 1);
That is not a good way to handle things. For one thing, you are trying to
read more data then the stream actually has stored in it. Also, how are
you
guaranteeing that the stored stream data won't exceed the size of
ls_body's
allocated memory? I would strongly suggest that you add an additional
parameter to the function that specifies how large ls_body actually is,
ie:
extern "C" __declspec(dllexport) bool __stdcall ShowEditor(char *,
int);
#include <memory
#include
bool __stdcall ShowEditor(char *ls_body, int max_body)
{
if( ls_body == NULL )
return false;
//Create a memory stream to convert the string recieved from
PowerBuilder
std::auto_ptr
ms->Write(ls_body, strlen(ls_body));
ms->Position = 0;
//Load the RTE
std::auto_ptr<TMainForm> MainForm(new TMainForm(NULL));
MainForm->RichEdit1->Lines->LoadFromStream(ms.get());
//Clear the Memory Stream to prepare for return trip
ms->Clear();
//Use editor
MainForm->ShowModal();
//Get All text from RTE
MainForm->RichEdit1->Lines->SaveToStream(ms.get());
ms->Position = 0;
//Write Encoded text to string for PB
int retCode = ms->Read(ls_body, std::min(ms->Size, max_body));
if( retCode < max_body )
memset(&ls_body[retCode], 0, max_body-retCode);
return (retCode > 0);
}
Alternatively (depending on your needs):
extern "C" __declspec(dllexport) bool __stdcall ShowEditor(char *,
int);
#include <memory
#include
#include
bool __stdcall ShowEditor(char *ls_body, int max_body)
{
if( ls_body == NULL )
return 0;
//Load the RTE
std::auto_ptr
MainForm->RichEdit1->Text = ls_body;
//Use editor
MainForm->ShowModal();
//Write Encoded text to string for PB
int max = std::min(MainForm->RichEdit1->GetTextLen(), max_body);
return strncpy(ls_body, MainForm->RichEdit1->Text.c_str(), max);
}
Then you can call it like this (I don't know PB so this is a guess):
Public Function boolean ShowEditor(ref string lb_body, val int lb_max)
Library "F:ProgrammingricheditDLLRichEditDLL.dll"
lb_retCode = ShowEditor(ls_body, 10000)
Gambit
|
|
|
| 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
|
|