From: Marc Hillman on
Thanks Jason - I have read the documentation - several times. Many sites
recommend to use of StringBuilder over String because String is not
immutable (whatever that means).

As mention by Armin - pansichar is a pointer to an ANSI char string, and
it's passed by reference.

The important symptom here is that it all works fine on very small programs,
but not on larger ones. Somehow the return variables location in memory is
coming into play.

"Jason Keats" <jkeats(a)melbpcDeleteThis.org.au> wrote in message
news:uHZrQJiuKHA.796(a)TK2MSFTNGP05.phx.gbl...
> Marc Hillman wrote:
>> I've been bashing my head up against a brick wall for 4 days, and I've
>> reached the limit of my frustration and knowledge. I'd appreciate some
>> ideas on what I'm doing wrong.
>>
>> I have a simple Visual Basic Express 2008 program. It calls a DLL
>> (supplied by others). Calls to the DLL in small (trivial) programs work
>> fine. When the program grows in size I get a "vshost.exe has stopped
>> working" message. It happens when I call any dll function that tries to
>> return a string. I have googled and tried everything.
>>
>> The full program is a few thousand lines, much of it auto coded because
>> of database access, but the critical bits are below.
>>
>> In fileOziExplorer.vb
>> Imports System.Text
>> Module OziExplorer
>> Declare Ansi Function oziGetOziVersion Lib "oziapi" (ByRef Version As
>> StringBuilder, ByRef DataLength As Integer) As Integer
>> End Mdule
>>
>> In file Form1.vb
>> Dim oziVersion As New StringBuilder(250), vDatalength As Integer
>> i = oziGetOziVersion(oziVersion, vDatalength)
>>
>> When the i=oziGetOziVersion is called I get the vshost error message.
>>
>> I have hacked vshost.exe to disable DEP.
>>
>> I'm totally out of ideas. All the obvious fixes have been tried.
>>
>>
>>
>
> Have you read the documentation?
>
> http://www.oziexplorer3.com/oziapi/oziapi_docs.html#oziGetOziVersion
>
> For starters, I would change "As StringBuilder" to "As String".
>
From: Tom Shelton on
On Mar 2, 9:01 am, Armin Zingler <az.nos...(a)freenet.de> wrote:
> Am 02.03.2010 14:01, schrieb Marc Hillman:
>
> > Good news and bad news.
>
> > The app no longer crashes, but the return results are curious. For the line
> > i = oziGetOziVersion(oziVersion, vDatalength)
>
> > 1.  vDatalength is 0
> > 2. when I assign st (a string)=oziVersion.tostring the result is gibberish
> > 3. oziVersion.Length is correct (6)
>
> > I think I'm close. How do I get the string out of the StringBuilder?
>
> I had searched for the function declaration and found
>
>   function oziGetOziVersion(var Version:pansichar;var DataLength:integer):integer;stdcall;
>
> I'm not sure how to translate "var Version:pansichar". I guess that "p"ansichar is a
> pointer to an ANSI char/string. In addition, var means it's passed by reference.
> So a pointer to a pointer is passed, right? By heart, I don't know how to declare it
> with the type String(builder). Anyone?
>
> --
> Armin

Looking at the documentation, I don't think you can use StringBuilder
here. It sounds like the API returns a pointer to an internal
buffer. Which you then need to copy to your own string. The buffers
may be reused. So, my guess is that this function has to be declared
like:

Declare Function oziGetOziVersion Lib "oziapi" (ByRef vVersion As
IntPtr, ByRef DataLength As Integer) As Integer

Then used something like:

Dim strPtr As IntPtr
Dim vLength As Integer

oziGetOziVersion (strPtr, vLength)
dim bufferptr as intptr = marshal.ReadIntPtr(strPtr)
string version = marshal.ptrtostringansi(bufferprt, vlength)

something like that anway... if i read the documentation right :)
From: Armin Zingler on
Am 02.03.2010 23:29, schrieb Tom Shelton:
>
> something like that anway... if i read the documentation right :)

Yes, thanks. That what I wasn't sure about.

--
Armin
From: Tom Shelton on
On 2010-03-02, Armin Zingler <az.nospam(a)freenet.de> wrote:
> Am 02.03.2010 23:29, schrieb Tom Shelton:
>>
>> something like that anway... if i read the documentation right :)
>
> Yes, thanks. That what I wasn't sure about.
>

What I'm not sure is if it's returning a ptr to a ptr to the buffer or a ptr
to the buffer, so some adjustment maybe needed to avoid a nasty crash :)

--
Tom Shelton
From: Marc Hillman on
Success Tom - thanks a million. Did not need the "dim bufferptr as intptr =
marshal.ReadIntPtr(strPtr)" statement." IntPtr is new to me, as is Marshal,
but I think I understand enough to fix all the other similar issues.

I still don't understand why 'simple' version of the code work with String
types, but it's great to finally have a solution. Thanks again.

It never ceases to amaze me the number of people who willingly help others
for no obvious reward.

"Tom Shelton" <tom_shelton(a)comcast.net> wrote in message
news:3472b5dd-6b44-4cd1-b2a7-686db2ac0da9(a)m27g2000prl.googlegroups.com...
> On Mar 2, 9:01 am, Armin Zingler <az.nos...(a)freenet.de> wrote:
>> Am 02.03.2010 14:01, schrieb Marc Hillman:
>>
>> > Good news and bad news.
>>
>> > The app no longer crashes, but the return results are curious. For the
>> > line
>> > i = oziGetOziVersion(oziVersion, vDatalength)
>>
>> > 1. vDatalength is 0
>> > 2. when I assign st (a string)=oziVersion.tostring the result is
>> > gibberish
>> > 3. oziVersion.Length is correct (6)
>>
>> > I think I'm close. How do I get the string out of the StringBuilder?
>>
>> I had searched for the function declaration and found
>>
>> function oziGetOziVersion(var Version:pansichar;var
>> DataLength:integer):integer;stdcall;
>>
>> I'm not sure how to translate "var Version:pansichar". I guess that
>> "p"ansichar is a
>> pointer to an ANSI char/string. In addition, var means it's passed by
>> reference.
>> So a pointer to a pointer is passed, right? By heart, I don't know how to
>> declare it
>> with the type String(builder). Anyone?
>>
>> --
>> Armin
>
> Looking at the documentation, I don't think you can use StringBuilder
> here. It sounds like the API returns a pointer to an internal
> buffer. Which you then need to copy to your own string. The buffers
> may be reused. So, my guess is that this function has to be declared
> like:
>
> Declare Function oziGetOziVersion Lib "oziapi" (ByRef vVersion As
> IntPtr, ByRef DataLength As Integer) As Integer
>
> Then used something like:
>
> Dim strPtr As IntPtr
> Dim vLength As Integer
>
> oziGetOziVersion (strPtr, vLength)
> dim bufferptr as intptr = marshal.ReadIntPtr(strPtr)
> string version = marshal.ptrtostringansi(bufferprt, vlength)
>
> something like that anway... if i read the documentation right :)