Problem calling unmanaged DLL from VB.NET

  • Thread starter Thread starter Marc Hillman
  • Start date Start date
M

Marc Hillman

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.
 
Am 02.03.2010 13:20, schrieb Marc Hillman:
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.

You're bashing your head against the wall. ;)
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

Try
BYVAL Version As StringBuilder
 
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?

(and thanks heaps for your really rapid response)
 
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?
 
Marc said:
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".
 
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.
 
Am 02.03.2010 14:01, schrieb Marc Hillman:





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 todeclare it
with the type String(builder). Anyone?

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 :)
 
Am 02.03.2010 23:29, schrieb Tom Shelton:

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 :)
 
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.
 
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.

Ok... cool. I wasn't sure if you needed that either. The documentation was a
bit cloudy and I don't know pascal all that well - so I wasn't sure if the
return was a pointer-to-pointer (which is what I assumed and why I had the
readintptr) or just a pointer. I'm glad you figured it out though :)
 
Marc Hillman said:
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.

The only reward we normally look for is a final post explaining the
exact solution you found. The above doesn't really explain it. :-)
 
But for those who help it is very useful.


Mark Hurd said:
The only reward we normally look for is a final post explaining the exact
solution you found. The above doesn't really explain it. :-)
 
Back
Top