Re: it cannot find a User32 function
Michael C <[email protected]> Wed, 3 May 2017 20:36:06 -0700
| Newsgroups | gmane.comp.python.ctypes |
|---|---|
| Message-ID | <CANyKM1g7CJ27oryrjbNgeqJ5=SMf_=5A6GefDWvmEhGQuvGFXw@mail.gmail.com> |
--===============5146058793441756577== Content-Type: multipart/alternative; boundary=001a1140fadc225260054eaa799b --001a1140fadc225260054eaa799b Content-Type: text/plain; charset=UTF-8 how do you set unicode strings? unicode_String = ? thanks! On Wed, May 3, 2017 at 7:53 PM, eryk sun <[email protected]> wrote: > On Wed, May 3, 2017 at 11:19 PM, Michael C > <[email protected]> wrote: > > Hi all, I am trying to move the location and change the size of a window, > > but the User32.FindWindow function cannot be found! > > > > AttributeError: function 'FindWindow' not found > > Here's the prototype from MSDN [1]: > > HWND WINAPI FindWindow( > _In_opt_ LPCTSTR lpClassName, > _In_opt_ LPCTSTR lpWindowName > ); > > [1]: https://msdn.microsoft.com/en-us/library/ms633499 > > The string type is "LPCTSTR". That's a [L]ong [P]ointer (just a > pointer nowadays; there's no segmented addressing) to a [C]onstant > [T]CHAR [STR]ing. A TCHAR is a [T]ext CHAR ("T" could also mean > "typed) that depends on defining the UNICODE macro in C. If the macro > is defined, a TCHAR is a two-byte WCHAR, i.e. a [W]ide CHAR, and > otherwise it's a single-byte CHAR. The macro also determines the > definition of the "T" types. If defined, an LPCTSTR is in turn defined > as an LPCWSTR, and otherwise it's an LPCSTR. > > Historically this split is because single-byte and double-byte code > pages were the way text was localized in the 80s and 90s in MS-DOS and > versions of Windows that extend DOS, i.e. Windows 3.x and 9x. The > newer NT system (developed in 1988-93 and released in 1993 as Windows > NT 3.1) is based on Unicode internally and uses 16-bit WCHARs. > > When the NT designers updated the existing Win16 API to Win32, they > needed to support porting legacy Windows applications that use code > pages, so they developed this typing system based on the UNICODE > macro. Also, when the Win32 API itself was ported to DOS-based Windows > 95, there was only rudimentary Unicode support, so for a long time > even new applications were designed around code pages. Starting with > Windows XP, all versions of Windows use the NT kernel, and by Windows > Vista new functions appear that only support Unicode (e.g. > SetFileInformationByHandle). > > What the FindWindow prototype is not showing is that when Windows is > built it has to support programs compiled for both CHAR and WCHAR. For > most functions Windows NT uses WCHAR, so the CHAR implementation > decodes the string arguments and calls a common internal function. The > code page it decodes from is usually the system-locale ANSI codepage > (e.g. 1252 in the U.S. and Western Europe), with a couple of > exceptions. The file-system 'ANSI' API can be set to the system-locale > OEM codepage (e.g. 850 in Western Europe) via SetFileApisToOEM. Also, > the console 'ANSI' API defaults to OEM and can be set to any > single-byte or multi-byte code page separately for input and screen > buffers via SetConsoleCP and SetConsoleOutputCP. > > Whenever possible you should prefer calling the [W]ide-character > function to avoid writing locale-dependent code. > > That said, here are the actual FindWindow prototypes from the WinUser.h > header: > > WINUSERAPI > HWND > WINAPI > FindWindowA( > _In_opt_ LPCSTR lpClassName, > _In_opt_ LPCSTR lpWindowName); > > WINUSERAPI > HWND > WINAPI > FindWindowW( > _In_opt_ LPCWSTR lpClassName, > _In_opt_ LPCWSTR lpWindowName); > > #ifdef UNICODE > #define FindWindow FindWindowW > #else > #define FindWindow FindWindowA > #endif // !UNICODE > > Since ctypes works at the ABI (application binary interface) level > rather than API (application programmng interface), you need to use > the function names a module actually links with, i.e. either > FindWindowA for the [A]NSI implementation or FindWindowW for the > [W]ide-character implementation. > > Let's take a look at your code. > > > import ctypes > > User32 = ctypes.WinDLL('User32', use_last_error=True) > > window_name = 'Star Wars' > > handle = User32.FindWindow(None, window_name ) > > If you're using Python 3, then 'Star Wars' is a Unicode string, and > you should call FindWindowW. If you're using Python 2, then it's a > byte string, and you should call FindWindowA. But I don't recommend > the latter. You should be working with Unicode, i.e. u'Star Wars'. For > example: > > import ctypes > from ctypes import wintypes > > user32 = ctypes.WinDLL('user32', use_last_error=True) > > user32.FindWindowW.restype = wintypes.HWND > user32.FindWindowW.argtypes = (wintypes.LPCWSTR, > wintypes.LPCWSTR) > > if __name__ == '__main__': > import os > kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) > > window_name = u'Spam Wars' > os.system('title {}'.format(window_name)) > > handle = user32.FindWindowW(None, window_name) > if handle is None: > handle = user32.FindWindowW(None, > u'Administrator: {}'.format(window_name)) > > assert handle == kernel32.GetConsoleWindow() > > Another thing to consider is that if you've defined the FindWindowW > prototype, ctypes in Python 2 will automatically convert a byte-string > argument to Unicode. It uses the encoding and errors that are set by > ctypes.set_conversion_mode(encoding, errors), which defaults to > ('mbcs', 'ignore'). Python's 'mbcs' encoding is the system-locale ANSI > code page. This automatic conversion is not implemented in Python 3 > ctypes, in which case you should definitely be using Unicode. > --001a1140fadc225260054eaa799b Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr">how do you set unicode strings?<div><br></div><div>unicode= _String =3D ?</div><div><br></div><div>thanks!</div></div><div class=3D"gma= il_extra"><br><div class=3D"gmail_quote">On Wed, May 3, 2017 at 7:53 PM, er= yk sun <span dir=3D"ltr"><<a href=3D"mailto:[email protected]" target=3D= "_blank">[email protected]</a>></span> wrote:<br><blockquote class=3D"gm= ail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-le= ft:1ex"><span class=3D"">On Wed, May 3, 2017 at 11:19 PM, Michael C<br> <<a href=3D"mailto:[email protected]">mysecretrobotfactory@= gmail.<wbr>com</a>> wrote:<br> > Hi all, I am trying to move the location and change the size of a wind= ow,<br> > but the User32.FindWindow function cannot be found!<br> ><br> > AttributeError: function 'FindWindow' not found<br> <br> </span>Here's the prototype from MSDN [1]:<br> <br> =C2=A0 =C2=A0 HWND WINAPI FindWindow(<br> =C2=A0 =C2=A0 =C2=A0 _In_opt_ LPCTSTR lpClassName,<br> =C2=A0 =C2=A0 =C2=A0 _In_opt_ LPCTSTR lpWindowName<br> =C2=A0 =C2=A0 );<br> <br> [1]: <a href=3D"https://msdn.microsoft.com/en-us/library/ms633499" rel=3D"n= oreferrer" target=3D"_blank">https://msdn.microsoft.com/en-<wbr>us/library/= ms633499</a><br> <br> The string type is "LPCTSTR". That's a [L]ong [P]ointer (just= a<br> pointer nowadays; there's no segmented addressing) to a [C]onstant<br> [T]CHAR [STR]ing. A TCHAR is a [T]ext CHAR ("T" could also mean<b= r> "typed) that depends on defining the UNICODE macro in C. If the macro<= br> is defined, a TCHAR is a two-byte WCHAR, i.e. a [W]ide CHAR, and<br> otherwise it's a single-byte CHAR. The macro also determines the<br> definition of the "T" types. If defined, an LPCTSTR is in turn de= fined<br> as an LPCWSTR, and otherwise it's an LPCSTR.<br> <br> Historically this split is because single-byte and double-byte code<br> pages were the way text was localized in the 80s and 90s in MS-DOS and<br> versions of Windows that extend DOS, i.e. Windows 3.x and 9x. The<br> newer NT system (developed in 1988-93 and released in 1993 as Windows<br> NT 3.1) is based on Unicode internally and uses 16-bit WCHARs.<br> <br> When the NT designers updated the existing Win16 API to Win32, they<br> needed to support porting legacy Windows applications that use code<br> pages, so they developed this typing system based on the UNICODE<br> macro. Also, when the Win32 API itself was ported to DOS-based Windows<br> 95, there was only rudimentary Unicode support, so for a long time<br> even new applications were designed around code pages. Starting with<br> Windows XP, all versions of Windows use the NT kernel, and by Windows<br> Vista new functions appear that only support Unicode (e.g.<br> SetFileInformationByHandle).<br> <br> What the FindWindow prototype is not showing is that when Windows is<br> built it has to support programs compiled for both CHAR and WCHAR. For<br> most functions Windows NT uses WCHAR, so the CHAR implementation<br> decodes the string arguments and calls a common internal function. The<br> code page it decodes from is usually the system-locale ANSI codepage<br> (e.g. 1252 in the U.S. and Western Europe), with a couple of<br> exceptions. The file-system 'ANSI' API can be set to the system-loc= ale<br> OEM codepage (e.g. 850 in Western Europe) via SetFileApisToOEM. Also,<br> the console 'ANSI' API defaults to OEM and can be set to any<br> single-byte or multi-byte code page separately for input and screen<br> buffers via SetConsoleCP and SetConsoleOutputCP.<br> <br> Whenever possible you should prefer calling the [W]ide-character<br> function to avoid writing locale-dependent code.<br> <br> That said, here are the actual FindWindow prototypes from the WinUser.h hea= der:<br> <br> =C2=A0 =C2=A0 WINUSERAPI<br> =C2=A0 =C2=A0 HWND<br> =C2=A0 =C2=A0 WINAPI<br> =C2=A0 =C2=A0 FindWindowA(<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 _In_opt_ LPCSTR lpClassName,<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 _In_opt_ LPCSTR lpWindowName);<br> <br> =C2=A0 =C2=A0 WINUSERAPI<br> =C2=A0 =C2=A0 HWND<br> =C2=A0 =C2=A0 WINAPI<br> =C2=A0 =C2=A0 FindWindowW(<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 _In_opt_ LPCWSTR lpClassName,<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 _In_opt_ LPCWSTR lpWindowName);<br> <br> =C2=A0 =C2=A0 #ifdef UNICODE<br> =C2=A0 =C2=A0 #define FindWindow=C2=A0 FindWindowW<br> =C2=A0 =C2=A0 #else<br> =C2=A0 =C2=A0 #define FindWindow=C2=A0 FindWindowA<br> =C2=A0 =C2=A0 #endif // !UNICODE<br> <br> Since ctypes works at the ABI (application binary interface) level<br> rather than API (application programmng interface), you need to use<br> the function names a module actually links with, i.e. either<br> FindWindowA for the [A]NSI implementation or FindWindowW for the<br> [W]ide-character implementation.<br> <br> Let's take a look at your code.<br> <span class=3D""><br> > import ctypes<br> > User32 =3D ctypes.WinDLL('User32', use_last_error=3DTrue)<br> > window_name =3D 'Star Wars'<br> > handle =3D User32.FindWindow(None, window_name )<br> <br> </span>If you're using Python 3, then 'Star Wars' is a Unicode = string, and<br> you should call FindWindowW. If you're using Python 2, then it's a<= br> byte string, and you should call FindWindowA. But I don't recommend<br> the latter. You should be working with Unicode, i.e. u'Star Wars'. = For<br> example:<br> <br> =C2=A0 =C2=A0 import ctypes<br> =C2=A0 =C2=A0 from ctypes import wintypes<br> <br> =C2=A0 =C2=A0 user32 =3D ctypes.WinDLL('user32', use_last_error=3DT= rue)<br> <br> =C2=A0 =C2=A0 user32.FindWindowW.restype =3D wintypes.HWND<br> =C2=A0 =C2=A0 user32.FindWindowW.argtypes =3D (wintypes.LPCWSTR,<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 wintypes.LPCWSTR)<br> <br> =C2=A0 =C2=A0 if __name__ =3D=3D '__main__':<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 import os<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 kernel32 =3D ctypes.WinDLL('kernel32', = use_last_error=3DTrue)<br> <br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 window_name =3D u'Spam Wars'<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 os.system('title {}'.format(window_name= ))<br> <br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 handle =3D user32.FindWindowW(None, window_name= )<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 if handle is None:<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 handle =3D user32.FindWindowW(Non= e,<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 u'Administrator= :=C2=A0 {}'.format(window_name))<br> <br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 assert handle =3D=3D kernel32.GetConsoleWindow(= )<br> <br> Another thing to consider is that if you've defined the FindWindowW<br> prototype, ctypes in Python 2 will automatically convert a byte-string<br> argument to Unicode. It uses the encoding and errors that are set by<br> ctypes.set_conversion_mode(<wbr>encoding, errors), which defaults to<br> ('mbcs', 'ignore'). Python's 'mbcs' encoding is= the system-locale ANSI<br> code page. This automatic conversion is not implemented in Python 3<br> ctypes, in which case you should definitely be using Unicode.<br> </blockquote></div><br></div> --001a1140fadc225260054eaa799b-- --===============5146058793441756577== Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot --===============5146058793441756577== Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ ctypes-users mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/ctypes-users --===============5146058793441756577==--