3
\$\begingroup\$

I have not completed this but want to make my own template library for wrapping the Win32 API to make it compatible with std::string/std::wstring... Here's a sample of what I've worked with so far.

My questions are:

  1. Is this a good idea?
  2. Is it acceptable to undefine Windows API macros (e.g. #undef GetWindowText)?
  3. Is there perhaps a better way to do this besides changing the name scheme (e.g. getWindowText or GetWindowString as opposded to GetWindowText)? I prefer not to change the names.

Note: Please don't provide answers like "why don't you just use WTL?" or "just use MFC". I prefer to deal directly with the Windows API; I just want to make it easier to work with std::basic_string.

Implementation

#ifdef _WINUSER_
#undef GetWindowTextLength
template<typename _T> int GetWindowTextLength(HWND hWnd);
template<> int GetWindowTextLength<wchar_t>(HWND hWnd) { return ::GetWindowTextLengthW(hWnd); }
template<> int GetWindowTextLength<char>(HWND hWnd) { return ::GetWindowTextLengthA(hWnd); }

#undef GetWindowText
template<typename _T> std::basic_string<_T> GetWindowText(HWND hWnd);
template<> std::basic_string<wchar_t> GetWindowText(HWND hWnd)
{
    std::size_t len = GetWindowTextLength<wchar_t>(hWnd)+1;
    std::vector<wchar_t> buffer(len);
    ::GetWindowTextW(hWnd, buffer.data(), len);
    return std::basic_string<wchar_t>(buffer.begin(), buffer.end());
}
template<> std::basic_string<char> GetWindowText(HWND hWnd)
{
    std::size_t len = GetWindowTextLength<char>(hWnd)+1;
    std::vector<char> buffer(len);
    ::GetWindowTextA(hWnd, buffer.data(), len);
    return std::basic_string<char>(buffer.begin(), buffer.end());
}
#endif//_WINUSER_

Example Usage

std::basic_string<TCHAR> text = GetWindowText(hWnd);
\$\endgroup\$
4
\$\begingroup\$

I have not completed this but want to make my own template library for wrapping the Win32 API to make it compatible with std::string/std::wstring...

Is this a good idea?

If you have the time to do that as an exercise, probably (there should be a lot of effort involved).

If you want to create a library for future use with an intentional name clash, probably no.

Is it acceptable to undefine Windows API macros (e.g. #undef GetWindowText)?

Not really. If you are careful about it, you can make it work, but these macros can change, their implementation can change depending on where MS wants to take their API in the future and what is behind them may change. You are better off writing your library so that there are no name clashes with MS's macro names.

Is there perhaps a better way to do this besides changing the name scheme (e.g. getWindowText or GetWindowString as opposded to GetWindowText)? I prefer not to change the names.

No. You are better off using new names. Seeing the old names in code would make me (as a client of your lib) assume they have the same semantics, parameters and behavior as the WinAPI defines (macros and all). I would assume the names belong to WinAPI and look automatically to MSDN documentation if I had questions (as in, not in your library's documentation).

Using the same name would create confusion for other people using your code, for you as a developer (consider what happens when you have an error due to a macro name accidentally included where you define your API: you'd have errors caused by name clash in macro expansion, when you don't want the macro defined. For you it would be (almost) easy to fix, as you know the problem. Consider what happens though, when a client of your code writes:

#include <yourcode.h> // undefines macros and defines your interface
#include <windows.h>  // redefines macros and causes errors

This is an error that is easy to make for client code (especially for someone not familiar with the implementation details/constraints of your library) and it is something that you cannot enforce in your library code (you actually could, if you issue #error directives in your includes but that is as brittle as the whole concept - MS changes some implementation details and you have to update your code).

Also consider that your library would have to be complete from the start - if you only implement wrappers for what you need and discover you need a new API, you'd have to define a wrapper to use it - you will be unable to simply include the WinAPI headers and using it from there (as doing so would cause macro expansion clashes).

I prefer to deal directly with the Windows API; I just want to make it easier to work with std::basic_string.

Nothing is stopping you from wrapping the calls. Just don't undefine WinAPI function access macros and replace them with functions (using undefined macro names). You'd introduce a naming/include limitation in client code that would be hard to get around to in specific cases, and would only work with ugly workarounds in client code or by requiring modifications to your library).

\$\endgroup\$
  • \$\begingroup\$ +1 Including the Windows.h header after my library was definitely something I hadn't thought about. \$\endgroup\$ – Drew Chapin May 1 '13 at 22:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.