Jump to content

Dllcall from 32 bit compile not working on 64 bit


 Share

Go to solution Solved by Jardz,

Recommended Posts

Hi all,

Hope someone out there can help...

I'm having a problem trying to get the following test script to work under windows 8.1 64bit when compiled as 32 bit.

The 64bit compile works fine!?? Also, the 32 bit compile works fine on 32 bit...

I've found some information on the issue here

http://www.pinvoke.net/default.aspx/winspool/DocumentProperties.html

They refer to using 'IntPtr.Zero' which seems to be for C#.

More info here

https://msdn.microsoft.com/en-us/library/system.intptr.zero(v=vs.110).aspx

I'm sure the issue is with the data type set for the pointer to the devmode struct but I've tried everything I can think of.

Please see follow test script to show the issue.

Many thanks in advance

**Edit**  Cleaned up first line of _DocumentProperties() function, as per JohnOne's comment below.

#include <Array.au3>
#include <WinAPIEx.au3>


Global Const $DM_OUT_DEFAULT = 1

Local $sPrinterName = _GetDefaultPrinter()
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $sPrinterName = ' & $sPrinterName & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
Local $iDevModeSize = _DocumentProperties(0, $sPrinterName)
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $iDevModeSize = ' & $iDevModeSize & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
Local $ptrDevMode= _WinAPI_CreateBuffer($iDevModeSize);adding 100 due to
Local $tDevMode = DllStructCreate($tagDEVMODE, $ptrDevMode)
DllStructSetData($tDevMode, "Size", DllStructGetSize($tDevMode))

;Local $iTestBufferSize = _WinAPI_GetMemorySize($ptrDevMode)
;MsgBox(4096, "Memory Size", $iTestBufferSize)
;_WinAPI_DisplayStruct($tDevMode, $tagDEVMODE)

_DocumentProperties(0, $sPrinterName, $tDevMode, $DM_OUT_DEFAULT)

_WinAPI_DisplayStruct($tDevMode, $tagDEVMODE)


$tDevMode = 0
_WinAPI_FreeMemory($ptrDevMode)

Exit


Func _DocumentProperties($hPrinter, $sPrinter, $tDevModeOutput = 0, $iFunc = 0)
    Local $ptrDevModeInput = DllStructGetPtr($tDevModeOutput)
    If $iFunc <> 0 Then MsgBox(0, "Pointer", $ptrDevModeInput)
    Local $ptrDevModeOut = $ptrDevModeInput
    Local $aResult = DllCall("Winspool.drv", "long", "DocumentPropertiesW", "hwnd", 0, "ptr", 0, "wstr", $sPrinter, "ptr", $ptrDevModeOut, "ptr", 0, "dword", $iFunc)
    ;_ArrayDisplay($aResult)
    Return $aResult[0]
EndFunc



Func _GetDefaultPrinter()
    Local $tBufferSize = DllStructCreate("dword")
    DllCall("Winspool.drv", "long", "GetDefaultPrinterW", "wstr", 0, "ptr", DllStructGetPtr($tBufferSize))
    Local $tPrinterName = DllStructCreate("wchar[" & DllStructGetData($tBufferSize, 1) & "]")
    DllCall("Winspool.drv", "long", "GetDefaultPrinterW", "ptr", DllStructGetPtr($tPrinterName), "ptr", DllStructGetPtr($tBufferSize))
    Local $sPrinter = DllStructGetData($tPrinterName, 1)
    $tPrinterName = 0
    $tBufferSize = 0
    Return $sPrinter
EndFunc
Edited by Jardz
Link to comment
Share on other sites

From what I can make out, these are what the types should be, so I guess you need to rethink you values.

For example does _GetDefaultPrinter() return a pointer?

Local $aResult = DllCall("Winspool.drv", "long", "DocumentPropertiesW", "handle", 0, "LONG_PTR", 0, "wstr*", $sPrinter, "ptr", $ptrDevModeOut, "ptr", 0, "dword", $iFunc)

AutoIt Absolute Beginners    Require a serial    Pause Script    Video Tutorials by Morthawt   ipify 

Monkey's are, like, natures humans.

Link to comment
Share on other sites

Hi JohnOne,

Many thanks for looking at this.

The _GetDefaultPrinter() functions working as is, the return is not so important, more that it populates the $tPrinterName struct with the printer name. I think the return might be the length of the string (possibly).

Anyway, my main problem is with the 'DocumentPropertiesW' second call to populate the $tDevmode struct.

The 'wstr' can't be a 'wstr*', it's not returning the pointer, it's just an input string.

The 'long_ptr' is interesting, I thought this might be where the issue lies. I've also tried 'int_ptr but still no joy.'

This is very strange....

Please keep any ideas coming, this is making me go more grey :wacko:

Link to comment
Share on other sites

Is there a reason you get a pointer to specific element of struct

Local $ptrDevModeInput = DllStructGetPtr($tDevModeOutput, 1)

Is Local $ptrDevModeInput = DllStructGetPtr($tDevModeOutput) any different?

AutoIt Absolute Beginners    Require a serial    Pause Script    Video Tutorials by Morthawt   ipify 

Monkey's are, like, natures humans.

Link to comment
Share on other sites

Interestingly I have that working except for the issue above. So on 32bit OS or a 64bit compile I can initialize a PrinterDC with my modified devmode just fine. Then print what I want.

It's step 2. where you populate your devmode struct with either the default or buffer settings. This dllcall fails if you have compiled 32 bit but running on 64 bit.

Interestingly step 1. works fine, I can get the size.

I thought I might be posting a working example until I came across this issue by accident!

Link to comment
Share on other sites

If you ran ProcMon on your .EXE you will find out why this happens.

You are calling the .dll by its filename only which means you are letting Windows determine where the file is.

A 32bit .EXE will use a search path which includes Syswow64, 64bit will use System32 directory.

Try pathing directly to where the DLL is located. If you FQP to C:\Windows\System32\winspool.drv and it still is using the one in Syswow64, use "sysnative" in your path.

c:windowssysnativewinspool.drv

Link to comment
Share on other sites

Hi Tripredacus,

Thanks for the suggestion, I've tried a lot over the last few days but not this.

I've tired both your suggestions but the system32 gives the same results, and the sysnative does not find winspool.sys.

The OS I'm testing on is Win 8.164 bit.

Regarding referencing winspool.drv by name only, I thought this was the correct way to do it? Allow windows to redirect appropriately.

Looking a Procmon I can see it tried current working directory first then syswow64 where it finds winspool.drv. This is what I'd expect to be correct??

My test script runs a dllcall to winspool.drv twice, the first time just to get the size required. This call works!

I'm convinced the issue is with the pointer field used for the out_buffer location. In my script it's  "ptr", $ptrDevMode.

JohnOne has thought of this and suggested 'long_ptr' which is large enough for 64bit addressing. But this fails also  :(

I'm wondering about  'IntPtr.Zero'?????

Please keep any ideas coming....

Link to comment
Share on other sites

Hi again JohnOne,

I think I may have tried them all!

Starting to think this may not be achievable with Autoit...yet! It's not a terrible thing, it's only the 32 on 64 OS that's failing. I could just have two exe's

I'm just not experienced enough to know to give up  :D

I'm running 3.3.12.0, I've not tried Beta yet, so not sure if there's anything new that may help.

Link to comment
Share on other sites

Regarding referencing winspool.drv by name only, I thought this was the correct way to do it? Allow windows to redirect appropriately.

Looking a Procmon I can see it tried current working directory first then syswow64 where it finds winspool.drv. This is what I'd expect to be correct??

Yes, that is the expected result. Windows knows that a 32bit .EXE has no use for 64bit binaries, so the 2nd place to look for things is syswow64.

Unfortunately, this is not the one you want to be using.

I have a program that runs into this, so I do an @OSarch detection. If amd64 then run a separate .exe (which is compiled x64) else if x86 then run the command.

The only reason why I opted to run a separate .exe is because you end up getting flaky results in trying to use the Sysnative link. Also I needed a quick fix and it works well enough not to bother finding another solution.

I have seen on some other threads that there is a way to tell AutoIT to disable the WoW redirect. I have not used that before.

Link to comment
Share on other sites

Thanks Tripredacus,

Your solution is one I've been preparing to fall back on, compile both then call the one for the @OSarch.

It's a shame as I wanted one exe to keep things tidy.

I'm sure the 32bit winspool.drv has the ability to do what I want it to, just I can't dllcall it correctly with Autoit.

I've tried calling the 64bit winspool.drv but this fails completely. As I expected it do. I don't believe I can use the 64 bit winspool on a 32 bit exe.

Many thanks JohnOne and Tripedacus.

Link to comment
Share on other sites

I tested the code from post#1 compiled on my Win8.1 x64 system and both versions (x86/x64) work properly.

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

Thanks UEZ for testing. It's not good being this confused first thing before strong coffee!! 

On my Win 8.1 64bit PC I'm logged in as an Administrator with UAC off.

I've tried multiple printers that are on this machine and even tried various compatibility options.

But I can not get the 32bit compile to populate the devmode buffer!!

I'll test on another PC later today.

Link to comment
Share on other sites

@UEZ,

Are you compiling a Beta version? and can you please post your $tagDEVMODE string?

I've tested mine and it's definitely not working on x64.

I'm wondering if you have a different $tagDEVMODE which aligns better when x86 is running on x64. Maybe a different data type is used somewhere????

Many thanks

Link to comment
Share on other sites

I'm using the AutoIt3Wrapper

#AutoIt3Wrapper_Compile_Both=y

Just starting to look at the Beta download.

At first glance the $tagDEVMODE looks the same.

I might be looking at this wrong but the official Devmode structure is a little complicated, thankfully some of the awkward elements are for displays.

I have noticed that if the Devmode struct is wrong, then the symptoms are the same as what I'm seeing with the x86 on x64 OS.

UEZ has given me hope, I'd all but given up...

Link to comment
Share on other sites

@UEZ,

Are you compiling a Beta version? and can you please post your $tagDEVMODE string?

I've tested mine and it's definitely not working on x64.

I'm wondering if you have a different $tagDEVMODE which aligns better when x86 is running on x64. Maybe a different data type is used somewhere????

Many thanks

 

Here the tag:

$tagDEVMODE = "wchar DeviceName[32];ushort SpecVersion;ushort DriverVersion;ushort Size;ushort DriverExtra;dword Fields;short Orientation;short PaperSize;short PaperLength;short PaperWidth;short Scale;short Copies;short DefaultSource;short PrintQuality;short Color;short Duplex;short YResolution;short TTOption;short Collate;wchar FormName[32];ushort Unused1;dword Unused2[3];dword Nup;dword Unused3;dword ICMMethod;dword ICMIntent;dword MediaType;dword DitherType;dword Reserved1;dword Reserved2;dword PanningWidth;dword PanningHeight"

I've compiled the code from post#1 but using 

#AutoIt3Wrapper_Compile_Both=y
#include <WinAPISys.au3>
#include <WinAPIDiag.au3> 

instead of 

#include <WinAPIEx.au3> 

but the result is the same for 3.3.12.0 / 3.3.13.20. In each case the struct will be displayed properly.

You can try my executables: http://www.mediafire.com/download/d6gildexog7jfrc/DocumentPropertiesW_Test.7z

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...