【问题标题】:What's the C++ version of Guid.NewGuid()?Guid.NewGuid() 的 C++ 版本是什么?
【发布时间】:2010-11-22 13:35:09
【问题描述】:

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

【问题讨论】:

标签: c++ windows winapi guid


【解决方案1】:

Guid.NewGuid 的文档指出,它是如何实现的:

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

所以 Guid.NewGuid() 的原生等价物是 CoCreateGuid()


CoCreateGuid 调用 UuidCreate,以生成 GUID。不过,这两个 API 调用略有不同:UuidCreate 返回一个 UUID,保证对创建它的计算机是唯一的,CoCreateGuid 生成一个绝对唯一的 GUID。

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

UuidCreate:

出于安全原因,通常希望防止网络上的以太网地址在公司或组织之外可用。 UuidCreate 函数生成一个UUID,它无法追踪到生成它的计算机的以太网地址。它也不能与在同一台计算机上创建的其他 UUID 关联。

CoCreateGuid:

CoCreateGuid 函数调用 RPC 函数 UuidCreate,它创建一个 GUID,一个全局唯一的 128 位整数。当您需要一个绝对唯一的数字并将其用作分布式环境中的持久标识符时,请使用 CoCreateGuid

【讨论】:

    【解决方案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 的原因。只是我的意见。
    • 另外还有StringFromGUID2。
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

          我认为CoCreateGuid 是您所追求的。示例:

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

          【讨论】:

          • 它无论如何都会在内部调用 UuidCreate()。
          • @sharptooth:这只是事实的一半。虽然CoCreateGuid 确实调用了UuidCreate,但它在唯一性方面提供了更强的保证。 CoCreateGuid“当您需要一个绝对唯一的数字时,请使用 CoCreateGuid,该数字将用作分布式环境中的持久标识符。”
          • 是否需要事先调用 CoInitialize()?
          • @sharptooth 从文档的角度来看是有道理的。该句子需要一个主题,并且编辑器提供了当前页面上的功能名称。这并不一定意味着CoCreateGuid 所做的比UuidCreate 更多。
          【解决方案7】:

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

          UUID newId;
          UuidCreate( &newId );
          

          我相信 Guid.NewGuid() 只是在 .NET 运行时映射到它。

          【讨论】:

          • 这是一个 UUID 结构,而不是 GUID 结构。
          • 它们是一样的,只是typedef名称不同!
          • 是的,但 GUID 只声称是全球唯一的; UUID 通过合约声称具有通用唯一性!因此,如果您希望您的代码在多个星球上运行,那么显然您应该使用后者! (不幸的是,如果/当量子计算流行起来并且多宇宙解释被证明是真的时,即使后者也可能被证明是不够的......)
          • 事实并非如此。 Guid.NewGuid 调用 CoCreateGuid(它又调用 UuidCreate,可能不止一次)。不同之处在于,CoCreateGuid 在唯一性方面提供了更强的保证,因此不同之处很重要。
          • @IInspectable 听起来不错。为什么不添加另一个解释所有细节的答案?
          猜你喜欢
          • 1970-01-01
          • 2011-04-30
          • 1970-01-01
          • 1970-01-01
          • 2015-03-28
          • 2011-04-27
          • 2010-09-19
          • 1970-01-01
          • 2020-07-12
          相关资源
          最近更新 更多