Function to create a GUID

With Acknowledgements to Randy Rogers and Graham Dawson, here’s how to add a function to create GUIDs to your app.

  1. Use LibMaker to create a .lib file for rpcrt4.lib, which you will find in Windows\SYSWOW64

  2. Add rpcrt4.lib to the libraries in your solution

  3. Add this to Global Embeds After Global Includes

UUIDGT              GROUP,TYPE
Data1                   ULONG 
Data2                   USHORT
Data3                   USHORT
Data4                   BYTE,DIM(8)
  end
  1. Add this to the global embed Inside the Global Map
   module('Rpcrt4.dll')
        UuidCreate(*UUIDGT),ULONG,PASCAL,RAW,NAME('UuidCreate')
        UuidToString(*UUIDGT,*LONG),ULONG,PASCAL,RAW,NAME('UuidToStringA')
        RpcStringFree(*LONG),ULONG,PASCAL,RAW,NAME('RpcStringFreeA')
    end
  1. Create a source procedure called Get_GUID, with prototype (),string (don’t miss the comma!) and parameters ()
Get_GUID PROCEDURE(),STRING

Data section is:

RPC_S_OK            EQUATE(0)
UUID                LIKE(UUIDGT),AUTO
RPC_STATUS          LONG

Code section is:

    clear(UUID,-1)
    RPC_STATUS = UuidCreate(UUID)
    if RPC_STATUS = RPC_S_OK
        return GUIDToString(UUID)
    end
    return ''   !failed
  1. Create a source procedure called GUIDToString with prototype (*UUIDGT pUuid),string, parameters
    (*UUIDGT pUuid)
GUIDToString PROCEDURE(*UUIDGT pUuid)

Data section is:

RPC_S_OK            EQUATE(0)
lResult                 LONG
lpszUuid                LONG
szUuid                  &CSTRING
sUuid                   STRING(36)

Code section is:

    lResult = UuidToString(pUuid,lpszUuid) !address(lpszUuid))
    IF lResult = RPC_S_OK
       szUuid &= (lpszUuid)
       sUuid = szUuid
       lResult = RpcStringFree(lpszUuid)
     END
    RETURN '{' & upper(sUuid) & '}'

Notes: You can combine the two procedures into one if you will always want a string version of the GUID.
I have added braces around my GUID just because that is what I need. You may not, and you may also prefer to get the result in lower rather than upper case.

3 Likes

This is some code that I found I was using. It uses CoCreateGuid() and StringFromGUID2() that are both in the shipping Win32.LIB:

Globally define:

T_GUID  GROUP,TYPE
Data1       ULONG
Data2       ULONG
Data3       USHORT
Data4       STRING(8)
        END  
  MAP
    MakeGUID(<*T_GUID OutGuid16Binary>),STRING
    MODULE('Win32')      
       CoCreateGUID    (*T_Guid Guid),LONG,RAW,PASCAL,DLL(1),NAME('CoCreateGuid') !Returns HRESULT  >=0 S_OK
       StringFromGUID2 (*T_Guid Guid,LONG OutLPZString,LONG SizeOutLPZS),LONG,RAW,PASCAL,DLL(1),NAME('StringFromGUID2') !Out is UNICODE Returns Chars
    END  
  END

Add this Procedure:

MakeGUID PROCEDURE(<*T_GUID OutGuid16Binary>)!,STRING   !MakeGUID e.g. {3963B960-0D8D-4620-A8C8-00C58272ACF3}
CoGUID16   LIKE(T_GUID)         !Ninary 16 bytes Group
BStrGUID   BSTRING              !Clarion's Unicode String type
BStrPtr    LONG,OVER(BStrGuid)  !Pointer to the OleString
CMadeGUID  CSTRING(39)          !Cstring assures no Null <0> in Return
    CODE 
    IF CoCreateGUID(CoGUID16) >=0 THEN    !CoGUID16 will be a Binary 16 Byte UUID
       IF ~OMITTED(OutGuid16Binary) THEN  !Caller passed an OUT to get the Binary 16 Byte GUID?
          OutGuid16Binary = CoGUID16        
       END
       BStrGuid = '?{39}' !MUST allocate BSTR - Formatted String {Guid} is 38 + <0>
       IF StringFromGUID2(CoGUID16,BStrPtr,LEN(BStrGUID)) > 0 THEN  !Take Binary GUID and Format as String GUID into BStrGuid
          CMadeGUID = BStrGUID                                      !Success so set as Return String GUID
       END
    END
    RETURN CMadeGUID

StringFromGUID2()'s 2nd parameter is the GUID String as an OUT . It is a UNICODE String so I use a trick to pass a Pointer to a Clarion BSTRING (Pointer is the LONG OVER(B) ). The BSTRING is Unicode and the RTL handles the conversion to ANSI STRING in the RETURN.

You could prototype as STRING e.g. (*T_Guid Guid,*STRING OutLPZString,LONG SizeOutLPZS)
The output being UNICODE will have a <0> every other character so you have to handle that in a Loop or other ways.

This UNICODE trick works for me setup with the English Char Set, YMMV.

Edit 9/10: Added (<*T_GUID OutGuid16Binary>) to MakeGUID so caller can get the Binary Guid. Added comments. Single Return.

One other GUID tip:
In the Editor on the Edit menu is the item Insert GUID (Ctrl+Shift+G) that will paste a GUID at the Cursor. I use this when I copy a Cwproj file and rename it to change the <ProjectGuid> </ProjectGuid> to be unique.

2 Likes

Cool.

Also, if you have Capesoft’s StringTheory, there is the MakeGuid() function.

ST MakeGuid() returns a 16 byte string of Random letters.

April 2023 version 3.34 added MakeGuid4() that works like the 2 functions above to make a true UUID that contains the Date, Time, Computer MAC Address and more to make it Universally Unique across computers.

1 Like

ST MakeGuid() returns a 16 byte string of Random letters.

uppercase letters and digits (so 36 possible characters). This would give 7.958661109946401e+24 possible combinations (a large number!).

StringTheory doesn’t contain these but conforms to version 4 UUIDs.

https://www.rfc-editor.org/rfc/rfc4122#section-4.1.3

which is “randomly or pseudo-randomly generated version specified in this document.”

because this can contain all the binary characters (rather than just a selection from the 36 letters and digits) there are a couple of formatting options to show in hex (32 chars rather than 16) and optionally add hyphens and brackets.

it uses GuidEncode for the formatting:
https://www.capesoft.com/docs/StringTheory3/StringTheory.htm#stGuidEncode

1 Like

sql{prop:sql} = ‘select newid()’
next(sql)

1 Like

I looked for Clarion version rather than a SQL version because I was using SQLite, and though it is possible to create an insert trigger to create a GUID (using several hex(random_blob…)) statements, SQLite doesn’t support the creation of functions out of the box, so you’d have to duplicate the code in a trigger for each table for which you needed GUIDs.