Simon
Simon

Reputation: 25983

What's the C++ version of Guid.NewGuid()?

I need to create a GUID in an unmanaged windows C++ project. I'm used to C#, where I'd use Guid.NewGuid(). What's the (unmanaged windows) C++ version?

Upvotes: 66

Views: 93267

Answers (8)

Igor Levicki
Igor Levicki

Reputation: 1596

All that current implementation of CoCreateGUID in combase.dll does is it calls UuidCreate, and if the result is RPC_S_UUID_LOCAL_ONLY it is replaced with S_OK:

#include <rpc.h>
#pragma comment(lib, "rpcrt4.lib")

static const int uuid_string_length = 36;

HRESULT CreateGUID(std::string& GUID)
{
    UUID        uuid = { 0 };
    RPC_CSTR    uuid_string = nullptr;

    HRESULT hr = UuidCreate(&uuid);

    hr = (hr == RPC_S_UUID_LOCAL_ONLY) ? S_OK : hr;

    if (SUCCEEDED(hr)) {
        hr = UuidToStringA(&uuid, &uuid_string);
    }

    if (SUCCEEDED(hr)) {
        GUID.resize(uuid_string_length);
        memcpy(&GUID[0], uuid_string, uuid_string_length);
    }

    if (uuid_string != nullptr) {
        RpcStringFreeA(&uuid_string);
    }

    return hr;
}

And that's a correct thing to do, since GUID is less unique than UUID.

Upvotes: 0

IInspectable
IInspectable

Reputation: 51385

The documentation for Guid.NewGuid points out, how it is implemented:

This is a convenient static method that you can call to get a new Guid. The method wraps a call to the Windows CoCreateGuid function.

So the native equivalent to Guid.NewGuid() is CoCreateGuid().


CoCreateGuid calls UuidCreate, to generate a GUID. Both API calls are slightly different, though: While UuidCreate returns a UUID, that is guaranteed to be unique to the computer that created it, CoCreateGuid produces a GUID that is absolutely unique.

If you need to decide, which API to use, here are the relevant sections from the documentation.

UuidCreate:

For security reasons, it is often desirable to keep ethernet addresses on networks from becoming available outside a company or organization. The UuidCreate function generates a UUID that cannot be traced to the ethernet address of the computer on which it was generated. It also cannot be associated with other UUIDs created on the same computer.

CoCreateGuid:

The CoCreateGuid function calls the RPC function UuidCreate, which creates a GUID, a globally unique 128-bit integer. Use CoCreateGuid when you need an absolutely unique number that you will use as a persistent identifier in a distributed environment.

Upvotes: 12

Tarun Kumar
Tarun Kumar

Reputation: 875

To get in guid in std::string on Windows

#include <Windows.h>
#include <array>

std::string getGUID()
{
    std::string result{};
    GUID guid;

    if (S_OK == CoCreateGuid(&guid))
    {
        std::array<char, 36> buffer{};   //32 characters of guid + 4 '-' in-between

        snprintf(buffer.data(), buffer.size(), "{%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]);
        result = std::string(buffer.data());
    }

    return result;
} 

Upvotes: 2

Soumya Mahunt
Soumya Mahunt

Reputation: 2762

In the new WinRT api you can use winrt::Windows::Foundation::GuidHelper::CreateNewGuid() which returns a struct of winrt::guid type. You can later pass it to winrt::to_hstring to get struct of winrt::hstring type, then pass it to winrt::to_string to get std::string type.

Upvotes: 1

Wyatt O&#39;Day
Wyatt O&#39;Day

Reputation: 1933

Here's a snippet of code to get the resulting string value of the generated GUID:

// For UUID
#include <Rpc.h>
#pragma comment(lib, "Rpcrt4.lib")

int _tmain(int argc, _TCHAR* argv[])
{
    // Create a new uuid
    UUID uuid;
    RPC_STATUS ret_val = ::UuidCreate(&uuid);

    if (ret_val == RPC_S_OK)
    {
        // convert UUID to LPWSTR
        WCHAR* wszUuid = NULL;
        ::UuidToStringW(&uuid, (RPC_WSTR*)&wszUuid);
        if (wszUuid != NULL)
        {
            //TODO: do something with wszUuid

            // free up the allocated string
            ::RpcStringFreeW((RPC_WSTR*)&wszUuid);
            wszUuid = NULL;
        }
        else
        {
            //TODO: uh oh, couldn't convert the GUID to string (a result of not enough free memory)
        }
    }
    else
    {
        //TODO: uh oh, couldn't create the GUID, handle this however you need to
    }

    return 0;
}

API reference:

Upvotes: 18

tcb
tcb

Reputation: 4604

To generate a new guid in windows and get the resulting value as a string.

#include <string>
#include <sstream>
#include <iostream>
#include <windows.h>
#include <iomanip>

int main()
{
    GUID guid;
    CoCreateGuid(&guid);

    std::ostringstream os;
    os << std::hex << std::setw(8) << std::setfill('0') << guid.Data1;
    os << '-';
    os << std::hex << std::setw(4) << std::setfill('0') << guid.Data2;
    os << '-';
    os << std::hex << std::setw(4) << std::setfill('0') << guid.Data3;
    os << '-';
    os << std::hex << std::setw(2) << std::setfill('0') << static_cast<short>(guid.Data4[0]);
    os << std::hex << std::setw(2) << std::setfill('0') << static_cast<short>(guid.Data4[1]);
    os << '-';
    os << std::hex << std::setw(2) << std::setfill('0') << static_cast<short>(guid.Data4[2]);
    os << std::hex << std::setw(2) << std::setfill('0') << static_cast<short>(guid.Data4[3]);
    os << std::hex << std::setw(2) << std::setfill('0') << static_cast<short>(guid.Data4[4]);
    os << std::hex << std::setw(2) << std::setfill('0') << static_cast<short>(guid.Data4[5]);
    os << std::hex << std::setw(2) << std::setfill('0') << static_cast<short>(guid.Data4[6]);
    os << std::hex << std::setw(2) << std::setfill('0') << static_cast<short>(guid.Data4[7]);

    std::string s(os.str());
    std::cout << s << std::endl;
}

Alternatively, you could use sprintf_s for the string conversion

GUID guid;
CoCreateGuid(&guid);
char guidStr[37];
sprintf_s(
    guidStr,
    "%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]);
std::string s(guidStr);

Upvotes: 8

Alan
Alan

Reputation: 13721

I think CoCreateGuid is what you're after. Example:

GUID gidReference;
HRESULT hCreateGuid = CoCreateGuid( &gidReference );

Upvotes: 55

sharptooth
sharptooth

Reputation: 170499

UuidCreate() in Win32 API has exactly the same effect. However you need to pass an address of the variable that will receive the generated value:

UUID newId;
UuidCreate( &newId );

I believe Guid.NewGuid() simply maps onto it inside the .NET runtime.

Upvotes: 46

Related Questions