Is there any way to simulate or mimic a pointer like variable in VB?
Like in C there can be a pointer to some object, like a structure or an array for example, which in C could look like this:
Code:
typedef struct bal
{
float balance;
char name[80];
} person;
void someFunction()
{
'
'
bal *p; // Define a pointer to the bal structure
p = &person; // Make p equal the address of the bal structure
'
'
p->name = "James";
'
'
}
What I need is some way to do the same thing or close to the same thing
Last edited by jmsrickland; Dec 28th, 2014 at 04:26 PM.
Anything I post is an example only and is not intended to be the only solution, the total solution nor the final solution to your request nor do I claim that it is. If you find it useful then it is entirely up to you to make whatever changes necessary you feel are adequate for your purposes.
Yes. You can use pointers as addresses in long variables.
What you don't have at a first search is an VB allocating system to allocate memory. This can be done from api call.
This is a quicksort routine using CompareString, but where are the strings to compare?
In one string I have all the strings, and I pass the pointers to pos() array (long type), and because I have not use zero as end point I have to pass the length to slen() array.
So this routine works without moving strings to temporary buffers but straight in place.
Code:
Declare Function CompareString Lib "kernel32" Alias "CompareStringW" (ByVal Locale As Long, ByVal dwCmpFlags As Long, ByVal lpString1 As Long, ByVal cchCount1 As Long, ByVal lpString2 As Long, ByVal cchCount2 As Long) As Long
Public Sub QuickSortExtended(ByVal LB As Long, ByVal UB As Long)
Dim M1 As Long, M2 As Long, pivlen As Long
Dim Piv As Long, Tmp As Long '<- adjust types here, when switching to something different than Long
If UB - LB = 1 Then
M1 = LB
If CompareString(1033, 0, pos(M1), SLen(M1), pos(UB), SLen(UB)) = 3 Then ''
Tmp = pos(M1): pos(M1) = pos(UB): pos(UB) = Tmp
Tmp = SLen(M1): SLen(M1) = SLen(UB): SLen(UB) = Tmp
Tmp = hit(M1): hit(M1) = hit(UB): hit(UB) = Tmp
End If
Exit Sub
Else
M1 = (LB + UB) \ 2
If CompareString(1033, 0, pos(M1), SLen(M1), pos(LB), SLen(LB)) = 2 Then
M2 = UB - 1
M1 = LB
Do
M1 = M1 + 1
If M1 > M2 Then
If pos(UB) < pos(LB) Then
Tmp = pos(LB): pos(LB) = pos(UB): pos(UB) = Tmp
Tmp = SLen(LB): SLen(LB) = SLen(UB): SLen(UB) = Tmp
Tmp = hit(LB): hit(LB) = hit(UB): hit(UB) = Tmp
End If
Exit Sub
End If
Loop Until CompareString(1033, 0, pos(M1), SLen(M1), pos(LB), SLen(LB)) <> 2
Piv = pos(M1)
pivlen = SLen(M1)
If M1 > LB Then
If CompareString(1033, 0, pos(LB), SLen(LB), Piv, pivlen) = 3 Then ''''
Tmp = hit(LB): hit(LB) = hit(M1): hit(M1) = Tmp
Tmp = pos(LB): pos(LB) = pos(M1): pos(M1) = Tmp
Tmp = SLen(LB): SLen(LB) = SLen(M1): SLen(M1) = Tmp
Piv = pos(M1)
pivlen = SLen(M1)
End If
End If
Else
Piv = pos(M1)
pivlen = SLen(M1)
M1 = LB
Do While CompareString(1033, 0, pos(M1), SLen(M1), Piv, pivlen) = 1: M1 = M1 + 1: Loop
End If
End If
M2 = UB
Do
Do While CompareString(1033, 0, pos(M2), SLen(M2), Piv, pivlen) = 3: M2 = M2 - 1: Loop
If M1 <= M2 Then
If M1 <> M2 Then
Tmp = pos(M2): pos(M2) = pos(M1): pos(M1) = Tmp
Tmp = SLen(M2): SLen(M2) = SLen(M1): SLen(M1) = Tmp
Tmp = hit(M2): hit(M2) = hit(M1): hit(M1) = Tmp
End If
M1 = M1 + 1
M2 = M2 - 1
End If
If M1 > M2 Then Exit Do
Do While CompareString(1033, 0, pos(M1), SLen(M1), Piv, pivlen) = 1: M1 = M1 + 1: Loop
Loop
If LB < M2 Then QuickSortExtended LB, M2
If M1 < UB Then QuickSortExtended M1, UB
End Sub
Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
Private Declare Sub GetMem1 Lib "msvbvm60" (ByVal Addr As Long, RetVal As Byte)
Private Declare Sub GetMem2 Lib "msvbvm60" (ByVal Addr As Long, RetVal As Integer)
Private Declare Sub GetMem4 Lib "msvbvm60" (ByVal Addr As Long, RetVal As Long)
Private Declare Sub GetMem8 Lib "msvbvm60" (ByVal Addr As Long, RetVal As Currency)
Private Declare Sub PutMem1 Lib "msvbvm60" (ByVal Addr As Long, ByVal NewVal As Byte)
Private Declare Sub PutMem2 Lib "msvbvm60" (ByVal Addr As Long, ByVal NewVal As Integer)
Private Declare Sub PutMem4 Lib "msvbvm60" (ByVal Addr As Long, ByVal NewVal As Long)
Private Declare Sub PutMem8 Lib "msvbvm60" (ByVal Addr As Long, ByVal NewVal As Currency)
You can use varptr(), strptr() to take addresses from variables and strings.
This is an example of using GlobalAlloc()
Here we don't free the hMem (memory handler) because that is taken from clipboard...
Code:
Private Declare Function GlobalAlloc Lib "kernel32" (ByVal wFlags As Long, ByVal dwBytes As Long) As Long
Private Declare Function GlobalFree Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Function GlobalReAlloc Lib "kernel32" (ByVal hMem As Long, ByVal dwBytes As Long, ByVal wFlags As Long) As Long
Private Declare Function GlobalSize Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) As Long
Private Const GMEM_DDESHARE = &H2000
Private Const GMEM_DISCARDABLE = &H100
Private Const GMEM_DISCARDED = &H4000
Private Const GMEM_FIXED = &H0
Private Const GMEM_INVALID_HANDLE = &H8000
Private Const GMEM_LOCKCOUNT = &HFF
Private Const GMEM_MODIFY = &H80
Private Const GMEM_MOVEABLE = &H2
Private Const GMEM_NOCOMPACT = &H10
Private Const GMEM_NODISCARD = &H20
Private Const GMEM_NOT_BANKED = &H1000
Private Const GMEM_NOTIFY = &H4000
Private Const GMEM_SHARE = &H2000
Private Const GMEM_VALID_FLAGS = &H7F72
Private Const GMEM_ZEROINIT = &H40
Private Const GPTR = (GMEM_FIXED Or GMEM_ZEROINIT)
Private Const GMEM_LOWER = GMEM_NOT_BANKED
Private Declare Function SetClipboardData Lib "user32" _
(ByVal wFormat As Long, ByVal hMem As Long) As Long
Private Declare Function OpenClipboard Lib "user32" _
(ByVal hwnd As Long) As Long
Private Declare Function CloseClipboard Lib "user32" _
() As Long
Private Function SetTextDataLong( _
ByVal lFormatId As Long, _
dLong As Long _
) As Boolean
Dim hMem As Long, lPtr As Long
Dim lSize As Long
lSize = 4
hMem = GlobalAlloc(0, lSize)
If (hMem > 0) Then
lPtr = GlobalLock(hMem)
CopyMemory ByVal lPtr, dLong, lSize
GlobalUnlock hMem
If (OpenClipboard(0) <> 0) Then
SetClipboardData lFormatId, hMem
CloseClipboard
End If
End If
End Function
Having looked at the code you're trying to convert I would create the array, and use a Long variable to index into the array in place of the pointer.
I think that may have been suggested long ago, but now that you're into the code more, you might have a better understanding of what I was saying in the long ago early posts.
For instance in C you had the following
Since all the pointers are used to index through an array, use a Long to hold the index and index through the array with it.
So, instead of pste being a pointer to a STE structure, it is a Long and used to index into an array of those structures contain in the pcon structure.
pcm, instead of being a pointer to a CM structure, it is used to index into the pcon.argcm array of those structures.
The pcmFirst is also changed to a Long and holds the first index into the pcon.argcm array for a given STE structure.
So, part of the access to those array using indexes instead of pointers could be coded like below.
Code:
Private Sub VGenMoves(pcon As tagCon, pste As Long, fCapsOnly As Boolean)
Dim pcm As Long
'... isqTo and isqFrom are set in code not shown
'pcm is set to "point" into the first available slot of pcon.argcm array
pcm = pcon.argste(pste).pcmFirst
'...
If pcon.argste(pste).isqEnP = isqTo Then
With pcon.argcm(pcm)
.isqFrom = isqFrom
.isqTo = isqTo
.cmk = cmkCAPTURE Or (valPAWN - pcPAWN)
.cmf = cmfMAKE_ENP Or cmfCAPTURE
End With
pcm = pcm + 1
End If
'....
End Sub
Lavolpe,
pointers are used for indirect addressing, mostly. You can see offsets that used as indexes, although indexes in addressing modes are values that can be increments or decrements by a value. Offsets are used as constant values. So pointers can be used as is, like a base to some offsets, or as a base for indexing addressing, like in your example.
You can find the background of pointers in addressing modes for a CPU. There are some registers that perform as indexes, and we can use Effective Address, as offsets to program counter or directly with some registers, look here
This info probably won't be relevant to the OP anymore, but anyway, for future VBF members/visitors who stumbles upon this thread, there are APIs which can retrieve or set the data pointed to by a pointer. See this thread for more details.
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
Having looked at the code you're trying to convert I would create the array, and use a Long variable to index into the array in place of the pointer.
I think that may have been suggested long ago, but now that you're into the code more, you might have a better understanding of what I was saying in the long ago early posts.
For instance in C you had the following
Since all the pointers are used to index through an array, use a Long to hold the index and index through the array with it.
So, instead of pste being a pointer to a STE structure, it is a Long and used to index into an array of those structures contain in the pcon structure.
pcm, instead of being a pointer to a CM structure, it is used to index into the pcon.argcm array of those structures.
The pcmFirst is also changed to a Long and holds the first index into the pcon.argcm array for a given STE structure.
So, part of the access to those array using indexes instead of pointers could be coded like below.
Code:
Private Sub VGenMoves(pcon As tagCon, pste As Long, fCapsOnly As Boolean)
Dim pcm As Long
'... isqTo and isqFrom are set in code not shown
'pcm is set to "point" into the first available slot of pcon.argcm array
pcm = pcon.argste(pste).pcmFirst
'...
If pcon.argste(pste).isqEnP = isqTo Then
With pcon.argcm(pcm)
.isqFrom = isqFrom
.isqTo = isqTo
.cmk = cmkCAPTURE Or (valPAWN - pcPAWN)
.cmf = cmfMAKE_ENP Or cmfCAPTURE
End With
pcm = pcm + 1
End If
'....
End Sub
I like this but I am having a little problem with ppi which points to argpi a 2d array so whenever I see ppi I don't know what to put in it like with the other index variables; pste, pcm, psq, I know to put in the index into the array.
Anything I post is an example only and is not intended to be the only solution, the total solution nor the final solution to your request nor do I claim that it is. If you find it useful then it is entirely up to you to make whatever changes necessary you feel are adequate for your purposes.
In VB, an object variable can be treated as a pointer, so I would simply create a Class to replace that Struct.
Is not the same. There is a counter for references, so if you forget to break the reference then your object stays alive...
What is like the pointer..is that you can use the object as data holder and pass the reference like passing a group of data.
Pointers are places that hold addresses. In C we declare what type of variable that pointer show. So a variable can act as a pointer if we can place an address of a specific variable. This is exactly the same as the reference or the passing of a variable in a subroutine by reference. References and pointers are different only in one aspect...pointers can throw the address where points, and became pointers to other points. Reference can't change that address. A reference stay a reference to specific variable.
So if you have an object variable then you can change the actual object, so this is like a pointer. But unlike pointer..if you set object to null may or may not loose your object, because of the use of internal counter. Pointers have no counters. You can do anything with pointers...but in C a pointer for a double must be a pointer for a double...With your object variable you can put anything, if it is a class. So the only reason that you want to use "pointer" is to use a structure placed in another structure, using a variable inside the big structure to hold address of the small structure. This scenario can be done with objects. But definitely, that is no a work with pointers, but more like working with references. Pointers uses offsets and indexes for the calculation of a specific address where we have data to load or store.
Last edited by georgekar; Dec 28th, 2014 at 10:41 PM.
Because the pointer reference type PPI, is used in a number of structures to hold references to the pieces and because of the two dimensions of the argpi array (by color and piece), I would essentially change the two dimensional array to be a 2d array of "pointers" to an array of pieces.
This new array of pieces can be added to the tagCON structure, but since you are unlikely to try parallel processing of move generation, having these arrays inside the tagCON structure and passing that structure to all the routines is really not necessary.
The only reason for gathering those structures into tagCON and passing it everywhere is in case parallel move generation might be desired, but there are complications with that and the code you're porting didn't try to implement any, so you could move those various arrays out of pcon if you wanted.
At this point you probably don't want to move them, but since we're adding a new array, albeit not a large array since it is only holding 32 pieces and the information associated with the piece is not large, you can choose whether you want the new array in tagCON or not.
For the test code I used to show porting and setting up of the arrays, I did add the array to tagCON but it isn't really necessary, I believe.
OK, so the 2d array, argpi now becomes a 2d array of Long (or Integer if you prefer since the largest number used will be 32).
A new 1d array of 32 elements of type tagPI will be the piece array.
You would preset the 2d array with "pointers" into the 1d array.
Code:
Private Type tagCon
sargpi() As tagPI 'New array to hold the pieces info
argpi() As Long 'Existing array to hold "pointers" into sargpi
argsq() As tagSQ
argste() As tagSTE
argcm() As tagCM
argcpi(1) As Integer
'...etc
End Type
Private Sub Form_Load()
'...
ReDim pcon.sargpi((coMAX * cpiMAX) - 1) 'The 1d array of pieces (32 elements)
ReDim pcon.argpi(coMAX - 1, cpiMAX - 1) 'The 2d array of "pointers" into sargpi
'...
'Initial the 2d array (argpi) with indexes into the sargpi array
Dim co As Integer, cpi As Integer
For co = 0 To coMAX - 1
For cpi = 0 To cpiMAX - 1
pcon.argpi(co, cpi) = (co * cpiMAX) + cpi 'turn 2d index into 1d index
Next
Next
End Sub
An example of using the arrays, a portion of porting the lblSet: C code of the FInitCon function
Code:
'...
If pcon.argcpi(co) >= cpiMAX Then
failed = True
Else
Dim ipi As Integer
ipi = pcon.argcpi(co) 'Second part of 2d index
ppi = pcon.argpi(co, ipi) 'The index where to store the next piece info (1d index)
pcon.argcpi(co) = ipi + 1 'ppi = &pcon->argpi[co][pcon->argcpi[co]++];
If (pc = pcKING) And (pcon.argcpi(co) > 1) Then 'if we have a king and it is not the first slot
pcon.argpi(co, ipi) = pcon.argpi(co, ipiKING) ' store the first slot index into this slot
pcon.argpi(co, ipiKING) = ppi 'store this index (ppi) in the first slot
End If
With pcon.sargpi(ppi)
.pc = pc
.co = co
.fDead = False
.isq = rnk * filIBD + fil 'isqFromRnkFil(rnk, fil)
.val = s_argvalPc(pc)
End With
fil = fil + 1
End If
You should notices I broke the C line;
ppi = &pcon->argpi[co][pcon->argcpi[co]++];
into three lines in VB
ipi = pcon.argcpi(co) 'Save the second index (the current piece count) before incrementing the piece count (in case we need to swap with king slot)
ppi = pcon.argpi(co, ipi) 'Get the 1d index (into sargpi) of where the piece information will be stored
pcon.argcpi(co) = ipi + 1 'increment the piece count for this color
Because the code wants the King piece information in the first slot for a color, when we get to where the King position is processed, the code
will swap those indexes in the argpi array, before filling in the King pieces information.
I'll attach the test code so you can see the full test, not just the short snippets above.
A large portion of the FinitCon function was not done, just the initial portion where it loops and processes the piece positions, which is the portion that messes around with the argpi array.
In other code where ppi is used, you can just set ppi to the value from the argpi array.
When you need to dereference ppi to access the fields, then use it to index into sargpi.
An example, I would port the following C code
like this (used nested Ifs to short circuit the NULL condition so don't get an invalid index when testing ppi content)
Code:
With pcon.argsq(isqA1)
If .ppi > -1 Then 'ppi field is set to -1 to indicate unitialized since 0 is a valid "pointer" into an array
If pcon.sargpi(.ppi).pc <> pcROOK Or _
pcon.sargpi(.ppi).co <> coWHITE Then
pcon.argste(pste).cf = pcon.argste(pste).cf And (Not cfE1C1)
End If
Else
pcon.argste(pste).cf = pcon.argste(pste).cf And (Not cfE1C1)
End If
End With
The test code prints out the values of the pcon.argpi array, and the corresponding sargpi values in the debug window once the loop processes the pieces part of the initialization string, so you can see what was done.
Code:
'Show some information from the arrays in the debug window to varify piece settings
Debug.Print
Dim idx As Long
For co = 0 To 1
For fil = 0 To 15
idx = pcon.argpi(co, fil)
Debug.Print Tab(1); co; ","; Tab(5); fil; Tab(9); ":"; idx;
Debug.Print Tab(15); "co="; pcon.sargpi(idx).co;
Debug.Print Tab(21); ",fDead= "; pcon.sargpi(idx).fDead;
Debug.Print Tab(36); ",isq="; pcon.sargpi(idx).isq;
Debug.Print Tab(46); ",pc="; pcon.sargpi(idx).pc;
Debug.Print Tab(53); ",val="; pcon.sargpi(idx).val
Next
Next