2

I tried to get string for Windows GUID, but failed by using boost::uuid. The result is exact as this post Boost uuid + boost endian said, byte order wrong.

void foo(GUID& g)
{
  boost::uuids::uuid * u = reinterpret_cast<boost::uuids::uuid*>(&g);
  std::string ustr = boost::lexical_cast<std::string>(*u);
}

Finally, I used this post Convert GUID structure to LPCSTR to complete my convert.

But I am still curious,

  1. Is there some elegant methods to convert any types to boost's ?
  2. If there is, is there out-of-shelf libs for Windows' ?
Raymond
  • 885
  • 10
  • 28

2 Answers2

3
u = reinterpret_cast<boost::uuids::uuid*>(g);

I believe you should take the address of g in the reinterpret_cast:

u = reinterpret_cast<boost::uuids::uuid*>(&g);

Even if you do take the address, I think you have other troubles. Microsoft uses double words and words in their GUID structure, while Boost uses bytes.

Microsoft:

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

Boost:

struct uuid
{
    ...
public:
    // or should it be array<uint8_t, 16>
    uint8_t data[16];
};

I believe you need to perform an explicit conversion with something like:

void MsToBoostUuid(const GUID& ms, boost::uuids::uuid& bst)
{
    bst.data[0] = static_cast<uint8_t>(ms.Data1 >> 24);
    bst.data[1] = static_cast<uint8_t>(ms.Data1 >> 16);
    bst.data[2] = static_cast<uint8_t>(ms.Data1 >>  8);
    bst.data[3] = static_cast<uint8_t>(ms.Data1 >>  0);

    bst.data[4] = static_cast<uint8_t>(ms.Data2 >> 8);
    bst.data[5] = static_cast<uint8_t>(ms.Data2 >> 0);

    bst.data[6] = static_cast<uint8_t>(ms.Data3 >> 8);
    bst.data[7] = static_cast<uint8_t>(ms.Data3 >> 0);

    bst.data[8] = ms.Data4[0];
    bst.data[9] = ms.Data4[1];
    ...
    bst.data[14] = ms.Data4[6];
    bst.data[15] = ms.Data4[7];
}

void foo(const GUID& g)
{
  boost::uuids::uuid u;
  MsToBoostUuid(g, u);

  std::string ustr = boost::lexical_cast<std::string>(*u);
}

You can also add operators, like:

inline bool operator==(const& uuid lhs, const GUID& rhs)
{
    boost::uuids::uuid t;
    MsToBoostUuid(rhs, t);
    return std::equal(lhs.begin(), lhs.end(), t.begin());
}

inline bool operator==(const GUID& lhs, const& uuid rhs)
{
    boost::uuids::uuid t;
    MsToBoostUuid(lhs, t);
    return std::equal(t.begin(), t.end(), rhs.begin());
}

... the result is exact as this post Boost uuid + boost endian said, byte order wrong.

I believe the currently accepted answer is incorrect. I believe Dutton's answer is correct, but it does not show you a typical conversion between UUID types.

jww
  • 97,681
  • 90
  • 411
  • 885
  • Thanks @jww for this question. My curiosity is `MsToBoost` looks ugly. Is there some elegant methods to convert? **AND** Is there an out-of-shelf libs for Windows-to-boost type covert? – Raymond Aug 26 '19 at 15:04
  • 1
    @Raymond - None that I can find: [convert microsoft GUID to "boost::uuids::uuid" github](https://www.google.com/search?q=convert+microsoft+GUID+to+"boost%3A%3Auuids%3A%3Auuid"+github). Any cross-platform conversion code you find is going to be similar to the code above. See, for example, Crypto++'s [`misc.h`](https://github.com/weidai11/cryptopp/blob/master/misc.h) and Botan's [`loadstor.h`](https://github.com/randombit/botan/blob/master/src/lib/utils/loadstor.h). Everyone has to play the endian games. – jww Aug 26 '19 at 15:31
  • Doesn't such a reinterpret_cast violate the current aliasing rules of the language? – VoidStar Jun 10 '22 at 21:04
1

I've used this code with success:

boost::uuids::uuid MakeUUID(const GUID& guid)
{
    boost::uuids::uuid result;
    std::memcpy(&result, reinterpret_cast<const void*>(&guid), result.size());
    std::uint8_t* ch = reinterpret_cast<std::uint8_t*>(&result);
    std::swap(ch[0], ch[3]);
    std::swap(ch[1], ch[2]);
    std::swap(ch[4], ch[5]);
    std::swap(ch[6], ch[7]);
    return result;
}

It's the same thing as copying byte by byte, but using swap you get away with little less lines of code.

olazabal
  • 11
  • 1