如果我在源代码中的某处定义了 UUID:
class DECLSPEC_UUID("31A0884B-2B2F-4243-B4A0-2AEFE11FDD68") MyGuidClass;
有没有办法将它用于 static const C 字符串声明? (Microsoft 特定。)
以这种形式:
static LPCWSTR kstrKeys[] =
{
__uuidof(MyGuidClass), //instead of this: L"31A0884B-2B2F-4243-B4A0-2AEFE11FDD68",
};
__uuidof 不返回字符串,而是返回 GUID。但可以在编译时将此 guid 转换为字符串。我使用 std::array 来存储字符串数据,因为这是 constexpr (即使在 C++17 中)
#include <Windows.h>
#include <array>
#include <iostream>
#include <string_view>
// compile time function to convert uuid to an array holding the string data
template<typename char_t, typename coclass_t>
static constexpr auto from_guid()
{
// __uuidof doesn't return a string buit a GUID class
const GUID guid{ __uuidof(coclass_t)};
// conversion table from decimal values to hex characters
std::array<char_t,16> output{'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
std::array<char_t,39> guid_str{};
// unrolled loop, it is not allowed to do type punning in constexpr
// so I cannot have a std::uint8_t* to the start of the memory
// of the guid. Then again it are easy byte mask operations
guid_str[0] = '{';
guid_str[1] = output[(guid.Data1 >> 28) & 0x0f];
guid_str[2] = output[(guid.Data1 >> 24) & 0x0f];
guid_str[3] = output[(guid.Data1 >> 20) & 0x0f];
guid_str[4] = output[(guid.Data1 >> 16) & 0x0f];
guid_str[5] = output[(guid.Data1 >> 12) & 0x0f];
guid_str[6] = output[(guid.Data1 >> 8) & 0x0f];
guid_str[7] = output[(guid.Data1 >> 4) & 0x0f];
guid_str[8] = output[guid.Data1 & 0x0f];
guid_str[9] = '-';
guid_str[10] = output[(guid.Data2 >> 12) & 0x0f];
guid_str[11] = output[(guid.Data2 >> 8) & 0x0f];
guid_str[12] = output[(guid.Data2 >> 4) & 0x0f];
guid_str[13] = output[guid.Data2 & 0x0f];
guid_str[14] = '-';
guid_str[15] = output[(guid.Data3 >> 12) & 0x0f];
guid_str[16] = output[(guid.Data3 >> 8) & 0x0f];
guid_str[17] = output[(guid.Data3 >> 4) & 0x0f];
guid_str[18] = output[guid.Data3 & 0x0f];
guid_str[19] = '-';
std::size_t offset{20ul};
for(std::size_t i=0; i < 8; ++i)
{
auto hi = guid.Data4[i] >> 4;
auto lo = guid.Data4[i] & 0xF;
if ( i==2 )
{
guid_str[offset++] = '-';
}
guid_str[offset++] = output[hi];
guid_str[offset++] = output[lo];
}
guid_str[offset] = '}';
return guid_str;
}
class __declspec(uuid("{6B8FF54A-BE2C-41A3-B9A1-5C443A1E14BB}")) MyGuidClass1 {};
class __declspec(uuid("{EA86CFEF-606C-4F9D-9EBA-9F4B40728153}")) MyGuidClass2 {};
// Let compiler create data in memory to refer to
static constexpr auto guid1_str{ from_guid<WCHAR,MyGuidClass1>() };
static constexpr auto guid2_str{ from_guid<WCHAR,MyGuidClass2>() };
// now you can refer to the compile time string buffers.
static std::array<const WCHAR*,2> kstrKeys
{
guid1_str.data(),
guid2_str.data()
};
// And here is the test output
int main()
{
std::wcout << kstrKeys[0] << L"\n";
std::wcout << kstrKeys[1] << L"\n";
// or just use the compile time constants directly
std::wcout << guid1_str.data() << L"\n";
std::wcout << guid2_str.data() << L"\n";
return 0;
}
can define next macros:
#define CC(m) ((m) < 10 ? '0' + (m) : 'A' + ((m)-10))
#define UV(m) CC(((m) >> 4) & 15), CC((m) & 15)
#define DECLARE_STRING_UUID(MyClass)\
enum { \
e0 = __uuidof(MyClass).Data1 & 0xff,\
e1 = (__uuidof(MyClass).Data1 >> 8 ) & 0xff,\
e2 = (__uuidof(MyClass).Data1 >> 16 ) & 0xff,\
e3 = (__uuidof(MyClass).Data1 >> 24 ) & 0xff,\
e4 = __uuidof(MyClass).Data2 & 0xff,\
e5 = (__uuidof(MyClass).Data2 >> 8 ) & 0xff,\
e6 = __uuidof(MyClass).Data3 & 0xff,\
e7 = (__uuidof(MyClass).Data3 >> 8 ) & 0xff,\
e8 = __uuidof(MyClass).Data4[0],\
e9 = __uuidof(MyClass).Data4[1],\
ea = __uuidof(MyClass).Data4[2],\
eb = __uuidof(MyClass).Data4[3],\
ec = __uuidof(MyClass).Data4[4],\
ed = __uuidof(MyClass).Data4[5],\
ee = __uuidof(MyClass).Data4[6],\
ef = __uuidof(MyClass).Data4[7],\
};\
public:\
inline static wchar_t szUUID[39] = {\
'{',\
UV(e3),\
UV(e2),\
UV(e1),\
UV(e0),\
'-',\
UV(e5),\
UV(e4),\
'-',\
UV(e7),\
UV(e6),\
'-',\
UV(e8),\
UV(e9),\
'-',\
UV(ea),\
UV(eb),\
UV(ec),\
UV(ed),\
UV(ee),\
UV(ef),\
'}',\
0\
};
并将其用于您的课堂:
class DECLSPEC_UUID("31A0884B-2B2F-4243-B4A0-2AEFE11FDD68") MyGuidClass
{
DECLARE_STRING_UUID(MyGuidClass);
};
测试用:
OutputDebugStringW(MyGuidClass::szUUID);