Wednesday, July 26, 2017

Further progress on the P/Invoke command-line tool

Continuing on from yesterday, I added more features to my P/Invoke command-line tool that expanded the set of functions it can handle. First I added support for null-terminated strings, both ANSI and Unicode, under the type names lpstr and lpwstr.

Then I went about supporting "out" parameters, those that take a pointer and put something in it. To do that, I introduced the concept of "slots," which can be allocated, passed to a function, and then printed to the screen. Of course, multiple-instruction commands required a way to pass multiple logical lines on the command line, so that required a little parser adjustment to treat a semicolon like a line separator. To implement the definition of slots, I refactored the other data-type select statements into a "kind" system. A kind object provides information on how to display and store values of that type.

Slots can be created with the newslot command (which takes the kind, name, and optionally an initial value):

newslot int quota

Slots can be used in calls. To pass the address of a slot (i.e. its pointer), use the slotptr keyword. To pass its current value, use slotdata.

call kernel32.dll!GetSystemRegistryQuota (nullptr, slotptr quota)

Finally, a slot can be printed with the readslot command:

readslot quota

Chaining all those together with semicolons retrieves and displays the current size of the Registry.

To see why a function is failing, it's useful to get the last Win32 error code. Unfortunately, dynamically generated P/Invoke methods don't seem to have a way of setting the last error for ease of managed access. So I just P/Invoke GetLastError after every call and store it in case the user issues a lasterror to retrieve it.

No comments:

Post a Comment