C++ DLL in VB crashing issue

I have a dll that someone made me in C++. I needed to use this dll in VB, in order to do that I had to make another dll in C++ that has functions I can call in VB.

The C++ dll I made has 4 functions. 2 callback functions that retrieve information from the original C++. And 2 functions that I can call from VB to send that information.

I know the original dll works fine as Ive tested it endlessly in a console app.

However when I use it with my dll and VB.. I get random crashes.

There is almost no code in my VB app as its just for testing. It just outputs the information so theres no problem there.

I believe the problem is in the C++ dll I made. I am pretty new with C++.
I think maybe a variable gets accessed in 2spots at the same time (is this possible?) and causes it to crash?

Heres the basic layout of my C++ dll

//global variables
CString allInfo="";
char* info=new char[25000];

//call back function 1
HANDLE OnInfo(SendInfo* tempInfo)
{
    CString stringTemp="";
    stringTemp=tempInfo->infomessage;
    allInfo=allInfo+ stringTemp+"\n";
    return 0;
}

//function for vb
BSTR _stdcall vbInfo()
{
    allInfo=allInfo.Right(20000); //get last 20,000 characters
    strcpy_s(info,20000,allInfo);
    BSTR Message;
    Message = SysAllocStringByteLen (info, lstrlen(info));
    return Message;
}

Crash seems to happen completely randomly.

Any suggestions?

Thanks
bail3yzAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

uboundCommented:
Given how little info you provide, I'm not sure how helpful I can be.  But I do have a few thoughts:

1) You express concern about variables being accessed in two places at once.  There is certainly nothing in this code that would prevent that from happening, and if it did, bad things would result.  

It appears that the intent here is that OnInfo gets called to build up a string, and eventually that string is retrieved from vb by calling vbInfo.  If that's the case, there is nothing to stop OnInfo from being called in the middle of vb calling vbInfo.

2) vbInfo doesn't clear out allInfo when it returns it.  Is this by design?

3) There seems to be some confusion in this code between ASCII and Unicode.  BSTRs are unicode, but strcpy works with ASCII.  What's the intent here?

4) You don't show how vbInfo is declared in vb.  If vb isn't told that this is a BSTR being returned, I believe the memory will leak.  That could eventually cause a crash.

Best I can do with what I see here.
0
bail3yzAuthor Commented:
1) ya I don't really know what I am doing.

2) correct

3) not really sure.  all I know is I need BSTR to send for VB to use as string.  I just googled how to convert from char to BSTR (this was before I was using CString) so I stuck with that.  Conversion seems to work.

4)
Public Declare Function getInfoLib "cppdll.dll" () As String

No mem leak as far as I know.  Also worth nothing this was working perfectly before.  The crush time is completely random.  The stream of data is  consistent.  if it was a mem leak I believe it would occur near the same time everytime.  And I can see the mem use of the process doesnt increase much.


Ive been doing a lot of guessing and checking.. and Ive changed the above code to the following



//call back function 1
HANDLE OnInfo(SendInfo* tempInfo)
{
    CString stringTemp="";
    stringTemp=tempInfo->infomessage;
    allInfo+= stringTemp+"\n";

    if (allInfo.GetLength()>20000)
            allInfo=allInfo.Mid(allInfo.GetLength()-15000,allInfo.GetLength());
    return 0;
}

//function for vb
BSTR _stdcall vbInfo()
{
   
    strcpy_s(info,25000,allInfo);
    BSTR Message;
    Message = SysAllocStringByteLen (info, lstrlen(info));
    return Message;
}


strcpy_s(info,25000,allInfo); //when this is at 20000 it would still crash sometimes.  I am guessing that sometimes OnInfo is called and updates allInfo and then vbInfo is called before the >20000 if statement?  Not sure if thats possible

I imagine this is a sloppy fix, but seems to be working.

If allInfo is updated when vbInfo is called, providing it doesnt cause any crashes then its not a concern to me.  Since vbInfo is only reading the variable, I think its fine?

Also there is another function like OnInfo that gets info from another source but also adds it to allinfo.  It is also a callback function so I dont know if it will ever be ran at same time as OnInfo.  Ive been running the program for 30-40 mins now calling the VB function every 100ms and it hasnt crashed yet since I made the above changes.. normally it would crash a lot sooner.



0
sarabandeCommented:
the problem probably was the strcpy_s which didn't consider a final terminating zero character.

so when the length of 20000 was reached in allinfo the string in info was not properly terminated after copy what means that strlen(info) would return a length greater 20000 until it finds a zero character by accident.

i think you should omit all the char arrays and string copy things and have only one global CString. you best would put it in a little class like

class Global
{
public:
    static CString &  get_allinfo() {  static CString allinfo; return allinfo; }
};

Open in new window


in the OnInfo you would do

// get a reference to global string
CString & allinfo = Global::get_allinfo();
// add new line
allinfo += CString(ptempInfo) + "\n";
// check length
int len =allinfo.GetLength();
if  (len > 20000)
{
     int nstart = 0;
     int npos  = 0;
     // search for line ends until rest length < 20000
     while ((npos = allinfo.Find(_T('\n'), nstart)) < len - 20000)
     {
           nstart = npos+1;
     }
     // take rest  
    allInfo = allinfo.Left(nstart);
}

Open in new window


and in the vbInfo you simply do


BSTR Message;
int len = Global::get_allinfo().GetLength();
Message = SysAllocStringByteLen ((LPCTSTR)Global::get_allinfo(), len+1 );

Open in new window


the cast to LPCTSTR not really is necessary cause CString has an implicit cast for that. but it shows what happens: you were copying the internal string buffer of the global CString to a BSTR which then was returned to VB.

Sara






0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
bail3yzAuthor Commented:
Thanks Sara!

I am leaving for a flight in an hour and won't be back until Monday, but I will try this and let you know what happens when I get back!

Thanks again.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.