1package FFI::Platypus::Lang::Win32; 2 3use strict; 4use warnings; 5use 5.008004; 6use Config; 7 8# ABSTRACT: Documentation and tools for using Platypus with the Windows API 9our $VERSION = '1.56'; # VERSION 10 11 12sub abi 13{ 14 $^O =~ /^(cygwin|MSWin32|msys)$/ && $Config{ptrsize} == 4 15 ? 'stdcall' 16 : 'default_abi'; 17} 18 19 20my %map; 21 22sub native_type_map 23{ 24 unless(%map) 25 { 26 require FFI::Platypus::ShareConfig; 27 %map = %{ FFI::Platypus::ShareConfig->get('type_map') }; 28 29 my %win32_map = qw( 30 BOOL int 31 BOOLEAN BYTE 32 BYTE uchar 33 CCHAR char 34 CHAR char 35 COLORREF DWORD 36 DWORD uint 37 DWORDLONG uint64 38 DWORD_PTR ULONG_PTR 39 DWORD32 uint32 40 DWORD64 uint64 41 FLOAT float 42 HACCEL HANDLE 43 HANDLE PVOID 44 HBITMAP HANDLE 45 HBRUSH HANDLE 46 HCOLORSPACE HANDLE 47 HCONV HANDLE 48 HCONVLIST HANDLE 49 HCURSOR HICON 50 HDC HANDLE 51 HDDEDATA HANDLE 52 HDESK HANDLE 53 HDROP HANDLE 54 HDWP HANDLE 55 HENHMETAFILE HANDLE 56 HFILE int 57 HFONT HANDLE 58 HGDIOBJ HANDLE 59 HGLOBAL HANDLE 60 HHOOK HANDLE 61 HICON HANDLE 62 HINSTANCE HANDLE 63 HKEY HANDLE 64 HKL HANDLE 65 HLOCAL HANDLE 66 HMENU HANDLE 67 HMETAFILE HANDLE 68 HMODULE HINSTANCE 69 HMONITOR HANDLE 70 HPALETTE HANDLE 71 HPEN HANDLE 72 HRESULT LONG 73 HRGN HANDLE 74 HRSRC HANDLE 75 HSZ HANDLE 76 HWINSTA HANDLE 77 HWND HANDLE 78 INT int 79 INT8 sint8 80 INT16 sint16 81 INT32 sint32 82 INT64 sint64 83 LANGID WORD 84 LCID DWORD 85 LCTYPE DWORD 86 LGRPID DWORD 87 LONG sint32 88 LONGLONG sint64 89 LONG32 sint32 90 LONG64 sint64 91 LPCSTR string 92 LPCVOID opaque 93 LPVOID opaque 94 LRESULT LONG_PTR 95 PSTR string 96 PVOID opaque 97 QWORD uint64 98 SC_HANDLE HANDLE 99 SC_LOCK LPVOID 100 SERVICE_STATUS_HANDLE HANDLE 101 SHORT sint16 102 SIZE_T ULONG_PTR 103 SSIZE_T LONG_PTR 104 UCHAR uint8 105 UINT uint 106 UINT8 uint8 107 UINT16 uint16 108 UINT32 uint32 109 UINT64 uint64 110 ULONG uint32 111 ULONGLONG uint64 112 ULONG32 uint32 113 ULONG64 uint64 114 USHORT uint16 115 USN LONGLONG 116 VOID void 117 WORD uint16 118 WPARAM UINT_PTR 119 120 ); 121 122 if($Config{ptrsize} == 4) 123 { 124 $win32_map{HALF_PTR} = 'sint16'; 125 $win32_map{INT_PTR} = 'sint32'; 126 $win32_map{LONG_PTR} = 'sint16'; 127 $win32_map{UHALF_PTR} = 'uint16'; 128 $win32_map{UINT_PTR} = 'uint32'; 129 $win32_map{ULONG_PTR} = 'uint16'; 130 } 131 elsif($Config{ptrsize} == 8) 132 { 133 $win32_map{HALF_PTR} = 'sint16'; 134 $win32_map{INT_PTR} = 'sint32'; 135 $win32_map{LONG_PTR} = 'sint16'; 136 $win32_map{UHALF_PTR} = 'uint16'; 137 $win32_map{UINT_PTR} = 'uint32'; 138 $win32_map{ULONG_PTR} = 'uint16'; 139 } 140 else 141 { 142 die "interesting word size you have"; 143 } 144 145 foreach my $alias (keys %win32_map) 146 { 147 my $type = $alias; 148 while(1) 149 { 150 if($type =~ /^(opaque|[us]int(8|16|32|64)|float|double|string|void)$/) 151 { 152 $map{$alias} = $type; 153 last; 154 } 155 if(defined $map{$type}) 156 { 157 $map{$alias} = $map{$type}; 158 last; 159 } 160 if(defined $win32_map{$type}) 161 { 162 $type = $win32_map{$type}; 163 next; 164 } 165 die "unable to resolve $alias => ... => $type"; 166 } 167 } 168 169 # stuff we are not yet dealing with 170 # LPCTSTR is unicode string, not currently supported 171 # LPWSTR 16 bit unicode string 172 # TBYTE TCHAR UNICODE_STRING WCHAR 173 # Not supported: POINTER_32 POINTER_64 POINTER_SIGNED POINTER_UNSIGNED 174 } 175 \%map; 176} 177 178 179sub load_custom_types 180{ 181 my(undef, $ffi) = @_; 182 $ffi->load_custom_type('::WideString' => 'LPCWSTR', access => 'read' ); 183 $ffi->load_custom_type('::WideString' => 'LPWSTR', access => 'write' ); 184} 185 1861; 187 188__END__ 189 190=pod 191 192=encoding UTF-8 193 194=head1 NAME 195 196FFI::Platypus::Lang::Win32 - Documentation and tools for using Platypus with the Windows API 197 198=head1 VERSION 199 200version 1.56 201 202=head1 SYNOPSIS 203 204 use utf8; 205 use FFI::Platypus 1.35; 206 207 my $ffi = FFI::Platypus->new( 208 api => 1, 209 lib => [undef], 210 ); 211 212 # load this plugin 213 $ffi->lang('Win32'); 214 215 # Pass two double word integer values to the Windows API Beep function. 216 $ffi->attach( Beep => ['DWORD','DWORD'] => 'BOOL'); 217 Beep(262, 300); 218 219 # Send a Unicode string to the Windows API MessageBoxW function. 220 use constant MB_OK => 0x00000000; 221 use constant MB_DEFAULT_DESKTOP_ONLY => 0x00020000; 222 $ffi->attach( [MessageBoxW => 'MessageBox'] => [ 'HWND', 'LPCWSTR', 'LPCWSTR', 'UINT'] => 'int' ); 223 MessageBox(undef, "I ❤️ Platypus", "Confession", MB_OK|MB_DEFAULT_DESKTOP_ONLY); 224 225 # Get a Unicode string from the Windows API GetCurrentDirectoryW function. 226 $ffi->attach( [GetCurrentDirectoryW => 'GetCurrentDirectory'] => ['DWORD', 'LPWSTR'] => 'DWORD'); 227 my $buf_size = GetCurrentDirectory(0,undef); 228 my $dir = "\0\0" x $buf_size; 229 GetCurrentDirectory($buf_size, \$dir) or die $^E; 230 print "$dir\n"; 231 232=head1 DESCRIPTION 233 234This module provides the Windows datatypes used by the Windows API. 235This means that you can use things like C<DWORD> as an alias for 236C<uint32>. The full list of type aliases is not documented here as 237it may change over time or be dynamic. You can get the list for your 238current environment with this one-liner: 239 240 perl -MFFI::Platypus::Lang::Win32 -E "say for sort keys %{ FFI::Platypus::Lang::Win32->native_type_map }" 241 242This plugin will also set the correct ABI for use with Win32 API 243functions. (On 32 bit systems a different ABI is used for Win32 API 244than what is used by the C library, on 32 bit systems the same ABI 245is used). Most of the time this exactly what you want, but if you 246need to use functions that are using the standard C calling convention, 247but need the Win32 types, you can do that by setting the ABI back 248immediately after loading the language plugin: 249 250 $ffi->lang('Win32'); 251 $ffi->abi('default_abi'); 252 253Most of the types should be pretty self-explanatory or at least provided 254in the Microsoft documentation on the internet, but the use of Unicode 255strings probably requires some more detail: 256 257[version 1.35] 258 259This plugin also provides C<LPCWSTR> and C<LPWSTR> "wide" string types 260which are implemented using L<FFI::Platypus::Type::WideString>. For 261full details, please see the documentation for that module, and note 262that C<LPCWSTR> is a wide string in the read-only string mode and 263C<LPWSTR> is a wide string in the read-write buffer mode. 264 265The C<LPCWSTR> is handled fairly transparently by the plugin, but for 266when using read-write buffers (C<LPWSTR>) with the Win32 API you typically 267need to allocate a buffer string of the right size. These examples will 268use C<GetCurrentDirectoryW> attached as C<GetCurrentDirectory> 269as in the synopsis above. These are illustrative only, you would normally 270want to use the L<Cwd> module to get the current working directory. 271 272=over 4 273 274=item default buffer size 2048 275 276The simplest way is to fallback on the rather arbitrary default buffer size of 2048. 277 278 my $dir; 279 GetCurrentDirectory(1024, \$dir); 280 print "I am in the directory: $dir\n"; 281 282B<Discussion>: This only works if you know the API that you are using will not ever use 283more than 2048 bytes. The author believes this to be the case for C<GetCurrentDirectoryW> 284since directory paths in windows have a maximum of 260 characters. If every character was 285outside the Basic Multilingual Plane (BMP) they would take up exactly 4 characters each. 286(This is probably not ever the case since the disk volume at least will be a Latin letter). 287Taking account of the C<NULL> termination you would need 260 * 4 + 2 bytes or 1048 bytes. 288 289We pass in a reference to our scalar so that the Win32 API can write into it. 290 291We are passing in half the number of bytes as the first argument because the API expects 292the number of C<WCHAR> (or C<wchar_t>), not the number of bytes or the technically the 293number of characters since characters can take up either 2 or 4 bytes in UTF-16. 294 295=item allocate your buffer to your own size. 296 297If possible it is of course always best to allocate exactly the size of buffer that 298you need. 299 300 my $size = GetCurrentDirectory(0, undef); 301 my $dir = "\0\0" x $size; 302 GetCurrentDirectory($size, \$dir); 303 print "I am in the directory: $dir\n"; 304 305B<Discussion>: In this case the API provides a way of getting the exact size of buffer 306that you need. We allocate this in Perl by creating a string of C<NULLs> of the right 307length. The Perl string C<"\0"> is exactly on byte, so we double that before using the 308C<x> operator to multiple that by the size returned by the API. 309 310Now, somewhat unexpectedly what is returned is not the same buffer, but a new string 311in new UTF-8 encoded Perl string. This is what you want most of the time. 312 313=item initialize your read-write buffer 314 315Some APIs might be modifying an existing string rather than just writing an entirely 316new one. In that case you still want to allocate a buffer, but you want to initialize 317it with a value. You can do this by passing an array reference instead of a scalar 318reference. The firs element of the array is the buffer, and the second is the initialization. 319 320 my $dir; 321 GetCurrentDirectory($size, [ \$dir, "I ❤ Perl + Platypus" ]); 322 323B<Discussion>: Note that this particular API ignores the string passed in and writes 324over it, but this demonstrates how you would initialize a buffer string. Once again, 325if C<$dir> is not initialized (is C<undef>), then a buffer of the default size of 2048 326bytes will be created internally. You can also allocate a specific number of bytes 327as in the previous example. 328 329=item allocate memory using C<malloc> etc. 330 331You can also allocate memory using C<malloc> (see L<FFI::Platypus::Memory>) and encode 332your string using L<Encode> and copy it using C<wcscpy>. This may be appropriate in 333some cases, but it is beyond the scope of this document. 334 335=back 336 337=head1 METHODS 338 339=head2 abi 340 341 my $abi = FFI::Platypus::Lang::Win32->abi; 342 343This is called internally when the type plugin is loaded by Platypus. 344It selects the appropriate ABI to make Win32 API function calls. 345 346=head2 native_type_map 347 348 my $hashref = FFI::Platypus::Lang::Win32->native_type_map; 349 350This is called internally when the type plugin is loaded by Platypus. 351It provides types aliases useful on the Windows platform, so it may 352also be useful for introspection. 353 354This returns a hash reference containing the native aliases for the 355Windows API. That is the keys are native Windows API C types and the 356values are libffi native types. 357 358This will includes types like C<DWORD> and C<HWND>, and others. The 359full list may be adjusted over time and may be computed dynamically. 360To get the full list for your install you can use this one-liner: 361 362 perl -MFFI::Platypus::Lang::Win32 -E "say for sort keys %{ FFI::Platypus::Lang::Win32->native_type_map }" 363 364=head2 load_custom_types 365 366 FFI::Platypus::Lang::Win32->load_custom_types($ffi); 367 368This is called internally when the type plugin is loaded by Platypus. 369It provides custom types useful on the Windows platform. For now 370that means the C<LPWSTR> and C<LPCWSTR> types. 371 372=head1 CAVEATS 373 374The Win32 API isn't a different computer language in the same sense that the 375other language plugins (those for Fortran or Rust for example). But implementing 376these types as a language plugin is the most convenient way to do it. 377 378Prior to version 1.35, this plugin didn't provide an implementation for 379C<LPWSTR> or C<LPCWSTR>, so in the likely event that you need those types make 380sure you also require at least that version of Platypus. 381 382=head1 SEE ALSO 383 384=over 4 385 386=item L<FFI::Platypus> 387 388The Core Platypus documentation. 389 390=item L<FFI::Platypus::Lang> 391 392Includes a list of other language plugins for Platypus. 393 394=item L<FFI::Platypus::Type::WideString> 395 396The wide string type plugin use for C<LPWSTR> and C<LPCWSTR> types. 397 398=item L<Win32::API> 399 400Another FFI, but for Windows only. 401 402=back 403 404=head1 AUTHOR 405 406Author: Graham Ollis E<lt>plicease@cpan.orgE<gt> 407 408Contributors: 409 410Bakkiaraj Murugesan (bakkiaraj) 411 412Dylan Cali (calid) 413 414pipcet 415 416Zaki Mughal (zmughal) 417 418Fitz Elliott (felliott) 419 420Vickenty Fesunov (vyf) 421 422Gregor Herrmann (gregoa) 423 424Shlomi Fish (shlomif) 425 426Damyan Ivanov 427 428Ilya Pavlov (Ilya33) 429 430Petr Písař (ppisar) 431 432Mohammad S Anwar (MANWAR) 433 434Håkon Hægland (hakonhagland, HAKONH) 435 436Meredith (merrilymeredith, MHOWARD) 437 438Diab Jerius (DJERIUS) 439 440Eric Brine (IKEGAMI) 441 442szTheory 443 444José Joaquín Atria (JJATRIA) 445 446Pete Houston (openstrike, HOUSTON) 447 448=head1 COPYRIGHT AND LICENSE 449 450This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis. 451 452This is free software; you can redistribute it and/or modify it under 453the same terms as the Perl 5 programming language system itself. 454 455=cut 456