How DriverKit driver notify application? - macos

I know how to send data to DriverKit and get back some values, that is application calling IOConnectCallStructMethod() and driver fill the OSData in structureOutput from application.
In my Application it is using IOConnectCallAsyncScalarMethod() and the kext using sendAsyncResult64() to let the app know events coming in. However the method sendAsyncResult64() is not available in DriverKit.
I saw AsyncCompletion looks like solution but no idea to implement it. Anyone know how to do?
Appreciate if any suggestion!

IOUserClient::AsyncCompletion is indeed the replacement for sendAsyncResult64().
To call it successfully, you need to retain the OSAction object supplied in the completion field of the IOUserClientMethodArguments supplied in your ExternalMethod dispatch function. Then, when you are ready to send an asynchronous result, call
userclient->AsyncCompletion(saved_osaction, result, async_arguments, num_async_arguments);
Don't forget to release the OSAction object once you no longer need it. The array of async arguments will be passed to the handler function in the user space application, same as with a kext calling sendAsyncResult64().
Note that you can't asynchronously fill "small" structureOutput fields (4096 bytes or less) as these must be returned in the ExternalMethod handler. Only if the buffer is large enough to be passed via structureOutputDescriptor can you retain that descriptor and fill it with data after the initial ExternalMethod returns. This is no different than for kexts, however.

Related

What is the use of passing additional data in CreateWindowEx

In Windows API docs, it mentions that you can pass additional data like State Information to CreateWindowEx() function as its last parameter which can be accessed during WM_CREATE/WM_NCCREATE events. Then, you can store the state info inside the window itself using SetWindowLongPtr() function.
But what would be the point of doing this if we can directly set data using SetWindowLongPtr() immediately after Window initialization (inside wWinmain())?
Passing user data through the lpParam parameter of CreateWindow/Ex() allows that data to be accessible to your window procedure while CreateWindow/Ex() is still running. There are several messages sent to the window by CreateWindow/Ex() itself, including WM_(NC)CREATE. When WM_(NC)CREATE is received, your data is accessible via the CREATESTRUCT pointed at by the lParam, and so you can then assign that data to the window via SetWindowLongPtr() (or SetProp()) for subsequent messages to access via GetWindowLongPtr() (or GetProp()).
If you wait until after CreateWindow/Ex() has exited before you then call SetWindowLongPtr(), those initial messages won't have a chance to access your data, unless you store it in a global or thread-local variable that the window procedure can access.
Whether or not that is acceptable to you depends on your particular situation.

Some data losts when I use NSURLConnection to get data asynchronously

I deal with the data and do some UI working according to the data in the method
-(void)connection:didReiveiceData(I use delegate as callback), and I find that UI working is always not finished completely.Maybe when the data is received, the UI threading is still busy, so some data losts.You may suggest me to deal with data in -(void)connectionFinishLoading:,it will cause other problems.
You've correctly suggested you need to process the received data in connectionDidFinishLoading:.
Before that, you need to collect all the receivedData (eg into an NSMutableData instance). Append the received data each time didReceiveData: is called (it may be called multiple times before it finishes).
the reason why some data lost is all about the method –rangeOfData:options:range:
I use it wrong.BTW, I think this method is very weird,the option accept only one of two value, NSDataSearchBackwards and NSDataSearchAnchored.why no "NSDataSearchForewards" or something like that?

Send multiple parameters with apple event

I am trying to send an apple event to an application we have developed.
I want to be able to call the apple event, and at the same time pass parameters with the event. eg acctid, acctpassword, order number.
I'm not sure how to format the apple event being sent.
Is this possible?, and if so any guidance.
Thanks
Stephen
I realise that you have accepted the given answer, but you CAN send several parameters within a single AppleEvent.
The parameters are each placed in an AEDesc using AECreateDesc() and are added to the AppleEvent with 4-character code names (OSType).
On the receiving end, they can be retrieved by AEGetParamDesc (theAppleEvent, 4-char-code, ...);
AEGetDescData is then used to extract the data from the AEDesc.
You can also use lists as parameters by using AEDescList values, which are essentially lists of AEDesc values.
The AEBuildDesc() and AEBuildAppleEvent() make the whole process quite easy.
I'm not 100% sure if you can send multiple parameters with a single apple event (though I thought you could but I couldn't find anything on it), but a backup method would be, if you have control to the development of both applications, you can put all of the variables within one parameter using a format you've made to separate the variables. You can simply join them in the first app, and split them up when received in the second app.

Usage of IcmpSendEcho2 with an asynchronous callback

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.

Is NSPasteboard thread-safe?

Is it safe to write data to an NSPasteboard object from a background thread? I can't seem to find a definitive answer anywhere. I think the assumption is that the data will be written to the pasteboard before the drag begins.
Background:
I have an application that is fetching data from Evernote. When the application first loads, it gets the meta data for each note, but not the note content. The note stubs are then listed in an outline view. When the user starts to drag a note, the notes are passed to the background thread that handles getting the note content from Evernote. Having the main thread block until the data is gotten results in a significant delay and a poor user experience, so I have the [outlineView:writeItems:toPasteboard:] function return YES while the background thread processes the data and invokes the main thread to write the data to the pasteboard object. If the note content gets transferred before the user drops the note somewhere, everything works perfectly. If the user drops the note somewhere before the data has been processed... well, everything blocks forever. Is it safe to just have the background thread write the data to the pasteboard?
You can promise the data to the pasteboard without actually having the data yet.
One way is to declare the type of the data on the pasteboard, passing yourself as the pasteboard's owner, and respond to a pasteboard:provideDataForType: message by providing the data (blocking, if necessary, until the data either arrives or fails to arrive). This means that you'll need to remember which objects were copied (by stashing them in an array, for example) so you can extract/generate the data from them when the promise comes due.
The other way, referenced in Harald Scheirich's answer, is to make your model objects conform to the NSPasteboardWriting protocol, ideally in a category (to separate interface-independent logic from Mac-specific logic). This is much cleaner than the old way, but requires Mac OS X 10.6 and later.
With NSPasteboardWriting, you'll implement promises by having the model objects' writingOptionsForType:pasteboard: method return the NSPasteboardWritingPromised option. Their pasteboardPropertyListForType: method will return the data, or at least try to—as before, this method should block until the data either arrives or fails to arrive.
Oh, and to answer the question in the title (“Is NSPasteboard thread-safe?”): There's no specific answer in the Thread Safety Summary, but there is this general statement:
… mutable objects are generally not thread-safe. To use mutable objects in a threaded application, the application must synchronize appropriately.
I would consider an NSPasteboard to be a mutable object, so no.
In practice, this isn't a problem: You typically only work with NSPasteboard in response to an action message (e.g., copy:), a drag, or a service invocation, and those all only happen on the main thread anyway. For them to happen on a secondary thread, you would have to explicitly send such messages yourself from code running on a secondary thread, in which case you are already doing something very wrong.
Conjecture:
I think your problem has nothing to do with threading but the fact that by returning YES you told the system that the data is ready. have you tried moving your data into a custom class supporting NSPasteboardWriting and NSPasteboardReading? this way the accessor to your data can block until the data is ready.
See the Pasteboard Documentation

Resources