Let's say my application calls CoInitialize when it starts and CoUninitialize before it exists.
Assuming I have a 3rd party component that's used by my application and does a similar thing, will this cause some kind of failure?
is it okay to call CoInitialize when that call has already been submitted? will the second call fail? or will it just "let it pass" as it's already called.
CoInitialize will return S_FALSE if it has already been initialized in the calling thread. However, for both invocations that return S_OK and S_FALSE there needs to be a CoUninitialize call. The number of calls to this functions get counted, and only when the number of CoUninitialize equals that of CoInitialize it will actually uninitialize things.
So in conclusion, a second call is harmless, and there are no problems with calling this pair of functions more than once.
It is pretty fundamentally wrong, CoInitialize() must be called by the code that owns the thread. Which is never the 3rd party component if it acts like an in-process server and doesn't start its own threads.
And sure, this can and will go wrong when it doesn't agree about the apartment type. Which is something it cannot guarantee, an STA is the usual choice and that requires pumping a message loop. The component won't do that, it's the host's job. And if the apartment type is a mismatch then it needs to marshal the interface pointer. Which it won't do when it relies on its apartment type of choice.
Related
I'm using WinHTTP in sync mode, without passing the WINHTTP_FLAG_ASYNC flag, and I thought that the callback is always being called synchronously. That is indeed what's happening most of the time, but sometimes, when calling WinHttpCloseHandle, the callback isn't called with the WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING notification right away. Instead, it's being called afterwards from a different thread.
It that expected behavior? Why does it become async for some cases, if the seesion is sync? I know how to fix it (waiting for the WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING notification if I don't get it right away), but I don't understand why that's the behavior that I'm seeing.
WinHTTP does not promise synchronous "same thread" callbacks in synchronous mode. On the contrary, MSDN states the opposite:
The callback function must be threadsafe and reentrant because it can be called on another thread for a separate request, and reentered on the same thread for the current request. It must therefore be coded to handle reentrance safely while processing. When the dwInternetStatus parameter is equal to WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, the callback does not need to be able to handle reentrance for the same request, because this callback is guaranteed to be the last, and does not occur when other messages for this request are handled.
This means that the symptom you are seeing is basically behavior by design and is not related to async mode: some callback calls might be sent to you from worker threads and then thread racing might reach your code late in your callback. You need to take this into consideration and either ignore those late calls, or synchronize with them, or reset callbacks early enough explicitly to not receive late notifications.
Regarding WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING specifically MSDN explains what you can rely on exactly (see quote above).
I remember there was a way to do this, something similar to unix signals, but not so widely used. But can't remember the term. No events/mutexes are used: the thread is just interrupted at random place, the function is called and when it returns, the thread continues.
Windows has Asynchronous Procedure Calls which can call a function in the context of a specific thread. APC's do not just interrupt a thread at a random place (that would be dangerous - the thread could be in the middle of writing to a file or obtaining a lock or in Kernel mode). Instead an APC will be dispatched when the calling thread enters an alterable wait by calling a specific function (See the APC documentation).
If the reason that you need to call code in a specific thread is because you are interacting with the user interface, it would be more direct to send or post a window message to the window handle that you want to update. Window messages are always processed in the thread that created the window.
you can search RtlRemoteCall, it's an undocumented routine though. there's APC in Windows semantically similar to Unix signal, however APC requires target thread is in an alertable state to get delivered, it's not guaranteed this condition is always met
Assuming that GetDC(hWnd) is called as the first instruction on WM_CREATE, for window hWnd, is it possible for GetDC() to return NULL?
I am concerned about the possibility of GetDC() failing due to lack of resources. When that happens should I check for errors? And what should I do if the call fails? Do the Win32 API function raise exceptions or should I raise exceptions?
GetDC() can indeed fail, no matter when or where you call it. You ought to take a rather pessimistic view when dealing with the API and be prepared for any API function to fail. As you suggest, one possible reason for failure is exhaustion of system resources, e.g. kernel handles, GDI objects etc.
So you should always check for errors. And not just GetDC(), every single call to an API function should have its return value checked.
The Windows API does not signal errors by raising exceptions. Instead the errors are always signalled through the values returned by the API function. You need to consult the documentation to understand how each individual function reports errors.
If you encounter a failure in a GDI function like GetDC() then there's not a lot you can do. In the scenario you describe I would log the error or report it to the user, and then terminate execution. There's generally no recovery from a failure of GetDC().
The pain of checking for errors every time an API function is called is one of the reasons why we have so many frameworks that wrap the low level API. A good framework will do the error checking for you and convert any errors into exceptions. Using a good framework allows you to concentrate on the normal flow of execution and not littering your code with handling code for exceptional cases.
Let's say my application calls CoInitialize when it starts and CoUninitialize before it exists.
Assuming I have a 3rd party component that's used by my application and does a similar thing, will this cause some kind of failure?
is it okay to call CoInitialize when that call has already been submitted? will the second call fail? or will it just "let it pass" as it's already called.
CoInitialize will return S_FALSE if it has already been initialized in the calling thread. However, for both invocations that return S_OK and S_FALSE there needs to be a CoUninitialize call. The number of calls to this functions get counted, and only when the number of CoUninitialize equals that of CoInitialize it will actually uninitialize things.
So in conclusion, a second call is harmless, and there are no problems with calling this pair of functions more than once.
It is pretty fundamentally wrong, CoInitialize() must be called by the code that owns the thread. Which is never the 3rd party component if it acts like an in-process server and doesn't start its own threads.
And sure, this can and will go wrong when it doesn't agree about the apartment type. Which is something it cannot guarantee, an STA is the usual choice and that requires pumping a message loop. The component won't do that, it's the host's job. And if the apartment type is a mismatch then it needs to marshal the interface pointer. Which it won't do when it relies on its apartment type of choice.
I've been reading the MSDN documentation for IcmpSendEcho2 and it raises more questions than it answers.
I'm familiar with asynchronous callbacks from other Win32 APIs such as ReadFileEx... I provide a buffer which I guarantee will be reserved for the driver's use until the operation completes with any result other than IO_PENDING, I get my callback in case of either success or failure (and call GetCompletionStatus to find out which). Timeouts are my responsibility and I can call CancelIo to abort processing, but the buffer is still reserved until the driver cancels the operation and calls my completion routine with a status of CANCELLED. And there's an OVERLAPPED structure which uniquely identifies the request through all of this.
IcmpSendEcho2 doesn't use an OVERLAPPED context structure for asynchronous requests. And the documentation is unclear excessively minimalist about what happens if the ping times out or fails (failure would be lack of a network connection, a missing ARP entry for local peers, ICMP destination unreachable response from an intervening router for remote peers, etc).
Does anyone know whether the callback occurs on timeout and/or failure? And especially, if no response comes, can I reuse the buffer for another call to IcmpSendEcho2 or is it forever reserved in case a reply comes in late?
I'm wanting to use this function from a Win32 service, which means I have to get the error-handling cases right and I can't just leak buffers (or if the API does leak buffers, I have to use a helper process so I have a way to abandon requests).
There's also an ugly incompatibility in the way the callback is made. It looks like the first parameter is consistent between the two signatures, so I should be able to use the newer PIO_APC_ROUTINE as long as I only use the second parameter if an OS version check returns Vista or newer? Although MSDN says "don't do a Windows version check", it seems like I need to, because the set of versions with the new argument aren't the same as the set of versions where the function exists in iphlpapi.dll.
Pointers to additional documentation or working code which uses this function and an APC would be much appreciated.
Please also let me know if this is completely the wrong approach -- i.e. if either using raw sockets or some combination of IcmpCreateFile+WriteFileEx+ReadFileEx would be more robust.
I use IcmpSendEcho2 with an event, not a callback, but I think the flow is the same in both cases. IcmpSendEcho2 uses NtDeviceIoControlFile internally. It detects some ICMP-related errors early on and returns them as error codes in the 12xx range. If (and only if) IcmpSendEcho2 returns ERROR_IO_PENDING, it will eventually call the callback and/or set the event, regardless of whether the ping succeeds, fails or times out. Any buffers you pass in must be preserved until then, but can be reused afterwards.
As for the version check, you can avoid it at a slight cost by using an event with RegisterWaitForSingleObject instead of an APC callback.