Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How can I access data from a pointer to an integer

Status
Not open for further replies.

sgursahaney

Programmer
Jun 11, 2001
57
US
Hello. I am using a VB program to call a Win32 API. The API I am using returns a pointer to an Integer value. I have declared the external function as such:

Public Declare Function sr_getevtdatap Lib "libsrlmt" () As Long

The C equivalent of this function is:

int *sr_getevtdatap()

Since the function is returning a pointer to an Integer rather than an Integer itself, I don't know how to access the actual integer value from within VB. Can anybody help me with this problem?

Regards,
Suresh
 
The only VB feature I know of that even deals remotely with pointers (except ByRef and ByVal) is AddressOf, but unfortunately that also returns a pointer to its variable argument. You may be able to use CopyMemory (in an unorthodox way I admit) to copy the value of the returned pointer to the AddressOf an int variable u define. This would only work if CopyMemory accepts pointers as arguments, and I'm sorry I don't remember if it does (my computer is being reimaged, VS is gone for now)

Hope that makes sense!

-Mike Difference between a madman and a genius:
A madman uses his genius destructively,
A genius uses his madness constructively.
 
Funny you should mention CopyMemory. I came across this article in another forum:

Most people think that Visual Basic does not have
pointers and hence is not capable of handling data
structures that requre pointers (by the way these data
structures can be implemented using classes).

Well, they are right but not for very long. Since Visual Basic
has access to the entire Win 32 API it is not so difficult
to equip it with pointers.Let's look at a simple code fragment
in C and then at its VBasic equivalent.

-----------------------------------------------------------------

#include
#include

int main(int argc, char* argv[])
{
int * ptr; //1
ptr=(int *)malloc(sizeof(int)); //2
*ptr=10; //3
printf("The address of ptr is %d and its values is %d\n",ptr,*ptr); //4
free(ptr); //5
return 0;
}

----------------------------------------------------------------

I have marked the lines with numbers so you ,the reader, can
follow more easily.

The eqivalent of the first line is

dim ptr as long 'int * ptr;

This was easy because it follows from the definition of the
pointer. A pointer is just a variable whose value is the
address of another variable. It is long because a pointer
in MS Windows is 4 bytes.

The second line:
ptr=(int *)malloc(sizeof(int));
Well how do we allocate memory dynamically in Visual Basic?
Malloc has no equivalent. Here we'll use the Win 32 API
function HeapAlloc(...).Please check the documentation for more
information on it.

So here's our code:
Dim hHeap As Long
hHeap = GetProcessHeap()
ptr=HeapAlloc(hHeap,0,2) 'an integer in Visual Basic is 2 bytes

We can even check if memory was allocated

if ptr<>0 then
'memory was allocated
'do stuff
end if


Now *ptr=10;
In Visual Basic we'll use the function CopyMemory which is
declared like so
--------------------------------------------------------------
Public Declare Sub CopyMemory Lib &quot;kernel32&quot; Alias _
&quot;RtlMoveMemory&quot; (Destination As Any, Source As Any, _
ByVal Length As Long)
------------------------------------------------------------------

Here's the little trick :
I modify the parameters and have two more definitions

------------------------------------------------------
'to write to memory
Public Declare Sub CopyMemoryWrite Lib &quot;kernel32&quot; Alias _
&quot;RtlMoveMemory&quot; (Byval Destination As long, Source As Any, _
ByVal Length As Long)
------------------------------------------------------
' to read from memory
Public Declare Sub CopyMemoryRead Lib &quot;kernel32&quot; Alias _
&quot;RtlMoveMemory&quot; (Destination As Any,byval Source As Long, _
ByVal Length As Long)
------------------------------------------------------

Now here's how
*ptr=10;
translates into Visual Basic

dim i as integer
i=10
CopyMemoryWrite ptr,i,2 ' an intger is two bytes



Now towards line 5.
printf(&quot;%d\n&quot;,*ptr);

dim j as integer
CopyMemoryRead j,ptr,2
MsgBox &quot;The adress of ptr is &quot; & cstr(ptr) & _
vbCrlf & &quot;and the value is &quot; & cstr(j)


Now free the memory

HeapFree GetProcessHeap(),0,ptr


That's all.

Here is the complete listing of the source code:
(just copy it into a project and run it).

-------------------------------------------------------
=======================================================
=======================================================
The Real stuff is here
-----------------------------------------------------
Option Explicit


Private Declare Sub CopyMemory Lib &quot;kernel32&quot; Alias &quot;RtlMoveMemory&quot; (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function GetProcessHeap Lib &quot;kernel32&quot; () As Long
Private Declare Function HeapAlloc Lib &quot;kernel32&quot; (ByVal hHeap As Long, ByVal dwFlags As Long, ByVal dwBytes As Long) As Long
Private Declare Function HeapFree Lib &quot;kernel32&quot; (ByVal hHeap As Long, ByVal dwFlags As Long, lpMem As Any) As Long
Private Declare Sub CopyMemoryWrite Lib &quot;kernel32&quot; Alias &quot;RtlMoveMemory&quot; (ByVal Destination As Long, Source As Any, ByVal Length As Long)
Private Declare Sub CopyMemoryRead Lib &quot;kernel32&quot; Alias &quot;RtlMoveMemory&quot; (Destination As Any, ByVal Source As Long, ByVal Length As Long)

Private Sub Form_Load()
Dim ptr As Long 'int * ptr;
Dim hHeap As Long
hHeap = GetProcessHeap()
ptr = HeapAlloc(hHeap, 0, 2) 'an integer in Visual Basic is 2 bytes
If ptr <> 0 Then
'memory was allocated
'do stuff
Dim i As Integer
i = 10
CopyMemoryWrite ptr, i, 2 ' an intger is two bytes
Dim j As Integer
CopyMemoryRead j, ptr, 2
MsgBox &quot;The adress of ptr is &quot; & CStr(ptr) & _
vbCrLf & &quot;and the value is &quot; & CStr(j)
HeapFree GetProcessHeap(), 0, ptr
End If
End Sub






----------------------------------------
Bonus:




Here is a simple and not complete implmemtation of
a linked list. (On the form put a Command button named Command1)



Option Explicit
Private Declare Sub CopyMemory Lib &quot;kernel32&quot; Alias &quot;RtlMoveMemory&quot; (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function GetProcessHeap Lib &quot;kernel32&quot; () As Long
Private Declare Function HeapAlloc Lib &quot;kernel32&quot; (ByVal hHeap As Long, ByVal dwFlags As Long, ByVal dwBytes As Long) As Long
Private Declare Function HeapFree Lib &quot;kernel32&quot; (ByVal hHeap As Long, ByVal dwFlags As Long, lpMem As Any) As Long
Private Declare Sub CopyMemoryPut Lib &quot;kernel32&quot; Alias &quot;RtlMoveMemory&quot; (ByVal Destination As Long, Source As Any, ByVal Length As Long)
Private Declare Sub CopyMemoryRead Lib &quot;kernel32&quot; Alias &quot;RtlMoveMemory&quot; (Destination As Any, ByVal Source As Long, ByVal Length As Long)

Dim pHead As Long
Private Type ListElement
strData As String * 255 '==255 * 2=500 bytes vbStrings are UNICODE !
pNext As Long '4 bytes
'pointer to next ; ==0 if end of list
'----------------
'total: 504 bytes
End Type

Private Sub CreateLinkedList()
'add three items to list
' get the heap first
Dim pFirst As Long, pSecond As Long 'local pointers
Dim hHeap As Long
hHeap = GetProcessHeap()
'allocate memory for the first and second element
pFirst = HeapAlloc(hHeap, 0, 504)
pSecond = HeapAlloc(hHeap, 0, 504)
If pFirst <> 0 And pSecond <> 0 Then
'memory is allocated
PutDataIntoStructure pFirst, &quot;Hello&quot;, pSecond
PutDataIntoStructure pSecond, &quot;Pointers&quot;, 0
pHead = pFirst
End If
'put he second element in the list
End Sub
Private Sub Command1_Click()
CreateLinkedList
ReadLinkedListDataAndFreeMemory
End Sub

Private Sub PutDataIntoStructure(ByVal ptr As Long, szdata As String, ByVal ptrNext As Long)
Dim le As ListElement
le.strData = szdata
le.pNext = ptrNext
CopyMemoryPut ptr, le, 504
End Sub
Private Sub ReadDataToStructure(ByVal ptr As Long, struct As ListElement)
Dim le As ListElement
CopyMemoryRead le, ptr, 504
struct.strData = le.strData
struct.pNext = le.pNext
End Sub

Private Sub ReadLinkedListDataAndFreeMemory()
Dim pLocal As Long
Dim hHeap As Long
Dim le As ListElement
Dim strData As String
pLocal = pHead
hHeap = GetProcessHeap()
Do While pLocal <> 0
ReadDataToStructure pLocal, le
strData = strData & vbCrLf & le.strData
HeapFree hHeap, 0, pLocal
pLocal = le.pNext
Loop
MsgBox strData
End Sub

Private Sub Form_Load()

End Sub
 
Good stuff here, no doubt. I would, however, be attentitive about iterating over pointer array elements in this way. C/C++ compilers already know the size of each data type (assuming you may use this tecnique for data other than integer, ANSI standards are loose here), so they also know how much to increment the pointer when you say ptr++ in your loop. Use the SizeOf VB function as a workaround, and you should have everything you need. Did this answer your Q?

-Mike Difference between a madman and a genius:
A madman uses his genius destructively,
A genius uses his madness constructively.
 
Option Explicit
Private Declare Sub CopyMemory Lib &quot;kernel32&quot; Alias &quot;RtlMoveMemory&quot; (Destination As Any, Source As Any, ByVal Length As Long) 'Long live Bruce McKinney...

Function PointerToInt(ByVal dw As Long) As Integer
CopyMemory PointerToInt, ByVal dw, 2
End Function
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top