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">&lt;<a href=3D"mailto:[email protected]" target=3D=
"_blank">[email protected]</a>&gt;</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>
&lt;<a href=3D"mailto:[email protected]">mysecretrobotfactory@=
gmail.<wbr>com</a>&gt; wrote:<br>
&gt; Hi all, I am trying to move the location and change the size of a wind=
ow,<br>
&gt; but the User32.FindWindow function cannot be found!<br>
&gt;<br>
&gt; AttributeError: function &#39;FindWindow&#39; not found<br>
<br>
</span>Here&#39;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 &quot;LPCTSTR&quot;. That&#39;s a [L]ong [P]ointer (just=
 a<br>
pointer nowadays; there&#39;s no segmented addressing) to a [C]onstant<br>
[T]CHAR [STR]ing. A TCHAR is a [T]ext CHAR (&quot;T&quot; could also mean<b=
r>
&quot;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&#39;s a single-byte CHAR. The macro also determines the<br>
definition of the &quot;T&quot; types. If defined, an LPCTSTR is in turn de=
fined<br>
as an LPCWSTR, and otherwise it&#39;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 &#39;ANSI&#39; API can be set to the system-loc=
ale<br>
OEM codepage (e.g. 850 in Western Europe) via SetFileApisToOEM. Also,<br>
the console &#39;ANSI&#39; 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&#39;s take a look at your code.<br>
<span class=3D""><br>
&gt; import ctypes<br>
&gt; User32 =3D ctypes.WinDLL(&#39;User32&#39;, use_last_error=3DTrue)<br>
&gt; window_name =3D &#39;Star Wars&#39;<br>
&gt; handle =3D User32.FindWindow(None, window_name )<br>
<br>
</span>If you&#39;re using Python 3, then &#39;Star Wars&#39; is a Unicode =
string, and<br>
you should call FindWindowW. If you&#39;re using Python 2, then it&#39;s a<=
br>
byte string, and you should call FindWindowA. But I don&#39;t recommend<br>
the latter. You should be working with Unicode, i.e. u&#39;Star Wars&#39;. =
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(&#39;user32&#39;, 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 &#39;__main__&#39;:<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 import os<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 kernel32 =3D ctypes.WinDLL(&#39;kernel32&#39;, =
use_last_error=3DTrue)<br>
<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 window_name =3D u&#39;Spam Wars&#39;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 os.system(&#39;title {}&#39;.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&#39;Administrator=
:=C2=A0 {}&#39;.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&#39;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>
(&#39;mbcs&#39;, &#39;ignore&#39;). Python&#39;s &#39;mbcs&#39; 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==--