Jardz Posted March 26, 2015 Posted March 26, 2015 (edited) 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. expandcollapse popup#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 March 26, 2015 by Jardz
JohnOne Posted March 26, 2015 Posted March 26, 2015 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.
Jardz Posted March 26, 2015 Author Posted March 26, 2015 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
JohnOne Posted March 26, 2015 Posted March 26, 2015 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.
Jardz Posted March 26, 2015 Author Posted March 26, 2015 No difference at all, sorry!! It's dirty left over from everything I've tried... I started getting desperate. The script I put together just for testing, unfortunately it hasn't helped...
JohnOne Posted March 26, 2015 Posted March 26, 2015 Have you looked at a C implementation? http://support.microsoft.com/en-us/kb/167345 AutoIt Absolute Beginners Require a serial Pause Script Video Tutorials by Morthawt ipify Monkey's are, like, natures humans.
Jardz Posted March 26, 2015 Author Posted March 26, 2015 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!
Tripredacus Posted March 26, 2015 Posted March 26, 2015 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 Twitter | MSFN | VGCollect
Jardz Posted March 26, 2015 Author Posted March 26, 2015 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....
JohnOne Posted March 26, 2015 Posted March 26, 2015 (edited) Could try UINT64 or UINT64* Or INT64 or INT64* Edited March 26, 2015 by JohnOne AutoIt Absolute Beginners Require a serial Pause Script Video Tutorials by Morthawt ipify Monkey's are, like, natures humans.
Jardz Posted March 26, 2015 Author Posted March 26, 2015 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 I'm running 3.3.12.0, I've not tried Beta yet, so not sure if there's anything new that may help.
Tripredacus Posted March 26, 2015 Posted March 26, 2015 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. Twitter | MSFN | VGCollect
Jardz Posted March 26, 2015 Author Posted March 26, 2015 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.
Mugen Posted March 26, 2015 Posted March 26, 2015 There are functions that are not designed to work under WoW emulation. Properly this is one of them.
UEZ Posted March 26, 2015 Posted March 26, 2015 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!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
Jardz Posted March 27, 2015 Author Posted March 27, 2015 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.
Jardz Posted March 27, 2015 Author Posted March 27, 2015 @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
JohnOne Posted March 27, 2015 Posted March 27, 2015 (edited) Are you using the autoit wrapper to make sure exe is compiled as 32, 64 bit EDIT: Or is it pragma now... #pragma compile(x64, false) Edited March 27, 2015 by JohnOne AutoIt Absolute Beginners Require a serial Pause Script Video Tutorials by Morthawt ipify Monkey's are, like, natures humans.
Jardz Posted March 27, 2015 Author Posted March 27, 2015 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...
UEZ Posted March 27, 2015 Posted March 27, 2015 (edited) @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 March 27, 2015 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!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now