[Style] Import a C function with wrong signature on purpose
Hi, for the boost.process library I need WinAPI functions which take an enumerator. Problem is: the forward-declaration doesn't work here, even with C++11. I.e. this code is still illegal, because X has a non-fixed type: enum X {}; enum X : typename std::underlying_type<X>::type ; I do however know which values the enum has take, thus I can redeclare it and have the reasonable expectation, that it will use the same underlying type. So theoretically, I could import the function into a seperate namespace (using extern "C") and use it, while having it declared with another enum type. I.e. you have in some C code the declaration: enum X { a,b,c}; void f(X); And I'll write in my code without including the other header: namespace import_thingy { extern "C" { enum X { a,b,c}; void f(X); } To be absolutely sure, I'd add an test, which asserts that the underlying types are equal. Now of course, that would never be accepted into the boost/winapi module, but I could just add this in my library. Would this be a dealbreaker for a library attempting to become a boost-library? If so, I'd need to put it into a source file and include windows.h there, but I'd really like the library to be header-only and under no circumstances include windows.h there. Thanks, Klemens
On Monday, 2 May 2016 23:17:37 MSK Klemens Morgenstern wrote:
Now of course, that would never be accepted into the boost/winapi module, but I could just add this in my library. Would this be a dealbreaker for a library attempting to become a boost-library? If so, I'd need to put it into a source file and include windows.h there, but I'd really like the library to be header-only and under no circumstances include windows.h there.
It's not just a question of style. This is likely break with a recent clang. Maybe gcc, too. The compiler has to check that the same named functions with C linkage are equivalent (i.e. receive the same arguments of the same type), and this is not the case with enums. This is one reason why Boost.WinAPI is so complicated. My guess is that unless you are able to avoid enums altogether, you have no choice but to include windows.h. Maybe you could reduce the negative impact of that by providing a way to build that part of your library separately.
It's not just a question of style. This is likely break with a recent clang. Maybe gcc, too. The compiler has to check that the same named functions with C linkage are equivalent (i.e. receive the same arguments of the same type), and this is not the case with enums. This is one reason why Boost.WinAPI is so complicated.
Thanks, I did not realise that. I tested it only with different versions of GCC (as you know, I have a nicer solution for MSVC) and that does work there (though it warns): extern "C" void f(int) {}; namespace x { extern "C" void f(unsigned int) {} } Gcc is quite tolerant here, but you're right, Clang (rightfully) complains. But I guess if I do that void f(unsigned int) __asm__("f"); I'll be tarred and feathered.
My guess is that unless you are able to avoid enums altogether, you have no choice but to include windows.h. Maybe you could reduce the negative impact of that by providing a way to build that part of your library separately.
It looks that way. Well it is not an esssential feature and it would only be necessary on windows. Still, it's really annoying, that you would need to built a binary because the of the bloody winapi. I hate that thing. And btw.: I did realize how much evil details the winapi holds. So good work, it's really helpful.
Am 02.05.2016 um 23:22 schrieb Andrey Semashev:
On Tuesday, 3 May 2016 00:21:38 MSK Klemens Morgenstern wrote:
But I guess if I do that
void f(unsigned int) __asm__("f");
I'll be tarred and feathered.
Does that work with __dllimport functions?
I just tried that with gcc 5.1, that works. Though it of course is an
utterly simple function.
#include
It's not just a question of style. This is likely break with a recent clang. Maybe gcc, too. The compiler has to check that the same named functions with C linkage are equivalent (i.e. receive the same arguments of the same type), and this is not the case with enums. This is one reason why Boost.WinAPI is so complicated.
My guess is that unless you are able to avoid enums altogether, you have no choice but to include windows.h. Maybe you could reduce the negative impact of that by providing a way to build that part of your library separately.
I missed the most obvious solution (I am using GetLastError because it's
shorter):
inline HANDLE_ kernel32_handle()
{
//it's a system dll, so I don't really need to clean up
static HANDLE_ h = get_module_handle("Kernel32.dll");
return h;
}
inline DWORD_ get_last_error()
{
typedef DWORD_ WINAPI (*GetLastError_t)();
static GetLastError_t p =
reinterpret_cast
On Sunday, 8 May 2016 19:05:45 MSK Klemens Morgenstern wrote:
I missed the most obvious solution (I am using GetLastError because it's shorter):
inline HANDLE_ kernel32_handle() { //it's a system dll, so I don't really need to clean up static HANDLE_ h = get_module_handle("Kernel32.dll"); return h; }
inline DWORD_ get_last_error() { typedef DWORD_ WINAPI (*GetLastError_t)(); static GetLastError_t p = reinterpret_cast
(get_proc_address(kernel32_handle(), "GetLastError")); return (*p)(); } I tested that directly with the winapi, the loaded address is correct.
That way I could load any function and override the enum type. I would have few static handles here, but since they all point to system-apis I don't think it's a problem to not clean them up (though that could be done via unique_ptr). That would also be pure C++03, but of course violate the current winapi style. Would that be acceptable for the winapi by any chance?
In C++03 that is not thread safe (i.e. p may not be initialized on first use). You do have to use call_once or something like it. Also, this is not strictly equivalent to just using the function directly because it involves the library loader and may result in deadlocks if called in DllMain. That said, I don't know if the function in question is safe in this regard in its own right. I think, the GetProcAddress solution might be ok in the context of your library, but probably not in Boost.WinAPI.
participants (2)
-
Andrey Semashev
-
Klemens Morgenstern