C++版本的Guid.NewGuid()是什么?

65

我需要在一个非托管的Windows C++项目中创建一个GUID。在C#中,我习惯使用Guid.NewGuid()。那么(非托管Windows)C++版是什么?


C++并没有定义一个。你必须依赖第三方库或特定于平台的操作系统提供的API。 - jalf
你可能想查看Boost UUID https://www.boost.org/doc/libs/1_62_0/libs/uuid/uuid.html。 - Mital Vora
7个回答

54

我认为CoCreateGuid是你需要的。例如:

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

12
无论如何,它都会在内部调用UuidCreate()函数。 - sharptooth
5
@sharptooth说的只是一半的真相。虽然 CoCreateGuid 确实调用了 UuidCreate,但它提供了关于唯一性的更强保证。CoCreateGuid:当你需要一个在分布式环境中作为持久标识符使用的绝对唯一号码时,请使用 CoCreateGuid - IInspectable
8
需要先调用CoInitialize()吗? - Serge Rogatch
@sharptooth 从文档的角度来看是有道理的。这个句子需要一个主语,而编辑器提供了当前页面上函数的名称。这并不一定意味着CoCreateGuidUuidCreate做得更多。 - zahir

45

Win32 API中的UuidCreate()具有完全相同的效果。但是您需要传递一个变量地址以接收生成的值:

UUID newId;
UuidCreate( &newId );

我认为Guid.NewGuid()只是在.NET运行时内部映射到它。


这将创建一个UUID结构,而不是GUID结构。 - Simon
5
它们是一样的,只是不同的typedef名称! - Konrad Rudolph
37
是的,但 GUID 仅声称是全局唯一的;UUID 则契约保证具有普遍唯一性!因此,如果您希望您的代码在不止一个星球上运行,那么显然应该使用后者!(不幸的是,即使是后者在量子计算和多宇宙解释被证明为真时也可能无法满足需求...) - BrendanMcK
7
并非如此。Guid.NewGuid 调用 CoCreateGuid(而 CoCreateGuid 又可能多次调用 UuidCreate)。区别在于,CoCreateGuid 提供了更强的唯一性保证,因此这种区别很重要。 - IInspectable
1
@IInspectable 听起来不错。为什么不添加另一个答案来解释所有的细节呢? - sharptooth
显示剩余3条评论

18
以下是一个代码片段,用于获取生成的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 参考:


11

Guid.NewGuid 的文档指出了其实现方式:

这是一个方便的 静态 方法,您可以调用它来获取一个新的GUID。该方法将调用 Windows CoCreateGuid 函数进行封装。

因此,与 Guid.NewGuid() 等价的本地方法是 CoCreateGuid()


CoCreateGuid 调用 UuidCreate 生成一个GUID。虽然这两个API调用略有不同: UuidCreate 返回一个UUID,并保证该值在创建它的计算机上是唯一的,而 CoCreateGuid 产生的GUID则绝对是独一无二的。

如果您需要决定使用哪个API,请参阅文档中的相关部分。

UuidCreate:

出于安全考虑,通常希望将网络上的以太网地址保持在公司或组织内部不可用。 UuidCreate 函数生成一个UUID,该 UUID 无法被追溯到生成它的计算机的以太网地址。 它也不能与在同一台计算机上创建的其他 UUID 相关联。

CoCreateGuid:

CoCreateGuid函数产生一个新的GUID。

CoCreateGuid函数调用RPC函数UuidCreate来创建GUID,即全局唯一的128位整数。在分布式环境中需要使用绝对唯一的数字作为持久标识符时,请使用CoCreateGuid


8
在Windows中生成一个新的GUID,并将结果作为字符串返回。
#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;
}

或者,您可以使用 sprintf_s 进行字符串转换。

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);

2
在Windows上获取std::string中的GUID
#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;
} 

为什么不使用string_view呢?或者更好的是,为什么不返回std::array呢?我不明白为什么需要分配std::string。这只是我的个人意见。 - Mecanik
1
另外,还有StringFromGUID2。 - Mecanik

1
在新的WinRT api中,您可以使用winrt::Windows::Foundation::GuidHelper::CreateNewGuid(),它返回一个winrt::guid类型的结构体。您稍后可以将其传递给winrt::to_hstring以获取winrt::hstring类型的结构体,然后将其传递给winrt::to_string以获取std::string类型。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接