dotnet interop:
No problem, but first a few questions: Do you know how many names will be returned? Are you supposed to allocate buffers for the data to be populated does the dll allocate the memory for the Strings (and you must have to free it later)? Tom [quoted text, click to view] Jeremy wrote: > Hello, > > I have an unmanaged c++ dll which exports the function: > > long GetAllFormationNames(long LithSchemeID, long LevelID, int & > numData, long ** Ids, char *** Names); > > it's the final argument that I am having trouble converting/calling > from VB.NET - everything I have tried has resulted in either an array > containing rubbish or an array with 1 element containing only the > first element that *should* be returned > > I am rather new to the .Net thing - so be gentle! > > Jeremy
Hello, I have an unmanaged c++ dll which exports the function: long GetAllFormationNames(long LithSchemeID, long LevelID, int & numData, long ** Ids, char *** Names); it's the final argument that I am having trouble converting/calling from VB.NET - everything I have tried has resulted in either an array containing rubbish or an array with 1 element containing only the first element that *should* be returned I am rather new to the .Net thing - so be gentle!
It certainly does. Here is what I recommend. Pass a ByRef IntPtr to the Names parameter. This will get you the address of the array. Of course, this array is really a continuous block of memory that has consecutive pointers to your strings (char arrays). You can use Marshal.ReadIntPtr(ptr, offset) to walk the array and get the IntPtrs to the actual data. [quoted text, click to view] >From those IntPtrs you can use Marshal.PtrToStringAnsi (or one of the
other Marshal.PtrToStringXXX methods) to get a .NET String. Don't forget to call whatever method the dll provides to free the memory is allocated for this call. Tom [quoted text, click to view] Jeremy wrote: > Hi, > > 1. I don't know in advance how many names will be returned - the > returned parameter numData is the number of names returned.. > > 2.. the dll allocates the memory for the strings. > > hope that makes it clearer! > > Regards, > > Jeremy > > On 24 Aug 2006 05:11:56 -0700, "TDC" <NOtcarvinSPAM@lycos.com> wrote: > > >No problem, but first a few questions: > > > >Do you know how many names will be returned? Are you supposed to > >allocate buffers for the data to be populated does the dll allocate the > >memory for the Strings (and you must have to free it later)? > > > >Tom > > > >Jeremy wrote: > >> Hello, > >> > >> I have an unmanaged c++ dll which exports the function: > >> > >> long GetAllFormationNames(long LithSchemeID, long LevelID, int & > >> numData, long ** Ids, char *** Names); > >> > >> it's the final argument that I am having trouble converting/calling > >> from VB.NET - everything I have tried has resulted in either an array > >> containing rubbish or an array with 1 element containing only the > >> first element that *should* be returned > >> > >> I am rather new to the .Net thing - so be gentle! > >> > >> Jeremy
Jeremy, Christian is correct (though you'd eventually put it in a for loop to get all the strings, not just the first one). By the way, a C++ longs is an VB Integer (or Int32 or UInt32) in .NET so you have another slight error. Tom [quoted text, click to view] Christian Fr=F6schlin wrote: > Jeremy wrote: > > >>r =3D GetAllFormationNames(1, 2, numdata, ids, ip) > >> > >>ReDim formations(numdata) > >> > >>formations(0) =3D Marshal.PtrToStringAuto(ip) > > You missed one level of indirection: ip does not point > to string data, it points to the array of char pointers. > Try Marshal.PtrToStringAuto(Marshal.ReadIntPtr(ip,0)).
I think offset is a byte-offset as opposed to an IntPtr-width offset. In other words, since an IntPtr is 4 bytes, increment the offset by 4 each time. Tom [quoted text, click to view] Jeremy wrote: > Aha - now we are getting there.. > > I can now get a whole array of strings back like this: > > >r =3D GetAllFormationNames(1, 2, numdatap, idsp, ipp) > > > > ReDim formationnames(numdatap) > > > > formationnames(0) =3D Marshal.PtrToStringAnsi(Marshal.ReadIntPtr= (ipp, 0)) > > > > If numdatap > 1 Then > > Dim offset As Integer > > offset =3D formationnames(0).Length > > For r =3D 1 To numdatap - 1 > > While formationnames(r) =3D "" Or IsNothing(formationnam= es(r)) > > formationnames(r) =3D Marshal.PtrToStringAnsi(Marsha= l=2EReadIntPtr(ipp, offset)) > > offset =3D offset + 1 > > End While > > > > Debug.Print(r & " : " & offset & " : " & formationnames(= r)) > > Next > > End If > > however at (seemingly) random points in the formationnames array I get > short (1 or 2 chars) strings of characters with ascii values over 128 > - I originally tried incrementing offset by the value of the last > string found instead of by 1, but then I found that a lot of the > elements of formationnames were empty.. > > ..I can write a check to ensure that the strings returned are > alphanumeric, but that's a rather ugly solution! > > anyway - thanks for the help in getting to this point! > > Jeremy > > On Fri, 25 Aug 2006 16:49:13 +0200, Christian Fr=F6schlin > <froeschlin@mvtec.com> wrote: > > >Jeremy wrote: > > > >>>r =3D GetAllFormationNames(1, 2, numdata, ids, ip) > >>> > >>>ReDim formations(numdata) > >>> > >>>formations(0) =3D Marshal.PtrToStringAuto(ip) > > > >You missed one level of indirection: ip does not point > >to string data, it points to the array of char pointers. > >Try Marshal.PtrToStringAuto(Marshal.ReadIntPtr(ip,0)).
Just noticed your while...I don't know why that is there. It should look more like this: For ndx as Integer = 0 to numOfNames -1 formationnames(ndx) = Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(ptr, offset)) offset += 4 Next ndx Tom
Hi, 1. I don't know in advance how many names will be returned - the returned parameter numData is the number of names returned.. 2.. the dll allocates the memory for the strings. hope that makes it clearer! Regards, Jeremy [quoted text, click to view] On 24 Aug 2006 05:11:56 -0700, "TDC" <NOtcarvinSPAM@lycos.com> wrote: >No problem, but first a few questions: > >Do you know how many names will be returned? Are you supposed to >allocate buffers for the data to be populated does the dll allocate the >memory for the Strings (and you must have to free it later)? > >Tom > >Jeremy wrote: >> Hello, >> >> I have an unmanaged c++ dll which exports the function: >> >> long GetAllFormationNames(long LithSchemeID, long LevelID, int & >> numData, long ** Ids, char *** Names); >> >> it's the final argument that I am having trouble converting/calling >> from VB.NET - everything I have tried has resulted in either an array >> containing rubbish or an array with 1 element containing only the >> first element that *should* be returned >> >> I am rather new to the .Net thing - so be gentle! >>
OK - I tried this: [quoted text, click to view] >Dim formations As String() >Dim r As Long >Dim ids As IntPtr >Dim numata as Long >Dim ip As IntPtr > >r = GetAllFormationNames(1, 2, numdata, ids, ip) > >ReDim formations(numdata) > >formations(0) = Marshal.PtrToStringAuto(ip)
the resulting string looks like rubbish though (I tried the other PtrToStringxxx functions too) ... I know the dll function works btw as I can call it from C++ hmm.. any more ideas? Cheers, Jeremy [quoted text, click to view] On 25 Aug 2006 05:30:26 -0700, "TDC" <NOtcarvinSPAM@lycos.com> wrote: >It certainly does. > >Here is what I recommend. Pass a ByRef IntPtr to the Names parameter. > > >This will get you the address of the array. Of course, this array is >really a continuous block of memory that has consecutive pointers to >your strings (char arrays). > >You can use Marshal.ReadIntPtr(ptr, offset) to walk the array and get >the IntPtrs to the actual data. > >>From those IntPtrs you can use Marshal.PtrToStringAnsi (or one of the >other Marshal.PtrToStringXXX methods) to get a .NET String. > >Don't forget to call whatever method the dll provides to free the >memory is allocated for this call. > >Tom > > >Jeremy wrote: >> Hi, >> >> 1. I don't know in advance how many names will be returned - the >> returned parameter numData is the number of names returned.. >> >> 2.. the dll allocates the memory for the strings. >> >> hope that makes it clearer! >> >> Regards, >> >> Jeremy >> >> On 24 Aug 2006 05:11:56 -0700, "TDC" <NOtcarvinSPAM@lycos.com> wrote: >> >> >No problem, but first a few questions: >> > >> >Do you know how many names will be returned? Are you supposed to >> >allocate buffers for the data to be populated does the dll allocate the >> >memory for the Strings (and you must have to free it later)? >> > >> >Tom >> > >> >Jeremy wrote: >> >> Hello, >> >> >> >> I have an unmanaged c++ dll which exports the function: >> >> >> >> long GetAllFormationNames(long LithSchemeID, long LevelID, int & >> >> numData, long ** Ids, char *** Names); >> >> >> >> it's the final argument that I am having trouble converting/calling >> >> from VB.NET - everything I have tried has resulted in either an array >> >> containing rubbish or an array with 1 element containing only the >> >> first element that *should* be returned >> >> >> >> I am rather new to the .Net thing - so be gentle! >> >>
Aha - now we are getting there.. I can now get a whole array of strings back like this: [quoted text, click to view] >r = GetAllFormationNames(1, 2, numdatap, idsp, ipp) > > ReDim formationnames(numdatap) > > formationnames(0) = Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(ipp, 0)) > > If numdatap > 1 Then > Dim offset As Integer > offset = formationnames(0).Length > For r = 1 To numdatap - 1 > While formationnames(r) = "" Or IsNothing(formationnames(r)) > formationnames(r) = Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(ipp, offset)) > offset = offset + 1 > End While > > Debug.Print(r & " : " & offset & " : " & formationnames(r)) > Next > End If
however at (seemingly) random points in the formationnames array I get short (1 or 2 chars) strings of characters with ascii values over 128 - I originally tried incrementing offset by the value of the last string found instead of by 1, but then I found that a lot of the elements of formationnames were empty.. ...I can write a check to ensure that the strings returned are alphanumeric, but that's a rather ugly solution! anyway - thanks for the help in getting to this point! Jeremy On Fri, 25 Aug 2006 16:49:13 +0200, Christian Fröschlin [quoted text, click to view] <froeschlin@mvtec.com> wrote: >Jeremy wrote: > >>>r = GetAllFormationNames(1, 2, numdata, ids, ip) >>> >>>ReDim formations(numdata) >>> >>>formations(0) = Marshal.PtrToStringAuto(ip) > >You missed one level of indirection: ip does not point >to string data, it points to the array of char pointers.
[quoted text, click to view] Jeremy wrote: >>r = GetAllFormationNames(1, 2, numdata, ids, ip) >> >>ReDim formations(numdata) >> >>formations(0) = Marshal.PtrToStringAuto(ip)
You missed one level of indirection: ip does not point to string data, it points to the array of char pointers.
Jeremy, Be sure to let us know how you made out. That way everyone can learn what works and what doesn't. Tom [quoted text, click to view] TDC wrote: > Just noticed your while...I don't know why that is there. It should > look more like this: > > For ndx as Integer = 0 to numOfNames -1 > > formationnames(ndx) = > Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(ptr, offset)) > offset += 4 > > Next ndx > > Tom
Don't see what you're looking for? Try a search.
|