Windows Vista Forums
Vista Forums Home Join Vista Forums Windows 7 Forum Vista Tutorials Tags
Welcome to Windows Vista Forums. Our forum is dedicated to helping you find solutions with any problems, errors or issues you are experiencing with Windows Vista. The Vista forum also covers news and updates and has an extensive Windows Vista tutorial section that covers a wide range of tips and tricks.

Go Back   Vista Forums > Misc Newsgroups > VB Script

Vista - Guid and Cstr

Reply
 
Old 08-05-2008   #1 (permalink)
Robert


 
 

Guid and Cstr

Hi

interesting issue.. I create a guid with the following function;

Function GUID ()
Dim TypeLib
Set TypeLib = CreateObject("Scriptlet.TypeLib")
GUID = TypeLib.Guid
End Function

Dim strLongString
StrLongString = cstr(Guid())

Even though I have explicitly converted this to a string, two characters are
on the end...that appear to be null or Asc(mid(StrLongString,39,1) returns 0,
and the same for character 40.

You dont seem to be able to append to this null terminated string either?

msgbox "~" & StrLongString & "Hello World"

gives you...

~{AC3E4A61-1CF5-42C5-B6FA-23939E574390}

Without Hello world.

It seems Cstr does not convert it to a vb string but leaves it as a null
terminated string? Is this the case?

Robert



My System SpecsSystem Spec
Old 08-05-2008   #2 (permalink)
mayayana


 
 

Re: Guid and Cstr

I just came across this. It looks like what you
found is a bug:

Function createGuid()
Set TypeLib = Server.CreateObject("Scriptlet.TypeLib")
tg = TypeLib.Guid
createGuid = left(tg, len(tg)-2)
Set TypeLib = Nothing
End Function

I don't know whether the problem always happens.
If it's not a "dependable" bug then the method of
snipping two characters could introduce a second bug.
I just tried this safer variation and it seems to work fine:

---------------------
s = CreateGUID

'-- if 2 dashes show in this msgbox then there are no nulls
'-- in the string s:

MsgBox "-" & s & "-"

Function CreateGUID()
Set TypeLib = CreateObject("Scriptlet.TypeLib")
CreateGUID = Replace(TypeLib.Guid, Chr(0), "")
Set TypeLib = Nothing
End Function

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

There's also the method used in API calls. In the
Win API a lot of functions return a string value put
into a buffer string of 0's sent by the caller. When
it comes back you get:
someresult00000000000000000000000000... etc.

The standard method to handle that is to snip the zeros
from the returned string:

Pt = Instr(1, returnstring, Chr(0))
If Pt > 0 then returnstring = left(returnstring, (Pt - 1))

'-- ( if Pt IS 0 the function didn't work.

CStr just converts a numeric or ambiguous value
to a string (or variant with subtype string). A GUID
is already a string. So you don't need CStr either way.



Quote:

>
> interesting issue.. I create a guid with the following function;
>
> Function GUID ()
> Dim TypeLib
> Set TypeLib = CreateObject("Scriptlet.TypeLib")
> GUID = TypeLib.Guid
> End Function
>
> Dim strLongString
> StrLongString = cstr(Guid())
>
> Even though I have explicitly converted this to a string, two characters
are
Quote:

> on the end...that appear to be null or Asc(mid(StrLongString,39,1) returns
0,
Quote:

> and the same for character 40.
>
> You dont seem to be able to append to this null terminated string either?
>
> msgbox "~" & StrLongString & "Hello World"
>
> gives you...
>
> ~{AC3E4A61-1CF5-42C5-B6FA-23939E574390}
>
> Without Hello world.
>
> It seems Cstr does not convert it to a vb string but leaves it as a null
> terminated string? Is this the case?
>
> Robert
>
>

My System SpecsSystem Spec
Old 08-05-2008   #3 (permalink)
Paul Randall


 
 

Re: Guid and Cstr


"Robert" <Robert@xxxxxx> wrote in message
news:A9A15594-B948-427C-9EC5-5586E44B5BE1@xxxxxx
Quote:

> Hi
>
> interesting issue.. I create a guid with the following function;
>
> Function GUID ()
> Dim TypeLib
> Set TypeLib = CreateObject("Scriptlet.TypeLib")
> GUID = TypeLib.Guid
> End Function
>
> Dim strLongString
> StrLongString = cstr(Guid())
>
> Even though I have explicitly converted this to a string, two characters
> are
> on the end...that appear to be null or Asc(mid(StrLongString,39,1) returns
> 0,
> and the same for character 40.
>
> You dont seem to be able to append to this null terminated string either?
>
> msgbox "~" & StrLongString & "Hello World"
>
> gives you...
>
> ~{AC3E4A61-1CF5-42C5-B6FA-23939E574390}
>
> Without Hello world.
MsgBox does not display any characters in a string beyond a Chr(0)
character. M$ would probably call this a feature, since null-terminated
strings are common in the programming world.

-Paul Randall


My System SpecsSystem Spec
Old 08-05-2008   #4 (permalink)
Old Pedant


 
 

RE: Guid and Cstr

"Robert" wrote:
Quote:

> Even though I have explicitly converted this to a string, two characters are
> on the end...that appear to be null or Asc(mid(StrLongString,39,1) returns 0,
> and the same for character 40.
Yes, this is documented in an MS knowledge base article. The
bug/flaw/feature (remember, "a feature is a bug that has been documented")
has been around since at least 2002 or so.

As suggested, do the Left(CStr(GUID()),38) and you'll be fine.

If you care, the problem does *not* lie in VBScript but in the
Scriptlet.TypeLib code. When you call CSTR( GUID( ) ) you are invoking the
COM function VariantChageTypeEx, passing in a variant that is essentially a
pointer to the COM object created by TypeLib and asking to have that
converted to a string. Since VariantChangeTypeEx can't possibly know the
internal structure of every arbitrary object in the world, it invokes the
equivalent of a ToString( ) method on the object (if such exists...if not, it
creates a useless dummy descriptor string). So the TypeLib's ToString( ) is
correctly converting the guid to a string, but then it doesn't correctly set
the length field for the BSTR that all Variant strings need. No idea why it
is off by 2 instead of by 1.


My System SpecsSystem Spec
Old 08-05-2008   #5 (permalink)
mr_unreliable


 
 

Re: Guid and Cstr



Robert wrote:
Quote:

> interesting issue.. I create a guid with the following function;
>
Robert, if you are having trouble creating guid's using
the usual scriptlet trickery, then you could also use
microsoft's old uuidgen.exe utility, which can be found
by searching the usual programming sites.

I am running uuidgen.exe as a console app, and retrieving
the output as stdout...

--- <code> ---
Dim wshShell : Set wshShell = CreateObject("WScript.Shell")
Dim oExec : Set oExec = wshShell.Exec("uuidgen.exe")
Const wshRunning = 0 ' status: the job is still running.
Const wshFinished = 1
Dim sInput(3)
Dim nrLine : nrLine = 0

Do
WScript.Sleep 100
' when you run uuidgen, the FIRST line of output should be the guid.
sInput(nrLine) = oExec.StdOut.ReadLine
dbPrint sMe & "sInput(" & CStr(nrLine) & "): " & sInput(nrLine)
dbPrint sMe & "Len(sInput): " & CStr(Len(sInput(nrLine)))
BugAssert(Len(sInput(nrLine)) = 36), sMe & "uh-oh. supposed guid is
the wrong length.. "
dbPrint sMe & "isGuid: " & CStr(isGUID(sInput(nrLine)))
if (oExec.Status = wshFinished) then
dbPrint sMe & "oExec.Status = wshFinished"
Exit Do
End If
nrLine = nrLine + 1
BugAssert(nrLine >= 3), sMe & "uh-oh, uuidgen produced unexpected
results.. "
Loop Until oExec.StdOut.AtEndOfStream

dbPrint "" ' space
dbPrint sMe & "GUID result: " & sInput(0)
oForm.TextBox(1).Text = sInput(0)
--- </code> ---

And, if you can't find microsoft's uuidgen, then there are
other utilities out there. For example, vbAccelerator has one:

http://www.vbaccelerator.com/home/Vb...Ds/article.asp

And finally, if you absolutely _MUST_ call api's, then there
is an example attached of how to do it, as vbScript class code,
using wshATO (wsh Api Toolkit - a proprietary control). But then,
you DynaWrap fans could use that too.

cheers, jw
____________________________________________________________

You got questions? WE GOT ANSWERS!!! ..(but, no guarantee
the answers will be applicable to the questions)



' ================================================
' === CLASS CREATE GUID ==========================
' ================================================

Class clsCreateGUID

Private CoCreateGuid ' as object (api call)
Private StringFromGUID2 ' as object (api call)
Private CopyMemory
Private typGUID ' as string (key) = 'tGUID'

Private c_sMe
' --- end of declarations and constants ----------

' the (one-and-only) GUID class property...
Public Default Property Get GUID() ' as string?

Dim uuid ' as GUID
Dim sGUID ' as String
Dim cChar ' as Long (character count)
Const MAX_PATH = 256
Dim adrBSTR ' as lp

GUID = ""

Set uuid = New clsGUID ' create the typedef, and clear it out...
dbPrint "[], adrSTRUCT: " & CStr(uuid.adrSTRUCT)
dbPrint "[Data1], " & Hex(uuid.Data1)

dbPrint "call cocreateguid"
Call CoCreateGuid(uuid) ' and place results in guid typedef...
dbPrint "cocreateguid exit"

' let's see what we got...
' dbPrint "[Data1], " & Hex(uuid.Data2)

' debugging code: allocate a long buffer (for character count)...
' Dim rtnValue : rtnValue = CLng(0) ' alloc long buf
' Dim lpRtnVal : lpRtnVal = oATO.LongPtr(rtnValue)
' CopyMemory CLng(lpRtnVal), CLng(uuid.adrSTRUCT), 4
' dbPrint "[uuid], .Data1?: " & Hex(rtnValue)
' CopyMemory CLng(lpRtnVal), CLng(uuid.adrSTRUCT + 4), 2
' dbPrint "[uuid], .Data2?: " & Hex(rtnValue)
' CopyMemory CLng(lpRtnVal), CLng(uuid.adrSTRUCT + 6), 2
' dbPrint "[uuid], .Data3?: " & Hex(rtnValue)

dbPrint " --- get uuid values --- "
dbPrint "Data1: " & Hex(uuid.Data1)
dbPrint "Data2: " & Hex(uuid.Data2)
dbPrint "Data3: " & Hex(uuid.Data3)
dbPrint "Data4: " & HexChar(uuid.Data4(0)) & HexChar(uuid.Data4(1)) & HexChar(uuid.Data4(2)) & HexChar(uuid.Data4(3)) _
& HexChar(uuid.Data4(4)) & HexChar(uuid.Data4(5)) & HexChar(uuid.Data4(6)) & HexChar(uuid.Data4(7))

' Step 1: set up a (unicode) string buffer, to receive the guid...
sGUID = String(MAX_PATH, Chr(0))
' Step 2: get the address of the vbScript string, i.e., the BSTR!!!
adrBSTR = oATO.vbStrPtr(sGUID)
dbPrint "[adrBSTR], " & CStr(adrBSTR)
' note: the guid provided will be unicode, and so you DON'T want
' wshATO converting ansi-to-unicode for you. Therefore, you
' have to declare the api parameter as lp, rather than as string...
dbPrint "call StringFromGUID2"
cChar = StringFromGUID2(uuid, adrBSTR, MAX_PATH)

' trim trailing NULLs and convert from Unicode
' If (cChar > 0) Then _
' GUID = Left(StrConv(sGUID, vbFromUnicode), cChar - 1)
If (cChar > 0) Then GUID = Left(sGUID, cChar - 1)


End Property

Private Function HexChar(vBYTE) ' parameter as byte
Dim sResult

sResult = Right("0" & Hex(vByte), 2) & "/"
HexChar = sResult

End Function


Sub Class_Initialize()
c_sMe = "[clsCreateGUID], "
dbPrint c_sMe & "Initializing"

' instantiate api (class code) used here...
Set CoCreateGuid = oATO.DeclareAPI("OLE32.DLL", "CoCreateGuid", "ByVal lpGUID As Typedef")
Set StringFromGUID2 = oATO.DeclareAPI("OLE32.DLL", "StringFromGUID2", "ByVal lpGUID As Typedef", "ByVal lpszBuff As Long", "ByVal intcb As Integer")
Set CopyMemory = oATO.DeclareAPI("KERNEL32.DLL", "RtlMoveMemory", _
"ByVal lpDest As Long", "ByVal lpSrc As Long", "ByVal cBytes As Long")

End Sub


Sub Class_Terminate()
dbPrint c_sMe & "Terminating"

End Sub

End Class ' clsCreateGUID



' ================================================
' === GUID TYPEDEF CLASS WRAPPER =================
' ================================================

Class clsGUID

' These definitions of the typedef fields OUGHT to be Const declarations.
' However, private const definitions apparently DON'T WORK in a class code.
' (Shame on you Microsoft). So, we are declaring them here,
' and assigning values in the init code.

' Type GUID ' field name (byte offset)
Private m_Data1 ' Data1 As Long (byte 0)
Private m_Data2 ' Data2 As Integer (byte 4)
Private m_Data3 ' Data3 As Integer (byte 6)
Private m_Data4 ' Data4(0 To 7) As Byte (byte 8)
' END TYPE

Private cbGUID ' as long (byte count of this typedef)
Private adrGUID ' as long
Private tGUID ' as string (key) = 'tGUID'

Private c_sMe
' --- end of declarations and constants ----------

' --- Discussion about storing values in the typedef ---
' Sorry, but you can't use the normal vbScript replace statements.
' You have to use oTD.PutLong (or putWhatever), as it behaves
' something like a 'CopyMemory', and gets a long (or whatever)
' into the typedef, instead of a variant...
' --- end of discussion --------------------------


Public Property Get Data1()
Data1 = oTD.GetLong(tGUID, m_Data1)
End Property

Public Property Let Data1(vRHS)
oTD.PutLong(tGUID, m_Data1) = vRHS
End Property

Public Property Get Data2()
Data2 = oTD.GetInteger(tGUID, m_Data2)
End Property

Public Property Let Data2(vRHS)
oTD.PutInteger(tGUID, m_Data2) = vRHS
End Property

Public Property Get Data3()
Data3 = oTD.GetInteger(tGUID, m_Data3)
End Property

Public Property Let Data3(vRHS)
oTD.PutInteger(tGUID, m_Data3) = vRHS
End Property

Public Property Get Data4(vIndex)
Data4 = oTD.GetByte(tGUID, m_Data4 + CLng(vIndex))
End Property

Public Property Let Data4(vIndex, vRHS)
oTD.PutByte(tGUID, m_Data4 + CLng(vIndex)) = vRHS
End Property


' provides memory address (i.e., a long pointer)...
Public Default Property Get adrSTRUCT()
adrSTRUCT = adrGUID
End Property



Sub Class_Initialize()
c_sMe = "[clsGUID], "
dbPrint c_sMe & "Initializing"

' fill in the typdef field constants,
' (maybe SOMEDAY we can just use: Private Const dwLength = 0)...
m_Data1 = 0 ' Data1 As Long (byte 0)
m_Data2 = 4 ' Data2 As Integer (byte 4)
m_Data3 = 6 ' Data3 As Integer (byte 6)
m_Data4 = 8 ' Data4(0 To 7) As Byte (byte 8)

cbGUID = 16 ' (byte count)
tGUID = "tGUID" ' (key)


On Error Resume Next ' turn on error checking
' create the typedef itself...
' (note: CreateTypeDef allocates memory and clears to zeros)
adrGUID = oTD.CreateTypDef(tGUID, cbGUID)
dbPrint c_sMe & "adrGUID: " & CStr(adrGUID)
' no need to set bytecount for THIS typedef/structure...

' check to make sure that the typedef creation succeeded...
BugAssert (err.number = 0), c_sME & "Unable to create typedef, " & vbCrlf _
& " most likely because oATO is not instantiated properly... "
On Error goto 0 ' turn off error checking...

End Sub


Sub Class_Terminate()
dbPrint c_sMe & "Terminating"
oTD.DestroyTypDef(tGUID) ' return typedef memory block(s)...
End Sub

End Class ' clsGUID



My System SpecsSystem Spec
Reply

Thread Tools


Similar Threads
Thread Forum
MBR vs GUID - Can I Have Both? Vista hardware & devices
Known bug in CStr (Date ()) in WSH 5.7? VB Script
RE: CLID, SID, GUID or UUID? Vista account administration
Nic-GUID with Powershell PowerShell
How to Determine Adapter GUID Vista General


Vista Forums is an independent web site and has not been authorized,
sponsored, or otherwise approved by Microsoft Corporation.
"Windows Vista", the Start Orb, and related materials are trademarks of Microsoft Corp.
© Designer Media Ltd

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46