50

I have a GUID variable and I want to write inside a text file its value. GUID definition is:

typedef struct _GUID {          // size is 16
    DWORD Data1;
    WORD   Data2;
    WORD   Data3;
    BYTE  Data4[8];
} GUID;

But I want to write its value like:

CA04046D-0000-0000-0000-504944564944

I observed that:

  • Data1 holds the decimal value for CA04046D
  • Data2 holds the decimal value for 0
  • Data3 holds the decimal value for next 0

But what about the others?

I have to interpret myself this values in order to get that output or is there a more direct method to print such a variable?

unwind
  • 391,730
  • 64
  • 469
  • 606
Jeni
  • 587
  • 1
  • 5
  • 12
  • 1
    Variables hold values, and values do not have a base. It may be displayed as decimal, hexidecimal, binary, or any other base as part of the "printing" function, but the value itself has no base and so is _not_ "decimal". – Mooing Duck Aug 07 '13 at 22:08

11 Answers11

65

Use the StringFromCLSID function to convert it to a string

e.g.:

GUID guid;
CoCreateGuid(&guid);

OLECHAR* guidString;
StringFromCLSID(guid, &guidString);

// use guidString...

// ensure memory is freed
::CoTaskMemFree(guidString);

Also see the MSDN definition of a GUID for a description of data4, which is an array containing the last 8 bytes of the GUID

djvg
  • 11,722
  • 5
  • 72
  • 103
John Sibly
  • 22,782
  • 7
  • 63
  • 80
  • 1
    using bstr as the prefix here is misleading as BSTR is a type and it is freed with SysFreeString(), not CoTaskMemFree(). I'd rename this to guidString, or guidStringCoTaskMemAlloc to be really explicit. OLECHAR is a vestige from 16 bit days, use wchar_t or WCHAR instead, better yet PWSTR as that includes the SAL annotation for "null terminated" – Chris Guzak May 15 '15 at 23:12
  • 6
    StringFromGUID2() can be used to avoid the allocation, it puts its result in a caller specified buffer. this avoids the possibility of failure and the need to free the result. – Chris Guzak May 15 '15 at 23:18
  • The link you gave says that Data4 contains values, not a pointer to an array as you say in the comment. – Serge Rogatch Jun 18 '15 at 15:37
  • @SergeRogatch I think I wrote that because C++ treats array types similar to a pointer to a single element... I'll change the wording to make it less confusing – John Sibly Jun 19 '15 at 09:36
61

Sometimes its useful to roll your own. I liked fdioff's answer but its not quite right. There are 11 elements of different sizes.

printf("Guid = {%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX}", 
  guid.Data1, guid.Data2, guid.Data3, 
  guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
  guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);

Output: "Guid = {44332211-1234-ABCD-EFEF-001122334455}"

Refer to Guiddef.h for the GUID layout.

Same, as a method:

void printf_guid(GUID guid) {
    printf("Guid = {%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX}", 
      guid.Data1, guid.Data2, guid.Data3, 
      guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
      guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
}

you can also pass a CLSID to this method.

rogerdpack
  • 62,887
  • 36
  • 269
  • 388
JustinB
  • 1,532
  • 15
  • 18
  • worked like a champ! I'm messing with some BLE structures that have UUID aka GUID. I set: GUID *guid = &pCharBuffer->CharacteristicUuid.Value.LongUuid; and used the printf above. thanks for sharing! – Gilson Aug 27 '14 at 19:37
  • 1
    I had to change each %02hhX into %02hX for it to work. – Brian THOMAS Feb 24 '17 at 16:06
  • Due to integer promotion, `h` and `hh` modifier can be omitted. – youfu Feb 05 '20 at 02:27
16

You can eliminate the need for special string allocations/deallocations by using StringFromGUID2()

GUID guid = <some-guid>;
// note that OLECHAR is a typedef'd wchar_t
wchar_t szGUID[64] = {0};
StringFromGUID2(&guid, szGUID, 64);
Tim Dowty
  • 1,460
  • 13
  • 9
  • these are not BSTRs, those are freed with SysFreeString(), StringFromCLSID result is freed with CoTaskMemAlloc – Chris Guzak Jul 13 '17 at 18:57
  • 2
    Well, the advantage of using StringFromGUID2() is that you don't have to do any COM or BSTR string deallocations. You pass it plain ol' memory, and it writes characters there. An OLECHAR is just a typedef'd wchar_t. – Tim Dowty Oct 12 '17 at 17:40
14

In case you prefer C++ way

std::ostream& operator<<(std::ostream& os, REFGUID guid){

    os << std::uppercase;
    os.width(8);
    os << std::hex << guid.Data1 << '-';

    os.width(4);
    os << std::hex << guid.Data2 << '-';

    os.width(4);
    os << std::hex << guid.Data3 << '-';

    os.width(2);
    os << std::hex
        << static_cast<short>(guid.Data4[0])
        << static_cast<short>(guid.Data4[1])
        << '-'
        << static_cast<short>(guid.Data4[2])
        << static_cast<short>(guid.Data4[3])
        << static_cast<short>(guid.Data4[4])
        << static_cast<short>(guid.Data4[5])
        << static_cast<short>(guid.Data4[6])
        << static_cast<short>(guid.Data4[7]);
    os << std::nouppercase;
    return os;
}

Usage:

static const GUID guid = 
{ 0xf54f83c5, 0x9724, 0x41ba, { 0xbb, 0xdb, 0x69, 0x26, 0xf7, 0xbd, 0x68, 0x13 } };

std::cout << guid << std::endl;

Output:

F54F83C5-9724-41BA-BBDB-6926F7BD6813

12

In case when your code uses ATL/MFC you also could use CComBSTR::CComBSTR(REFGUID guid) from atlbase.h:

GUID guid = ...;
const CComBSTR guidBstr(guid);  // Converts from binary GUID to BSTR
const CString guidStr(guidBstr); // Converts from BSTR to appropriate string, ANSI or Wide

It will make conversion & memory cleanup automatically.

Quentin
  • 62,093
  • 7
  • 131
  • 191
Rost
  • 8,779
  • 28
  • 50
8

Courtesy of google's breakpad project:

std::string ToString(GUID *guid) {
    char guid_string[37]; // 32 hex chars + 4 hyphens + null terminator
    snprintf(
          guid_string, sizeof(guid_string),
          "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
          guid->Data1, guid->Data2, guid->Data3,
          guid->Data4[0], guid->Data4[1], guid->Data4[2],
          guid->Data4[3], guid->Data4[4], guid->Data4[5],
          guid->Data4[6], guid->Data4[7]);
    return guid_string;
}

UUID guid = {0};
UuidCreate(&guid);
std::cout << ToString(&guid);
Marco M.
  • 2,956
  • 2
  • 29
  • 22
8

Inspired by JustinB's answer

#define GUID_FORMAT "%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX"
#define GUID_ARG(guid) (guid).Data1, (guid).Data2, (guid).Data3, (guid).Data4[0], (guid).Data4[1], (guid).Data4[2], (guid).Data4[3], (guid).Data4[4], (guid).Data4[5], (guid).Data4[6], (guid).Data4[7]

and then

printf("Int = %d, string = %s, GUID = {" GUID_FORMAT "}\n", myInt, myString, GUID_ARG(myGuid));
Benoit
  • 76,634
  • 23
  • 210
  • 236
steve
  • 3,230
  • 1
  • 19
  • 14
2

Use UuidToString function to convert GUID to string. The function accepts UUID type which is typedef of GUID.

2

I know the question is quite old, but would this work maybe?

inline std::ostream& operator <<(std::ostream& ss,GUID const& item) {
  OLECHAR* bstrGuid;
  ::StringFromCLSID(item, &bstrGuid);
  ss << bstrGuid;
  ::CoTaskMemFree(bstrGuid);
  return ss;
}
Cookie
  • 12,004
  • 13
  • 54
  • 83
1
std::string
GuidToString(const GUID& guid, bool lower = false)
{
    const char* hexChars = lower ? "0123456789abcdef" : "0123456789ABCDEF";

    auto f = [hexChars](char* p, unsigned char v)
    {
        p[0] = hexChars[v >> 4];
        p[1] = hexChars[v & 0xf];
    };

    char s[36];
    f(s, static_cast<unsigned char>(guid.Data1 >> 24));
    f(s + 2, static_cast<unsigned char>(guid.Data1 >> 16));
    f(s + 4, static_cast<unsigned char>(guid.Data1 >> 8));
    f(s + 6, static_cast<unsigned char>(guid.Data1));
    s[8] = '-';
    f(s + 9, static_cast<unsigned char>(guid.Data2 >> 8));
    f(s + 11, static_cast<unsigned char>(guid.Data2));
    s[13] = '-';
    f(s + 14, static_cast<unsigned char>(guid.Data3 >> 8));
    f(s + 16, static_cast<unsigned char>(guid.Data3));
    s[18] = '-';
    f(s + 19, guid.Data4[0]);
    f(s + 21, guid.Data4[1]);
    s[23] = '-';
    f(s + 24, guid.Data4[2]);
    f(s + 26, guid.Data4[3]);
    f(s + 28, guid.Data4[4]);
    f(s + 30, guid.Data4[5]);
    f(s + 32, guid.Data4[6]);
    f(s + 34, guid.Data4[7]);

    return std::string(s, 36);
}
tcb
  • 4,408
  • 5
  • 34
  • 51
-2
printf(%X-%X-%X-%X-%X", guid.Data1, guid.Data2, guid.Data3, &guid.Data4);
RAS
  • 8,100
  • 16
  • 64
  • 86
fdioff
  • 7