views:

456

answers:

2

I have a Windows application that HAS to run as 32-bits (because of other limitations out of my control). However, my application has to call and access a driver which may be 32-bits or 64-bits depending on the system where it is installed.

I access the driver through DeviceIoControl() calls, exchanging data structures declared in an include file. Data structures contains fields declared as "DWORD_PTR" (the include file I don't control either).

My problem is that on a 64-bits system, the driver expects the structures to contain 64-bits integer (because of DWORD_PTR declaration). However, my 32-bits program sees those DWORD_PTR as 32-bits integers. I then have a data mismatch between my program version of the data structures and the driver understanding of those structures.

DeviceIoControl() ends-up failing with ERROR_INSUFFICIENT_BUFFER (The data area passed to a system call is too small). I confirmed that I don't get this error if I pass a 64-bits version of the structs to the driver.

I have a few ugly options out of this mess. But I wonder if anyone has some nicer suggestions?


Solution:

  • Declare a new copy of the shared structures with REAL 64-bits data fields (__int64)
  • Dynamically check the OS architecture (32/64)
  • Use the 32-bits or 64-bits version of the structures for the DeviceIoControl() calls.

Drawbacks:

  • I have to maintain an explicit 64-bits copy of the structures declaration manually. It can be a pain over time.


My other solutions are variation of this one, but they ALWAYS involve maintaining some copy of the structures definition (for example in an IDL for COM servers option).

Edit: This is a Microsoft driver and it seems it does not use IoIs32bitsProcess(irp)!

+2  A: 

You maintain both 32-bit and 64-bit version of structures and implement special handling via IoIs32BitProcess(irp) function in device driver DEVICE_CONTROL handler and convert it to 64-bit structure whenever needed. This is the common way of doing it.

Here is a good amount of documentation about it on MSDN.

Since you later mentioned you don't have control over driver source code, I suggest you to maintain your own variant for 32-bit on 64-bit and send the right one checking the OS architecture. It looks like structure declarations are not done properly for the driver.

ssg
I don't control the driver. IoIs32BitProcess() is called from the driver, not my application. Obviously it doesn't because I am getting error codes ERROR_INSUFFICIENT_BUFFER (The data area passed to a system call is too small.)
Philibert Perusse
Oh if you don't have control over driver source code, you basically need to have access to structure declarations the driver provides. If they don't provide anything, you need to experiment with both 32-bit and 64-bit structures.
ssg
They do provide structure declarations. But they declare fields as DWORD_PTR. So I am basically stuck with my ugly solution. I works, I tested it, but I hoped for something cleaner.
Philibert Perusse
Obviously they didn't provide the structures the proper way. I can't think of a clean solution over a dirty implementation :)
ssg
You might as well consider filing a bug to the party that developed the driver.
ssg
A: 

Is there a way to manipulate a #define when including the header with the structure defs such that you're always using the 64-bit definition? That seems like the best option to me (if possible that is).

If not, I'd shadow the 64-bit structure in my own code -- that way there is only a strucuture def to watch out for, rather than a bunch of if32bit/if64bit stuff sprinkled throughout -- that seems more bug prone. Perhaps you could do something like:

_ASSERT(sizeof(myStruct) == sizeof(64bitStruct))

at the start of your app, so if you ever get newer headers, the first run of your app will remind you that you need to sync.

DougN