![]() |
![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() |
| 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. |
| |||||||
![]() |
| |
| | #1 (permalink) |
| | 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 Specs![]() |
| | #2 (permalink) |
| | 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 Quote: > on the end...that appear to be null or Asc(mid(StrLongString,39,1) returns 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 Specs![]() |
| | #3 (permalink) |
| | 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. character. M$ would probably call this a feature, since null-terminated strings are common in the programming world. -Paul Randall |
My System Specs![]() |
| | #4 (permalink) |
| | 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. 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 Specs![]() |
| | #5 (permalink) |
| | Re: Guid and Cstr Robert wrote: Quote: > interesting issue.. I create a guid with the following function; > 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 Specs![]() |
![]() |
| 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 | |||