Winapi功能的模板

Template for WinAPI functions

本文关键字:功能 Winapi      更新时间:2023-10-16

是否有可能以某种方式为Winapi函数创建模板?例如,有两个相似的功能(LookUpprivileGename和LookUpprivilegedIsplayName),但具有不同的参数集。我将两个函数称为:第一个调用检索所需的缓冲区大小,第二个调用返回所需的值。如果不可能,是否有其他方法可以使代码更紧凑?

您可能想要类似的东西:

template<typename CharT>
bool LookupPriviledgeDisplayName(CharT const *, CharT const *, DWORD *, std::basic_string<CharT> & strDisplayName);
template<>
bool LookupPriviledgeDisplayName<char>(char const * pszSystem, char const * pszName, DWORD * pdwLangID, std::basic_string <char> & strDisplayName)
{
    DWORD dwLength = 0;
    if(!LookupPrivilegeDisplayNameA(pszSystem, pszName, nullptr, &dwLength, pdwLangID))
        return false;
    std::vector<char> buffer(dwLength + 1);
    if(!LookupPrivilegeDisplayNameA(pszSystem, pszName, &buffer[0], &dwLength, pdwLangID))
        return false;
    strDisplayName.assign(&buffer[0], &buffer[0] + dwLength);
    return true;
}
template<>
bool LookupPriviledgeDisplayName<wchar_t>(wchar_t const * pszSystem, wchar_t const * pszName, DWORD * pdwLangID, std::basic_string <wchar_t> & strDisplayName)
{
    DWORD dwLength = 0;
    if(!LookupPrivilegeDisplayNameW(pszSystem, pszName, nullptr, &dwLength, pdwLangID))
        return false;
    std::vector<wchar_t> buffer(dwLength + 1);
    if(!LookupPrivilegeDisplayNameW(pszSystem, pszName, &buffer[0], &dwLength, pdwLangID))
        return false;
    strDisplayName.assign(&buffer[0], &buffer[0] + dwLength);
    return true;
}

类似的东西。主要想法是通过避免重复的功能分开代码。

#include <memory>
#include <string>
#include <iostream>
#include <system_error>
#include <cassert>
//  Error handler.
void
On_Error(const ::DWORD error_code)
{
    throw ::std::system_error{static_cast<int>(error_code), ::std::system_category()};
}
//  Error check.
void
Validate_LookupPrivilegeNameSuccess(const ::BOOL result, const bool expect_insufficient_buffer)
{
    if(FALSE == result)
    {
        auto const error_code{::GetLastError()};
        if((ERROR_INSUFFICIENT_BUFFER == error_code) && (!expect_insufficient_buffer))
        {
            On_Error(error_code);
        }
    }
}
enum class
t_PrivilegeNameCategoryId
{
    name
,   display_name
};
//  Helper class calling WinAPI methods, checking input and output.
template<t_PrivilegeNameCategoryId> class
t_LookupPrivilegeNameImpl;
template<> class
t_LookupPrivilegeNameImpl<t_PrivilegeNameCategoryId::name> final
{
    public: static ::std::size_t
    Lookup(const ::LPCWSTR psz_system_name, ::LUID & luid, const ::LPWSTR p_buffer, ::DWORD buffer_capacity_items_count)
    {
        assert((0 == buffer_capacity_items_count) || (nullptr != p_buffer));
        Validate_LookupPrivilegeNameSuccess
        (
            ::LookupPrivilegeNameW
            (
                psz_system_name
            ,   ::std::addressof(luid)
            ,   p_buffer
            ,   ::std::addressof(buffer_capacity_items_count)
            )
        ,   nullptr == p_buffer
        );
        return(buffer_capacity_items_count);
    }
};
template<> class
t_LookupPrivilegeNameImpl<t_PrivilegeNameCategoryId::display_name> final
{
    public: static ::std::size_t
    Lookup(const ::LPCWSTR psz_system_name, const ::LPCWSTR psz_display_name, const ::LPWSTR p_buffer, ::DWORD buffer_capacity_items_count)
    {
        assert(psz_display_name);
        assert(L'' != psz_display_name[0]);
        assert((0 == buffer_capacity_items_count) || (nullptr != p_buffer));
        ::DWORD language_id{};
        Validate_LookupPrivilegeNameSuccess
        (
            ::LookupPrivilegeDisplayNameW
            (
                psz_system_name
            ,   psz_display_name
            ,   p_buffer
            ,   ::std::addressof(buffer_capacity_items_count)
            ,   ::std::addressof(language_id)
            )
        ,   nullptr == p_buffer
        );
        return(buffer_capacity_items_count);
    }
};
//  Lookup function implementing get size -> resize buffer -> get data algorithm.
template<t_PrivilegeNameCategoryId name_category_id, typename... TArgs> void
Lookup_PrivilegeName(::std::wstring & name, TArgs &&... args)
{
    try
    {
        name.resize(t_LookupPrivilegeNameImpl<name_category_id>::Lookup(::std::forward<TArgs>(args)..., ::LPWSTR{}, ::DWORD{}));
        t_LookupPrivilegeNameImpl<name_category_id>::Lookup(::std::forward<TArgs>(args)..., name.data(), static_cast<::DWORD>(name.size()));
        if(name.empty() || (L'' != name.back()))
        {
            On_Error(ERROR_UNIDENTIFIED_ERROR);
        }
        name.pop_back();
    }
    catch(...)
    {
        name.clear();
        throw;
    }
}
int main()
{
    ::LPCWSTR psz_system_name{};
    ::LUID privilege_luid{5}; // a wild guess
    ::std::wstring privilege_name{};
    Lookup_PrivilegeName<t_PrivilegeNameCategoryId::name>(privilege_name, psz_system_name, privilege_luid);
    ::std::wstring privilege_display_name{};
    Lookup_PrivilegeName<t_PrivilegeNameCategoryId::display_name>(privilege_display_name, psz_system_name, privilege_name.c_str());
    ::std::wcout << privilege_name << L"n" << privilege_display_name << ::std::endl;
    return(0);
}

我的俄罗斯朋友向我解释了模板的局限性。他建议将功能与上下文切换使用。在我的情况下,这将是这样的:

BOOL LookupData(DWORD context, PLUID luid, wstring input, wstring & output) {
  BOOL status = TRUE;
  DWORD buflen = 0, lang = 0;
  switch (context) {
     case 0: status = LookupPrivilegeName(NULL, luid, NULL, &buflen); break;
     case 1: status = LookupPrivilegeDisplayName(NULL, input.c_str(), NULL, &buflen, &lang); break;
     default: return FALSE;
  }
  if (!status && ERROR_INSUFFICIENT_BUFFER != GetLastError())  return status;
  auto buffer = make_unique<wchar_t[]>(buflen);
  switch (context) {
     case 0: status = LookupPrivilegeName(NULL, luid, buffer.get(), &buflen); break;
     case 1: status = LookupPrivilegeDispayName(NULL, input.c_str(), buffer.get(), &buflen, &lang); break;
  }
  if (!status) {
      buf.release();
      return status;
  }
  output = buf.get();
  buf.release();
  return status;
}

现在我可以在获得Token_privileges结构后的周期写入:

std::wstring name, desription;
if (!LookupData(0, tp->Privipeges[i].Luid,  L"", name)) break;
if (!LookupData(1, NULL, name, description)) break;
std::wcout << name << L" - " << std::endl;

当然,这是肮脏的技巧。