WinAPI函数的模板

时间:2017-12-28 20:33:33

标签: c++ templates winapi

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

3 个答案:

答案 0 :(得分:0)

你可能想要这样的东西:

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

答案 1 :(得分:0)

像这样的东西。主要思想是按功能分离代码,避免重复。

#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'\0' != 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'\0' != 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);
}

答案 2 :(得分: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;

当然,这是一个肮脏的伎俩,但它确实有效。