-
Sep 28th, 2023, 08:43 AM
#1
Thread Starter
PowerPoster
How do I construct a VARIANT with the API, set the type to string
How do I construct a VARIANT with the API, set the type to string, and specify the character address
SysAllocStringByteLen can make a string ptr,how to make a VARIANT ?
Last edited by xiaoyao; Sep 28th, 2023 at 10:17 AM.
-
Sep 28th, 2023, 09:37 AM
#2
Thread Starter
PowerPoster
Re: How do I construct a VARIANT with the API, set the type to string
Code:
Private Declare Sub VariantInit Lib "oleaut32.dll" (ByRef pvarg As Variant)
Private Declare Function SysAllocString Lib "oleaut32.dll" (ByVal psz As Long) As Long
Private Declare Sub SysFreeString Lib "oleaut32.dll" (ByVal bstrString As Long)
Private Declare Function GetMem2 Lib "msvbvm60" (Src As Any, Dst As Any) As Long
Const vbLongLong As Integer = &H14
Private Const vbTypeMask As Integer = &HFFF
Private Const vbByRef As Integer = &H4000
Public Property Get VarType(VarName) As VbVarType
GetMem2 VarName, VarType
VarType = VarType And vbTypeMask
End Property
Public Property Let VarType(VarName, ByVal Value As VbVarType)
Dim VT As Integer
GetMem2 VarName, VT
VT = (VT And (Not vbTypeMask)) Or (Value And vbTypeMask)
GetMem2 VT, VarName
End Property
Private Sub CreateStringVariant()
Dim myVariant As Variant
Dim strData As String
VariantInit myVariant
strData = "Hello, World!"
VarType(myVariant) = vbString
Dim bstrData As Long
bstrData = SysAllocString(StrPtr(strData))
'how to set bstrData to myVariant ???
myVariant = strData ' bstrData
MsgBox myVariant
SysFreeString bstrData
End Sub
-
Sep 28th, 2023, 09:46 AM
#3
Re: How do I construct a VARIANT with the API, set the type to string
What type of string variant?
Dim v As Variant
v = "text"
Create a Variant of type VT_BSTR, VB's native string format.
There's several other types of strings. If you need a VT_LPWSTR variant, it's more difficult than you'd think. I've adjusted the syntax for VB6; the original is in tbShellLib for twinBASIC. Left the LongPtrs; you can add an enum for it if you aren't using oleexp, which defines it as an alias.
Code:
Public Declare Function CoTaskMemAlloc Lib "ole32" (ByVal cb As LongPtr) As LongPtr
Public Declare Function lstrlenW Lib "kernel32" (lpString As Any) As Long
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
Public Declare Sub ZeroMemory Lib "kernel32" Alias "RtlZeroMemory" (Destination As Any, ByVal Length As LongPtr)
'[Description ("Creates a PROPVARIANT of type VT_LPWSTR from a tB String") ]
Public Function InitPropVariantFromString(psz As String, ppropvar As Variant) As Long
'This unfortunately isn't as easy as making a VT_BSTR Variant then calling VariantChangeType; that fails.
If VarPtr(ppropvar) = 0 Then InitPropVariantFromString = E_POINTER: Exit Function
Dim lpAlloc As LongPtr: lpAlloc = CoTaskMemAlloc((lstrlenW(ByVal StrPtr(psz)) + 1) * 2)
ZeroMemory ByVal lpAlloc, (lstrlenW(ByVal StrPtr(psz)) + 1) * 2
CopyMemory ByVal lpAlloc, ByVal StrPtr(psz), lstrlenW(ByVal StrPtr(psz)) * 2
VariantSetType ppropvar, VT_LPWSTR
CopyMemory ByVal PointerAdd(VarPtr(ppropvar), 8), lpAlloc, LenB(lpAlloc)
InitPropVariantFromString = S_OK
End Function
'[ Description ("Sets a Variant to the specified type without any alteration to the data. vtOnlyIf raises an error if the original type is other than specified. WARNING: Many data formats are incompatible, use VariantChangeType absent specific need....") ]
Public Function VariantSetType(pvar As Variant, ByVal vt As Integer, Optional ByVal vtOnlyIf As Integer = -1) As Boolean
If VarPtr(pvar) = 0 Then Exit Function
If vtOnlyIf <> -1 Then
If VarType(pvar) <> vtOnlyIf Then
Exit Function
End If
End If
CopyMemory pvar, vt, 2
VariantSetType = True
End Function
'[ Description ("Performs an unsigned add on a LongPtr (Long or LongLong)") ]
Public Function PointerAdd(ByVal Start As LongPtr, ByVal Incr As LongPtr) As LongPtr
#If Win64 Then
PointerAdd = ((Start Xor &H8000000000000000) + Incr) Xor &H8000000000000000
#Else
PointerAdd = ((Start Xor &H80000000) + Incr) Xor &H80000000
#End If
End Function
Variant vt values:
Code:
Public Enum VARENUM
VT_EMPTY = 0
VT_NULL = 1
VT_I2 = 2
VT_I4 = 3
VT_R4 = 4
VT_R8 = 5
VT_CY = 6
VT_DATE = 7
VT_BSTR = 8
VT_DISPATCH = 9
VT_ERROR = 10
VT_BOOL = 11
VT_VARIANT = 12
VT_UNKNOWN = 13
VT_DECIMAL = 14
VT_I1 = 16
VT_UI1 = 17
VT_UI2 = 18
VT_UI4 = 19
VT_I8 = 20
VT_UI8 = 21
VT_INT = 22
VT_UINT = 23
VT_VOID = 24
VT_HRESULT = 25
VT_PTR = 26
VT_SAFEARRAY = 27
VT_CARRAY = 28
VT_USERDEFINED = 29
VT_LPSTR = 30
VT_LPWSTR = 31
VT_RECORD = 36
VT_INT_PTR = 37
VT_UINT_PTR = 38
VT_FILETIME = 64
VT_BLOB = 65
VT_STREAM = 66
VT_STORAGE = 67
VT_STREAMED_OBJECT = 68
VT_STORED_OBJECT = 69
VT_BLOB_OBJECT = 70
VT_CF = 71
VT_CLSID = 72
VT_STREAMED_PROPSET = 73
VT_STORED_PROPSET = 74
VT_BLOB_PROPSET = 75
VT_VERBOSE_ENUM = 76
VT_BSTR_BLOB = &HFFF
VT_VECTOR = &H1000
VT_ARRAY = &H2000
VT_BYREF = &H4000
VT_RESERVED = &H8000&
VT_ILLEGAL = &Hffff&
VT_ILLEGALMASKED = &H0fff
VT_TYPEMASK = &H0fff
End Enum
-
Sep 28th, 2023, 09:49 AM
#4
Thread Starter
PowerPoster
Re: How do I construct a VARIANT with the API, set the type to string
DOSE VB6 HAVE VARIANT TLB LIKE THIS?
Code:
VARIANT x1,x2,x3,x4;
x1.vt = VT_BSTR;
x1.bstrVal = SysAllocString(L"Hello world1");
-
Sep 28th, 2023, 09:54 AM
#5
Thread Starter
PowerPoster
Re: How do I construct a VARIANT with the API, set the type to string
Dim vv As Variant
Dim s As String
s = "abc中"
InitPropVariantFromString s, vv
MsgBox vv
err:
458, the variable uses an automation type that Visual Basic does not support
now its'ok
change this:
Code:
Const E_POINTER As Long = &H80004003
Const S_OK As Long = 0
VariantSetType ppropvar, VT_BSTR
Last edited by xiaoyao; Sep 28th, 2023 at 09:58 AM.
-
Sep 28th, 2023, 10:07 AM
#6
Thread Starter
PowerPoster
Re: How do I construct a VARIANT with the API, set the type to string
how to copy?
copymemoryLng VarPtr(vv2), VarPtr(vv), 16
length=16,now it's ok
Code:
Declare Sub copymemoryLng Lib "kernel32" Alias "RtlMoveMemory" (ByVal Dest As Long, ByVal Source As Long, ByVal Length As Long)
Dim vv2 As Variant
vv2 = "a"
MsgBox Len(vv)
copymemoryLng VarPtr(vv2), VarPtr(vv), Len(vv)
MsgBox vv2
With CoTaskMemAlloc, which requires more code, I generate DLL apis in another programming language
Using SysAllocStringByteLen to return the pointer, VB6 call API can directly get the string data.
I define a variant, initialize some character data, and give the variant's address pointer to a DLL created by another program
'In DLL: First empty the data of the original variant address, then modify the string address in the variant?
Last edited by xiaoyao; Sep 28th, 2023 at 10:21 AM.
-
Sep 28th, 2023, 10:32 AM
#7
Thread Starter
PowerPoster
Re: How do I construct a VARIANT with the API, set the type to string
clear old string ptr:
SysFreeString StrPtr(s2)
MsgBox "s2=" & s2
why not clear?
Dim VariantStrPtr As Long
CopyMemory VariantStrPtr, ByVal VarPtr(vv) + 8, 4
SysFreeString VarPtr(VariantStrPtr)
SysFreeString VariantStrPtr
it's free ok !need add byval
SysFreeString ByVal VariantStrPtr
-
Sep 28th, 2023, 01:22 PM
#8
Re: How do I construct a VARIANT with the API, set the type to string
Like I said there's different types of strings. VB6 does not support LPWSTR except that in some cases a BSTR can be substituted, so the only thing you do with a VT_LPWSTR string variant is pass it off to APIs requiring or understanding that format.
If you're using only in VB6 why are you doing any of this? For VT_BSTR all you need:
Dim v As Variant
v = "string"
VB will free it automatically. Do not use my longer code unless you need VT_LPWSTR.
Don't copy it with CopyMemory,
Dim v2 As Variant
v2 = v1
VB will copy it automatically.
It calls those SysAlloc and SysFree APIs under the hood for you.
-
Sep 28th, 2023, 06:35 PM
#9
Thread Starter
PowerPoster
Re: How do I construct a VARIANT with the API, set the type to string
how to make a Variant with ref?
here bptr only put long,can't put real varptr(b),how to do?
vbs code:
Code:
Dim a, b, c, bptr
bptr=0
a = 11
b = 22
bptr=http1.getvarptr(b)
c=0
c = http1.sum2(a, bptr)
vb6 com dll:
Private Const vbByRef As Integer = &H4000
Code:
Public Function Sum2(ByVal a As Variant, b As Variant) As Variant
Sum2 = a + b
b = b * 2
End Function
Public Function GetVarptr(String1 As Variant) As Variant
GetVarptr = VarPtr(String1)
End Function
https://www.vbforums.com/showthread.php?807655-RESOLVED-Is-VarPtrStrArray-actually-needed&p=4954415&viewfull=1#post4954415
It is also possible to obtain the VarPtrStrArray using VarPtr together with ParamArray. This saves using the typedef, although requires a few lines of code to create a function VarPtrStrArray() to return the pointer
Code:
Private Declare Sub GetWord Lib "msvbvm60.dll" Alias "GetMem2" _
(ByRef inSrc As Any, ByRef inDst As Integer)
Private Declare Sub GetDWord Lib "msvbvm60.dll" Alias "GetMem4" _
(ByRef inSrc As Any, ByRef inDst As Long)
'Usage Example
' Dim s() As String : ptr As Long
' ptr = VarPtrStrArray(s())
Public Function VarPtrStrArray(ParamArray p()) As Long
Const vbByRef = &H4000&
Const ERROR_TYPE_MISMATCH = 13
Dim ptrPA As Long, PtrArray As Long, PtrSafeArray As Long
Dim vt As Integer, bIsDefined As Boolean
If UBound(p) <> 0 Then Err.Raise ERROR_TYPE_MISMATCH: Exit Function
ptrPA = VarPtr(p(0))
If ptrPA Then GetWord ByVal ptrPA, vt
If (vt And vbArray) = 0 Then Err.Raise ERROR_TYPE_MISMATCH: Exit Function
If (vt And vbByRef) = 0 Then Err.Raise ERROR_TYPE_MISMATCH: Exit Function
If ptrPA <> 0 Then GetDWord ByVal ptrPA + 8, PtrArray Else PtrArray = 0
If PtrArray <> 0 Then GetDWord ByVal PtrArray, PtrSafeArray
bIsDefined = (PtrSafeArray <> 0)
VarPtrStrArray = PtrArray
End Function
Last edited by xiaoyao; Sep 28th, 2023 at 06:47 PM.
-
Sep 28th, 2023, 07:13 PM
#10
Re: How do I construct a VARIANT with the API, set the type to string
Sorry I can't understand what you're asking or trying to do in that post.
-
Sep 28th, 2023, 10:11 PM
#11
Thread Starter
PowerPoster
Re: How do I construct a VARIANT with the API, set the type to string
how to get varptr (vv as variant) in vb6 dll
dim vv as variant
vv="abc"
msgbox varptr(vv)
msgbox getvarptr(vv)
'it's not same like varptr(vv)
Code:
Public Function DllMain( _
ByVal hInstDll As Long, _
ByVal fdwReason As Long, _
ByVal lpvReserved As Long) As Long
Public Function GetVarPtr(ByRef vv As Variant) As Variant 'export api
GetVarPtr = VarPtr(vv)
End Function
-
Sep 28th, 2023, 11:22 PM
#12
Re: How do I construct a VARIANT with the API, set the type to string
Still not following. For me VarPtr(vv) = GetVarPtr(vv)
Code:
Dim vv As Variant
vv = "abc"
Debug.Print VarPtr(vv)
Debug.Print GetVarPtr(vv)
Public Function GetVarPtr(ByRef vv As Variant) As Variant 'export api
Debug.Print VarPtr(vv)
GetVarPtr = VarPtr(vv)
End Function
You're getting different results?
prints
1700172
1700172
1700172
-
Sep 29th, 2023, 12:04 AM
#13
Thread Starter
PowerPoster
Re: How do I construct a VARIANT with the API, set the type to string
 Originally Posted by fafalone
Still not following. For me VarPtr(vv) = GetVarPtr(vv)
Code:
Dim vv As Variant
vv = "abc"
Debug.Print VarPtr(vv)
Debug.Print GetVarPtr(vv)
Public Function GetVarPtr(ByRef vv As Variant) As Variant 'export api
Debug.Print VarPtr(vv)
GetVarPtr = VarPtr(vv)
End Function
You're getting different results?
prints
1700172
1700172
1700172
in dll export, arg only suppory byval v as long
Code:
Public Function GetVarPtr(ByVal V As Long) As Long
' CreateIExprSrvObj 0, 4, 0
' CoInitialize 0
Dim VV As Variant
MessageBox 0, "V=" & V, "TEST", 0
GetVarPtr = VarPtrA(V)
End Function
test dll
Code:
Private Declare Function GetVarPtr2 Lib "AComDll_Thread.dll" Alias "GetVarPtr" (vv As Any) As Variant
Private Sub BTGetVarPtr2_Click()
Dim vv As Variant
vv = "abc"
MsgBox "varpatr(vv)=" & VarPtr(vv)
MsgBox "GetVarPtr2(vv)=" & GetVarPtr2(vv)
End Sub
-
Sep 29th, 2023, 12:17 AM
#14
Thread Starter
PowerPoster
Re: How do I construct a VARIANT with the API, set the type to string
I USE ON A TOOL LIKE AHK.EXE (USE VBS SCRIPT)
IT'S SUPPORT API:
Private Declare Function VarPtrA Lib "msvbvm60" Alias "VarPtr" (var As Any) As Long
BUT IT'S CAN'T SUPPOT ARGS type
maybe it will change all args to long type,
Code:
Private Declare Function VarPtrA Lib "msvbvm60" Alias "VarPtr" (byval var As long) As Long
so not support varptr Parameters of the address。
now i make a com dll for Com_getVartype
call by com object,it will put Parameters use the address。
so i need make to dll:com dll,and standard dll
i also put this code to script tool like ahk.exe
Code:
Private Declare Function VarPtrA Lib "msvbvm60" Alias "VarPtr" (byval var As long) As Long
but VarPtrA results are different about: vb6 varptr(vv as variant)
If you want to make VBS a small IDE, you can dynamically create forms and dynamically add controls. You can also call standard DLL apis, support structures, support controls. There are many difficulties to solve, the transmission of data types, structural simulation, etc. Many technical problems are difficult to solve.
Even in the VB6 environment, it is difficult to get the event name of VB CALSS1.CLS, the type and name of each member parameter.
For example, dynamic indefinite parameters are passed many times, but also keep the variable address reference unchanged (not copy VARIANT values) :
Public Sub suba( ParamArray Items())
call b(items)
end sub
sub b(ParamArray Items())
call c(items)
end sub
sub c(ParamArray Items())
'
end sub
After all, VB6 is 25 years old and has a lot of bugs.
At the same time, 1 billion times of redundant calculation, VB6 compiled EXE only takes 2 seconds,vbs takes 130 seconds, the time difference is 60 times.
The speed is very slow, and there are many bugs and incompatibilities.
The end result is an ahk.exe-like scripting tool in China that takes more than 10,000 seconds to run the same calculation.
For example, SCRIPTCONTROL, executing JS code, obtaining JSON arrays, there are also many incompatibilities.
var a=[1,2,3];
js.eval("a[0]")
js.eval(a)(0) is err,can't use this method
Last edited by xiaoyao; Sep 29th, 2023 at 12:29 AM.
-
Sep 29th, 2023, 01:15 AM
#15
Re: How do I construct a VARIANT with the API, set the type to string
If the VarPtr values are different, somewhere you're making a copy of it rather than passing a reference.
Seems you've drifted off into another topic with paramarrays; those aren't actually true multiple arguments, they're just an array of variants. This thread should shed some light on their internals and how to handle them at a low level: https://www.vbforums.com/showthread....n-C-export-DLL
-
Sep 29th, 2023, 01:48 AM
#16
Thread Starter
PowerPoster
Re: How do I construct a VARIANT with the API, set the type to string
how to free a string ptr,use SysFree?
i put string variant args to dll。
I'm passing a pointer to a variable of a variant type.
Once the variable is allocated, it does not need to be released.
Then you only need to modify the pointer of the address of the string each time.
dll will make a new string address
how to free old string ptr memory data?
How do I get the system to reclaim this area of memory without causing a memory leak?
-
Sep 29th, 2023, 02:38 AM
#17
Re: How do I construct a VARIANT with the API, set the type to string
Is there an objective behind all these non-sensical dumps of gibberish?
Olaf
-
Sep 29th, 2023, 04:27 AM
#18
Thread Starter
PowerPoster
Re: How do I construct a VARIANT with the API, set the type to string
The initial problem was to use VBS to create an object such as XMLHTTP server or winhttprequest to request a web page HTM, and very few computers kept displaying information such as security channel errors. Even with the SERVER xmlhttp object, the error is not displayed, but you still cannot get the actual text of the page (please open the page with a browser to display it).
Other programming languages can be downloaded successfully, so want to use another IDE to create a DLL to VB6 call, but found that passed the data UNICODE is not recognized, and the returned data is not recognized by ANSI format.
So you want to pass the pointer directly, write data directly to the pointer. Or return a new string pointer. If you request a web page multiple times, you need to clear the last string pointer data, otherwise it will cause memory leaks or EXE crashes.
Last edited by xiaoyao; Sep 29th, 2023 at 04:37 AM.
-
Sep 29th, 2023, 04:28 AM
#19
Thread Starter
PowerPoster
Re: How do I construct a VARIANT with the API, set the type to string
It is used for: parameter passing of string, character variant between different programming languages.
For example, PYTHON calls VB6 COM DLL, standard DLL, JS and VB6 object methods call each other and so on.
If, like sendmessage wm_gettext, you first allocate a large-capacity variable, write data to the DLL API and then remove CHR(0) and other data, this method I think is too troublesome.
-
Sep 29th, 2023, 07:18 AM
#20
Re: How do I construct a VARIANT with the API, set the type to string
If you're passing with VT_BYREF like you want to, you shouldn't be using SysFreeString at all, because then VB will crash when your DLL invalidates a pointer out from under it.
Also why would you use variants for this to begin with? Just use regular strings. It's much easier to interop between languages with a simple array of integers.
-
Sep 29th, 2023, 08:23 AM
#21
Thread Starter
PowerPoster
Re: How do I construct a VARIANT with the API, set the type to string
Because I'm calling these standard DLL APIs in VBS. It can pass arguments to variants, but it cannot pass pointers. I need to e the result back directly in the parameter.Because it uses the API to return only integers directly.I just empty the variant of the string type, its original memory address, the payment address.
I just want to modify the string pointer of the variant with the code. Not directly to modify the string variable to clear 。
In theory, it should be feasible to modify the pointer directly, but it is necessary to do a good job of this memory to prevent leaks and crashes.
-
Sep 29th, 2023, 08:34 AM
#22
Thread Starter
PowerPoster
Re: How do I construct a VARIANT with the API, set the type to string
 Originally Posted by fafalone
If you're passing with VT_BYREF like you want to, you shouldn't be using SysFreeString at all, because then VB will crash when your DLL invalidates a pointer out from under it.
Also why would you use variants for this to begin with? Just use regular strings. It's much easier to interop between languages with a simple array of integers.
Why did you contribute so much to VB6? You have developed many excellent open source projects all the time.
I found it difficult to modify the value of the parameter passed in the test process.
I return fixed string data to him, but the data received by the receiving end is only two bytes each time, and it is garbled, and the display is different each time.Maybe this is the wrong pointer.It took me one night, and I was almost there.
When I allocate one KB of space, if I download a web page that reaches 10 KB, I will crash when I write it in.
The string structure of other languages is different from that of BB6, so there is no way to directly pass it to him 1 to 1.
I converted it to a wide Unicode byte first. And then write the address of that string. Modify the length of the first 4 bytes.
Later, I found that if I passed the address of the string variant directly.Modify the 8th byte position. Gets the value of the string pointer to the. (Constructs a new string variable pointer.)The key is the original string address. Is there anyone who can clean up the data? If I call him 1000 times in a loop. Will there be a leak of 1000 memory? Because I created 1000 string pointers back to the variant.If the other way around, it's an array of strings. I'm just forcing it. How many elements does he have? Reset the array every 50 times.
-
Sep 29th, 2023, 11:47 AM
#23
Re: How do I construct a VARIANT with the API, set the type to string
Strings really aren't that different in most languages... but the point I'm making is you're only multiplying the complexity by attempting to wrap it in a Variant to use with a language that doesn't have VB's support for Variants built in.
Now if that's your goal, to understand how to deal with COM VARIANT structs in languages that don't wrap them like VB, ok. But if your goal is to pass strings back and forth, this is not a good method for it.
-
Sep 29th, 2023, 05:54 PM
#24
Thread Starter
PowerPoster
Re: How do I construct a VARIANT with the API, set the type to string
My current second method is. He's actually going to construct a new string variable, and I'm going to change the length by four bytes.And then write that data.
This method eliminates the need to allocate space repeatedly.It's like a buffer zone, and the premise is that it's needed at the beginning. Pre-allocated memory area. Uch as 500 KB.
If the downloaded page is 300KB, I just need to change the length.If I hadn't forcibly reclaimed this space. It is possible to leak a small amount of memory.
So I also need to add a function to restore the memory space of 500kb in DIY.
Because VBS does not have strptr, varptr, nor can it detect whether the string pointer in the variant has changed?So we can only use a lot of black technology. To modify the pointer in the argument, or to read the string pointer of that variant.
vbs getref(),This is also a strange function.
How to make multiple threads call a procedure in scriptcontrol Vbs?
I don't know whether he compiles and runs or purely parses and runs.
-
Sep 29th, 2023, 06:54 PM
#25
Re: How do I construct a VARIANT with the API, set the type to string
If you're just going between VB and VBS you shouldn't be playing with internals at all, because VBS deals with Variants the same way and it's the only type it even supports.
For what you're doing you need to either allocate the empty space to begin with, then you can simply whether it's still null, or use an input and output instead of just trying to modify an input in a weird way.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|