E-MailRelay
gnowide.h
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2024 Graeme Walker <graeme_walker@users.sourceforge.net>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16// ===
17///
18/// \file gnowide.h
19///
20/// Contains inline functions that convert to and from UTF-8
21/// strings in order to call wide-character "W()" or "_w()"
22/// Windows functions internally.
23///
24/// This means that in the rest of the code filesystem paths,
25/// registry paths, environment variables, command-lines etc.
26/// can be always UTF-8, independent of the o/s, current locale
27/// or codepage.
28///
29/// For temporary backwards compatibility, if G_ANSI is
30/// undefined then the "A()" API functions are used with no
31/// UTF-8 conversions.
32///
33/// \see http://utf8everywhere.org
34///
35
36#ifndef G_NOWIDE_H
37#define G_NOWIDE_H
38
39#ifdef G_WINDOWS
40
41#include "gdef.h"
42#include "gpath.h"
43#include "gstringview.h"
44#include "gcodepage.h"
45#include "gconvert.h"
46#include <vector>
47#include <string>
48#include <algorithm>
49#include <cstdio> // std::remove()
50#include <sddl.h>
51#include <io.h>
52#include <fcntl.h>
53#include <stdlib.h>
54#include <prsht.h>
55#include <shlwapi.h>
56#include <shlobj.h>
57#include <string.h> // ::strdup()
58
59namespace G
60{
61 namespace nowide
62 {
63 #ifdef G_ANSI
64 // (G_ANSI is deprecated)
65 static constexpr bool w = false ;
66 using FIND_DATA_type = WIN32_FIND_DATAA ;
67 using WNDCLASS_type = WNDCLASSA ;
68 using PROPSHEETPAGE_type = PROPSHEETPAGEA ;
69 using PROPSHEETHEADER_type = PROPSHEETHEADERA ;
70 using NOTIFYICONDATA_type = NOTIFYICONDATAA ;
71 #if GCONFIG_HAVE_WINDOWS_STARTUP_INFO_EX
72 using STARTUPINFO_BASE_type = STARTUPINFOA ;
73 using STARTUPINFO_REAL_type = STARTUPINFOEXA ;
74 constexpr DWORD STARTUPINFO_flags = EXTENDED_STARTUPINFO_PRESENT ;
75 #else
76 using STARTUPINFO_BASE_type = STARTUPINFOA ;
77 using STARTUPINFO_REAL_type = STARTUPINFOA ;
78 constexpr DWORD STARTUPINFO_flags = 0 ;
79 #endif
80 using IShellLink_type = IShellLinkA ;
81 using ADDRINFO_type = ADDRINFOW ;
82 #else
83 static constexpr bool w = true ;
84 using FIND_DATA_type = WIN32_FIND_DATAW ;
85 using WNDCLASS_type = WNDCLASSW ;
86 using PROPSHEETPAGE_type = PROPSHEETPAGEW ;
87 using PROPSHEETHEADER_type = PROPSHEETHEADERW ;
88 using NOTIFYICONDATA_type = NOTIFYICONDATAW ;
89 #if GCONFIG_HAVE_WINDOWS_STARTUP_INFO_EX
90 using STARTUPINFO_BASE_type = STARTUPINFOW ;
91 using STARTUPINFO_REAL_type = STARTUPINFOEXW ;
92 constexpr DWORD STARTUPINFO_flags = EXTENDED_STARTUPINFO_PRESENT ;
93 #else
94 using STARTUPINFO_BASE_type = STARTUPINFOW ;
95 using STARTUPINFO_REAL_type = STARTUPINFOW ;
96 constexpr DWORD STARTUPINFO_flags = 0 ;
97 #endif
98 using IShellLink_type = IShellLinkW ;
99 using ADDRINFO_type = ADDRINFOA ;
100 #endif
101
102 inline std::string getCommandLine()
103 {
104 if( w )
105 return Convert::narrow( GetCommandLineW() ) ;
106 else
107 return std::string( GetCommandLineA() ) ;
108 }
109 inline DWORD getFileAttributes( const Path & path )
110 {
111 if( w )
112 return GetFileAttributesW( Convert::widen(path.str()).c_str() ) ;
113 else
114 return GetFileAttributesA( path.cstr() ) ;
115 }
116 inline HANDLE findFirstFile( const Path & path , WIN32_FIND_DATAW * find_data_p )
117 {
118 return FindFirstFileW( Convert::widen(path.str()).c_str() , find_data_p ) ;
119 }
120 inline HANDLE findFirstFile( const Path & path , WIN32_FIND_DATAA * find_data_p )
121 {
122 return FindFirstFileA( path.cstr() , find_data_p ) ;
123 }
124 inline BOOL findNextFile( HANDLE h , WIN32_FIND_DATAW * find_data_p )
125 {
126 return FindNextFileW( h , find_data_p ) ;
127 }
128 inline BOOL findNextFile( HANDLE h , WIN32_FIND_DATAA * find_data_p )
129 {
130 return FindNextFileA( h , find_data_p ) ;
131 }
132 inline std::string cFileName( const WIN32_FIND_DATAW & find_data )
133 {
134 return Convert::narrow( find_data.cFileName ) ;
135 }
136 inline std::string cFileName( const WIN32_FIND_DATAA & find_data )
137 {
138 return std::string( find_data.cFileName ) ;
139 }
140 template <typename T>
141 void open( T & io , const Path & path , std::ios_base::openmode mode )
142 {
143 #if GCONFIG_HAVE_EXTENDED_OPEN
144 // msvc and _wfsopen() :-)
145 if( w )
146 io.open( Convert::widen(path.str()).c_str() , mode , _SH_DENYNO ) ;
147 else
148 io.open( path.str() , mode , _SH_DENYNO ) ;
149 #else
150 // mingw :-(
151 if( w )
152 io.open( Convert::widen(path.str()).c_str() , mode ) ;
153 else
154 io.open( path.str() , mode ) ;
155 #endif
156 }
157 inline int open( const Path & path , int flags , int pmode , bool inherit = false )
158 {
159 if( !inherit )
160 flags |= _O_NOINHERIT ;
161 _set_errno( 0 ) ; // mingw bug
162 int fd = -1 ;
163 if( w )
164 {
165 #if GCONFIG_HAVE_WSOPEN_S
166 return 0 == _wsopen_s( &fd , Convert::widen(path.str()).c_str() , flags , _SH_DENYNO , pmode ) ? fd : -1 ;
167 #else
168 return _wopen( Convert::widen(path.str()).c_str() , flags , pmode ) ;
169 #endif
170 }
171 else
172 {
173 return 0 == _sopen_s( &fd , path.cstr() , flags , _SH_DENYNO , pmode ) ? fd : -1 ;
174 }
175 }
176 inline std::FILE * fopen( const Path & path , const char * mode )
177 {
178 if( w )
179 return _wfsopen( Convert::widen(path.str()).c_str() , Convert::widen(mode).c_str() , _SH_DENYNO ) ;
180 else
181 return _fsopen( path.cstr() , mode , _SH_DENYNO ) ;
182 }
183 inline bool rename( const Path & from , const Path & to )
184 {
185 if( w )
186 return 0 == _wrename( Convert::widen(from.str()).c_str() , Convert::widen(to.str()).c_str() ) ;
187 else
188 return 0 == std::rename( from.cstr() , to.cstr() ) ;
189 }
190 inline bool remove( const Path & path )
191 {
192 if( w )
193 return 0 == _wremove( Convert::widen(path.str()).c_str() ) ;
194 else
195 return 0 == std::remove( path.cstr() ) ;
196 }
197 inline bool rmdir( const Path & path )
198 {
199 if( w )
200 return 0 == _wrmdir( Convert::widen(path.str()).c_str() ) ;
201 else
202 return 0 == _rmdir( path.cstr() ) ;
203 }
204 inline int mkdir( const Path & dir )
205 {
206 if( w )
207 return _wmkdir( Convert::widen(dir.str()).c_str() ) ;
208 else
209 return _mkdir( dir.cstr() ) ;
210 }
211 typedef struct _stat64 statbuf_type ;
212 inline int stat( const Path & path , statbuf_type * statbuf_p )
213 {
214 if( w )
215 return _wstat64( Convert::widen(path.str()).c_str() , statbuf_p ) ;
216 else
217 return _stat64( path.cstr() , statbuf_p ) ;
218 }
219 inline std::string getComputerNameEx( COMPUTER_NAME_FORMAT name_type = ComputerNameNetBIOS )
220 {
221 if( w )
222 {
223 DWORD size = 0 ;
224 std::vector<wchar_t> buffer ;
225 if( !GetComputerNameExW( name_type , NULL , &size ) && GetLastError() == ERROR_MORE_DATA && size )
226 buffer.resize( static_cast<std::size_t>(size) ) ;
227 else
228 return {} ;
229 if( !GetComputerNameExW( name_type , buffer.data() , &size ) ||
230 (static_cast<std::size_t>(size)+1U) != buffer.size() )
231 return {} ;
232 return Convert::narrow( buffer.data() , buffer.size()-1U ) ;
233 }
234 else
235 {
236 DWORD size = 0 ;
237 std::vector<char> buffer ;
238 if( !GetComputerNameExA( name_type , NULL , &size ) && GetLastError() == ERROR_MORE_DATA && size )
239 buffer.resize( static_cast<std::size_t>(size) ) ;
240 else
241 return {} ;
242 if( !GetComputerNameExA( name_type , buffer.data() , &size ) ||
243 (static_cast<std::size_t>(size)+1U) != buffer.size() )
244 return {} ;
245 return std::string( buffer.data() , buffer.size()-1U ) ;
246 }
247 }
248 inline BOOL lookupAccountName( const std::string & full_name , char * sid_buffer , DWORD * sidsize_p ,
249 bool with_domain , DWORD * domainsize_p , SID_NAME_USE * type_p )
250 {
251 if( w )
252 {
253 std::vector<wchar_t> domainbuffer( std::max(DWORD(1),*domainsize_p) ) ;
254 return LookupAccountNameW( NULL , Convert::widen(full_name).c_str() , sid_buffer , sidsize_p ,
255 with_domain ? domainbuffer.data() : nullptr , domainsize_p , type_p ) ;
256 }
257 else
258 {
259 std::vector<char> domainbuffer( std::max(DWORD(1),*domainsize_p) ) ;
260 return LookupAccountNameA( NULL , full_name.c_str() , sid_buffer , sidsize_p ,
261 with_domain ? domainbuffer.data() : nullptr , domainsize_p , type_p ) ;
262 }
263 }
264 inline BOOL lookupAccountSid( PSID sid , std::string * name_out_p ,
265 bool with_name , DWORD * namesize_p ,
266 bool with_domain , DWORD * domainsize_p , SID_NAME_USE * type_p )
267 {
268 if( w )
269 {
270 std::vector<wchar_t> namebuffer( std::max(DWORD(1),*namesize_p) ) ;
271 std::vector<wchar_t> domainbuffer( std::max(DWORD(1),*domainsize_p) ) ;
272 BOOL rc = LookupAccountSidW( NULL , sid ,
273 with_name ? namebuffer.data() : nullptr , namesize_p ,
274 with_domain ? domainbuffer.data() : nullptr , domainsize_p ,
275 type_p ) ;
276 if( with_name && name_out_p )
277 *name_out_p = Convert::narrow( namebuffer.data() , namebuffer.size() ) ;
278 return rc ;
279 }
280 else
281 {
282 std::vector<char> namebuffer( std::max(DWORD(1),*namesize_p) ) ;
283 std::vector<char> domainbuffer( std::max(DWORD(1),*domainsize_p) ) ;
284 BOOL rc = LookupAccountSidA( NULL , sid ,
285 with_name ? namebuffer.data() : nullptr , namesize_p ,
286 with_domain ? domainbuffer.data() : nullptr , domainsize_p ,
287 type_p ) ;
288 if( with_name && name_out_p )
289 *name_out_p = std::string( namebuffer.data() , namebuffer.size() ) ;
290 return rc ;
291 }
292 }
293 inline std::string convertSidToStringSid( PSID sid_p )
294 {
295 if( w )
296 {
297 wchar_t * str_p = nullptr ;
298 if( !ConvertSidToStringSidW( sid_p , &str_p ) || str_p == nullptr )
299 return {} ;
300 std::wstring s( str_p ) ;
301 LocalFree( str_p ) ;
302 return Convert::narrow( s ) ;
303 }
304 else
305 {
306 char * str_p = nullptr ;
307 if( !ConvertSidToStringSidA( sid_p , &str_p ) || str_p == nullptr )
308 return {} ;
309 std::string s( str_p ) ;
310 LocalFree( str_p ) ;
311 return s ;
312 }
313 }
314 inline unsigned int getTextMetricsHeight( HDC hdc ) noexcept
315 {
316 if( w )
317 {
318 TEXTMETRICW tm ;
319 GetTextMetricsW( hdc , &tm ) ;
320 return static_cast<unsigned int>( tm.tmHeight + tm.tmExternalLeading ) ;
321 }
322 else
323 {
324 TEXTMETRICA tm ;
325 GetTextMetricsA( hdc , &tm ) ;
326 return static_cast<unsigned int>( tm.tmHeight + tm.tmExternalLeading ) ;
327 }
328 }
329 inline HPROPSHEETPAGE createPropertySheetPage( PROPSHEETPAGEW * page , const std::string & title , int dialog_id )
330 {
331 std::wstring wtitle = G::Convert::widen( title ) ;
332 page->pszTitle = wtitle.c_str() ;
333 page->pszTemplate = dialog_id ? MAKEINTRESOURCEW(dialog_id) : 0 ;
334 return CreatePropertySheetPageW( page ) ;
335 }
336 inline HPROPSHEETPAGE createPropertySheetPage( PROPSHEETPAGEA * page , const std::string & title , int dialog_id ) noexcept
337 {
338 page->pszTitle = title.c_str() ;
339 page->pszTemplate = dialog_id ? MAKEINTRESOURCEA(dialog_id) : 0 ;
340 return CreatePropertySheetPageA( page ) ;
341 }
342 inline INT_PTR propertySheet( PROPSHEETHEADERW * header , const std::string & title , int icon_id )
343 {
344 std::wstring wtitle = G::Convert::widen( title ) ;
345 header->pszIcon = icon_id ? MAKEINTRESOURCEW(icon_id) : 0 ;
346 header->pszCaption = wtitle.c_str() ;
347 return PropertySheetW( header ) ;
348 }
349 inline INT_PTR propertySheet( PROPSHEETHEADERA * header , const std::string & title , int icon_id ) noexcept
350 {
351 header->pszIcon = icon_id ? MAKEINTRESOURCEA(icon_id) : 0 ;
352 header->pszCaption = title.c_str() ;
353 return PropertySheetA( header ) ;
354 }
355 inline void reportEvent( HANDLE h , DWORD id , WORD type , const char * message )
356 {
357 if( w )
358 {
359 std::wstring wmessage = Convert::widen( message ) ;
360 const wchar_t * p [] = { wmessage.c_str() , nullptr } ;
361 ReportEventW( h , type , 0 , id , nullptr , 1 , 0 , p , nullptr ) ;
362 }
363 else
364 {
365 const char * p [] = { message , nullptr } ;
366 ReportEventA( h , type , 0 , id , nullptr , 1 , 0 , p , nullptr ) ;
367 }
368 }
369 inline HANDLE registerEventSource( const std::string & name )
370 {
371 if( w )
372 return RegisterEventSourceW( nullptr , Convert::widen(name).c_str() ) ;
373 else
374 return RegisterEventSourceA( nullptr , name.c_str() ) ;
375 }
376 inline LSTATUS regCreateKey( const Path & reg_path , HKEY * key_out_p ,
377 HKEY hkey_in = HKEY_LOCAL_MACHINE , bool * is_new_p = nullptr )
378 {
379 LSTATUS result = 0 ;
380 DWORD disposition = 0 ;
381 if( w )
382 result = RegCreateKeyExW( hkey_in , Convert::widen(reg_path.str()).c_str() ,
383 0 , NULL , 0 , KEY_ALL_ACCESS , NULL , key_out_p , &disposition ) ;
384 else
385 result = RegCreateKeyExA( hkey_in , reg_path.cstr() ,
386 0 , NULL , 0 , KEY_ALL_ACCESS , NULL , key_out_p , &disposition ) ;
387 if( is_new_p )
388 *is_new_p = disposition == REG_CREATED_NEW_KEY ;
389 return result ;
390 }
391 inline LSTATUS regOpenKey( HKEY key_in , const Path & sub , HKEY * key_out_p , bool read_only = false )
392 {
393 REGSAM access = read_only ? (STANDARD_RIGHTS_READ|KEY_QUERY_VALUE) : KEY_ALL_ACCESS ;
394 if( w )
395 return RegOpenKeyExW( key_in , Convert::widen(sub.str()).c_str() ,
396 0 , access , key_out_p ) ;
397 else
398 return RegOpenKeyExA( key_in , sub.cstr() ,
399 0 , access , key_out_p ) ;
400 }
401 inline LSTATUS regDeleteKey( HKEY key , const Path & sub )
402 {
403 if( w )
404 return RegDeleteKeyW( key , Convert::widen(sub.str()).c_str() ) ;
405 else
406 return RegDeleteKeyA( key , sub.cstr() ) ;
407 }
408 inline LSTATUS regQueryValueType( HKEY key , const Path & sub , DWORD * type_out_p , DWORD * size_out_p )
409 {
410 if( w )
411 return RegQueryValueExW( key , Convert::widen(sub.str()).c_str() ,
412 0 , type_out_p , nullptr , size_out_p ) ;
413 else
414 return RegQueryValueExA( key , sub.cstr() ,
415 0 , type_out_p , nullptr , size_out_p ) ;
416 }
417 inline LSTATUS regGetValueString( HKEY key , const Path & sub , std::string * value_out_p )
418 {
419 DWORD type = 0 ;
420 LSTATUS status = 0 ;
421 DWORD size = 0 ;
422 if( w )
423 status = RegQueryValueExW( key , Convert::widen(sub.str()).c_str() , 0 , &type , nullptr , &size ) ;
424 else
425 status = RegQueryValueExA( key , sub.cstr() , 0 , &type , nullptr , &size ) ;
426 if( type != REG_SZ )
427 return ERROR_INVALID_DATA ;
428 if( status != ERROR_SUCCESS )
429 return status ;
430 if( w )
431 {
432 std::vector<wchar_t> buffer( static_cast<std::size_t>(size)+1U , '\0' ) ;
433 status = RegQueryValueExW( key , Convert::widen(sub.str()).c_str() , 0 , &type ,
434 reinterpret_cast<BYTE*>(buffer.data()) , &size ) ;
435 if( status != ERROR_SUCCESS )
436 return status ;
437 buffer[std::min(buffer.size()-1U,static_cast<std::size_t>(size))] = L'\0' ;
438 *value_out_p = Convert::narrow( buffer.data() ) ;
439 }
440 else
441 {
442 std::vector<char> buffer( static_cast<std::size_t>(size)+1U , '\0' ) ;
443 status = RegQueryValueExA( key , sub.cstr() , 0 , &type ,
444 reinterpret_cast<BYTE*>(buffer.data()) , &size ) ;
445 if( status != ERROR_SUCCESS )
446 return status ;
447 buffer[std::min(buffer.size()-1U,static_cast<std::size_t>(size))] = '\0' ;
448 *value_out_p = std::string( buffer.data() ) ;
449 }
450 return status ;
451 }
452 inline LSTATUS regGetValueNumber( HKEY key , const Path & sub , DWORD * value_out_p )
453 {
454 DWORD type = 0 ;
455 LSTATUS status = 0 ;
456 DWORD size = 4 ;
457 if( w )
458 status = RegQueryValueExW( key , Convert::widen(sub.str()).c_str() , 0 ,
459 &type , reinterpret_cast<BYTE*>(value_out_p) , &size ) ;
460 else
461 status = RegQueryValueExA( key , sub.cstr() , 0 ,
462 &type , reinterpret_cast<BYTE*>(value_out_p) , &size ) ;
463 if( type != REG_DWORD || size < 4U )
464 return ERROR_INVALID_DATA ;
465 if( status != ERROR_SUCCESS )
466 return status ;
467 return status ;
468 }
469 inline LSTATUS regSetValue( HKEY key , const Path & sub , const std::string & s )
470 {
471 if( w )
472 {
473 std::wstring ws = Convert::widen( s ) ;
474 const BYTE * p = reinterpret_cast<const BYTE*>(ws.c_str()) ;
475 DWORD n = static_cast<DWORD>( (s.size()*2U)+1U ) ;
476 return RegSetValueExW( key , Convert::widen(sub.str()).c_str() , 0 , REG_SZ , p , n ) ;
477 }
478 else
479 {
480 DWORD n = static_cast<DWORD>( s.size()+1U ) ;
481 const BYTE * p = reinterpret_cast<const BYTE*>(s.c_str()) ;
482 return RegSetValueExA( key , sub.cstr() , 0 , REG_SZ , p , n ) ;
483 }
484 }
485 inline LSTATUS regSetValue( HKEY key , const Path & sub , DWORD n )
486 {
487 if( w )
488 return RegSetValueExW( key , Convert::widen(sub.str()).c_str() , 0 , REG_DWORD ,
489 reinterpret_cast<const BYTE*>(&n) , sizeof(DWORD) ) ;
490 else
491 return RegSetValueExA( key , sub.cstr() , 0 , REG_DWORD ,
492 reinterpret_cast<const BYTE*>(&n) , sizeof(DWORD) ) ;
493 }
494 inline BOOL createProcess( std::string_view exe , std::string_view command_line ,
495 const char * /*env_char_block_p*/ , const wchar_t * env_wchar_block_p ,
496 const Path * cd_path_p , DWORD startup_info_flags ,
497 STARTUPINFOW * startup_info , PROCESS_INFORMATION * info_ptr , bool inherit = true )
498 {
499 return CreateProcessW( exe.empty() ? nullptr : Convert::widen(exe).c_str() ,
500 const_cast<wchar_t*>(Convert::widen(command_line).c_str()) ,
501 nullptr , nullptr ,
502 inherit , startup_info_flags|CREATE_UNICODE_ENVIRONMENT ,
503 const_cast<wchar_t*>(env_wchar_block_p) ,
504 cd_path_p ? Convert::widen(cd_path_p->str()).c_str() : nullptr ,
505 startup_info , info_ptr ) ;
506 }
507 inline BOOL createProcess( const std::string & exe , const std::string & command_line ,
508 const char * env_char_block_p , const wchar_t * /*env_wchar_block_p*/ ,
509 const Path * cd_path_p , DWORD startup_info_flags ,
510 STARTUPINFOA * startup_info , PROCESS_INFORMATION * info_ptr , bool inherit = true )
511 {
512 return CreateProcessA( exe.empty() ? nullptr : exe.c_str() ,
513 const_cast<char*>(command_line.c_str()) ,
514 nullptr , nullptr ,
515 inherit , startup_info_flags ,
516 const_cast<char*>(env_char_block_p) ,
517 cd_path_p ? cd_path_p->cstr() : nullptr ,
518 startup_info , info_ptr ) ;
519 }
520 inline std::string windowsPath()
521 {
522 if( w )
523 {
524 std::vector<wchar_t> buffer( MAX_PATH+1 ) ;
525 buffer[0] = 0 ;
526 unsigned int n = GetWindowsDirectoryW( buffer.data() , MAX_PATH ) ;
527 if( n == 0 || n > MAX_PATH )
528 return {} ;
529 return Convert::narrow( buffer.data() , static_cast<std::size_t>(n) ) ;
530 }
531 else
532 {
533 std::vector<char> buffer( MAX_PATH+1 ) ;
534 buffer[0] = 0 ;
535 unsigned int n = GetWindowsDirectoryA( buffer.data() , MAX_PATH ) ;
536 if( n == 0 || n > MAX_PATH )
537 return {} ;
538 return std::string( buffer.data() , static_cast<std::size_t>(n) ) ;
539 }
540 }
541 inline std::string strerror( int errno_ )
542 {
543 if( w )
544 {
545 #if GCONFIG_HAVE_WCSERROR_S
546 std::vector<wchar_t> buffer( 80U , '\0' ) ;
547 if( _wcserror_s( buffer.data() , buffer.size()-1U , errno_ ) || buffer.at(0U) == L'\0' )
548 return std::string("unknown error (").append(std::to_string(errno_)).append(1U,')') ;
549 return Convert::narrow( buffer.data() ) ;
550 #else
551 std::vector<char> buffer( 80U , '\0' ) ;
552 if( strerror_s( buffer.data() , buffer.size()-1U , errno_ ) || buffer.at(0U) == '\0' )
553 return std::string("unknown error (").append(std::to_string(errno_)).append(1U,')') ;
554 return CodePage::fromCodePageAnsi( std::string(buffer.data()) ) ;
555 #endif
556 }
557 else
558 {
559 std::vector<char> buffer( 80U , '\0' ) ;
560 if( strerror_s( buffer.data() , buffer.size()-1U , errno_ ) || buffer.at(0U) == '\0' )
561 return std::string("unknown error (").append(std::to_string(errno_)).append(1U,')') ;
562 return {buffer.data()} ;
563 }
564 }
565 inline std::string formatMessage( DWORD e )
566 {
567 if( w )
568 {
569 wchar_t * ptr = nullptr ;
570 FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER |
571 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS ,
572 NULL , e , MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT) ,
573 reinterpret_cast<wchar_t*>(&ptr) , 1 , NULL ) ;
574 std::string result = ptr ? Convert::narrow(ptr) : std::string() ;
575 if( ptr ) LocalFree( ptr ) ;
576 return result ;
577 }
578 else
579 {
580 char * ptr = nullptr ;
581 FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER |
582 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS ,
583 NULL , e , MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT) ,
584 reinterpret_cast<char*>(&ptr) , 1 , NULL ) ;
585 std::string result = ptr ? std::string(ptr) : std::string() ;
586 if( ptr ) LocalFree( ptr ) ;
587 return result ;
588 }
589 }
590 inline G::Path exe()
591 {
592 if( w )
593 {
594 std::vector<wchar_t> buffer ;
595 std::size_t sizes[] = { 80U , 1024U , 32768U , 0U } ; // documented limit of 32k
596 for( std::size_t * size_p = sizes ; *size_p ; ++size_p )
597 {
598 buffer.resize( *size_p+1U , '\0' ) ;
599 DWORD buffer_size = static_cast<DWORD>( buffer.size() ) ;
600 DWORD rc = GetModuleFileNameW( HNULL , buffer.data() , buffer_size ) ;
601 if( rc == 0 ) break ;
602 if( rc < buffer_size )
603 return {Convert::narrow( std::wstring(buffer.data(),static_cast<std::size_t>(rc)) )} ;
604 }
605 return {} ;
606 }
607 else
608 {
609 std::vector<char> buffer ;
610 std::size_t sizes[] = { 80U , 1024U , 32768U , 0U } ; // documented limit of 32k
611 for( std::size_t * size_p = sizes ; *size_p ; ++size_p )
612 {
613 buffer.resize( *size_p+1U , '\0' ) ;
614 DWORD buffer_size = static_cast<DWORD>( buffer.size() ) ;
615 DWORD rc = GetModuleFileNameA( HNULL , buffer.data() , buffer_size ) ;
616 if( rc == 0 ) break ;
617 if( rc < buffer_size )
618 return {std::string_view( buffer.data() , static_cast<std::size_t>(rc) )} ;
619 }
620 return {} ;
621 }
622 }
623 inline G::Path cwd()
624 {
625 if( w )
626 {
627 wchar_t * p = _wgetcwd( nullptr , 2048 ) ; // "a buffer of at least .. is .. allocated" "more only if necessary"
628 if( p == nullptr )
629 return {} ;
630 Path result( Convert::narrow(std::wstring(p)) ) ;
631 std::free( p ) ;
632 return result ;
633 }
634 else
635 {
636 char * p = _getcwd( nullptr , 2048 ) ; // "a buffer of at least .. is .. allocated" "more only if necessary"
637 if( p == nullptr )
638 return {} ;
639 Path result( (std::string_view(p)) ) ;
640 std::free( p ) ;
641 return result ;
642 }
643 }
644 inline std::string getenv( const std::string & name , const std::string & default_ )
645 {
646 if( w )
647 {
648 #if GCONFIG_HAVE_WGETENV_S
649 std::size_t n = 0U ;
650 _wgetenv_s( &n , nullptr , 0U , Convert::widen(name).c_str() ) ;
651 if( n == 0U ) return default_ ; // ignore rc
652 std::vector<wchar_t> buffer( n ) ;
653 auto rc = _wgetenv_s( &n , buffer.data() , buffer.size() , Convert::widen(name).c_str() ) ;
654 if( rc != 0 || n != buffer.size() ) return default_ ;
655 return Convert::narrow( buffer.data() , buffer.size()-1U ) ;
656 #else
657 const wchar_t * p = _wgetenv( Convert::widen(name).c_str() ) ;
658 if( p == nullptr ) return default_ ;
659 return Convert::narrow( p , wcslen(p) ) ;
660 #endif
661 }
662 else
663 {
664 #if GCONFIG_HAVE_GETENV_S
665 std::size_t n = 0U ;
666 getenv_s( &n , nullptr , 0U , name.c_str() ) ;
667 if( n == 0U ) return default_ ; // ignore rc
668 std::vector<char> buffer( n ) ;
669 auto rc = getenv_s( &n , buffer.data() , buffer.size() , name.c_str() ) ;
670 if( rc != 0 || n != buffer.size() ) return default_ ;
671 return { buffer.data() , buffer.size()-1U } ;
672 #else
673 const char * p = ::getenv( name.c_str() ) ;
674 if( p == nullptr ) return default_ ;
675 return {p} ;
676 #endif
677 }
678 }
679 inline errno_t putenv( const std::string & key , const std::string & value )
680 {
681 if( w )
682 {
683 #if GCONFIG_HAVE_WPUTENV_S
684 return _wputenv_s( Convert::widen(key).c_str() , Convert::widen(value).c_str() ) ;
685 #else
686 std::string s = CodePage::toCodePageAnsi( std::string(key).append(1U,'=').append(value) ) ;
687 GDEF_WARNING_DISABLE_START( 4996 )
688 _putenv( strdup(s.c_str()) ) ; // deliberate leak
689 GDEF_WARNING_DISABLE_END
690 return 0 ;
691 #endif
692 }
693 else
694 {
695 return _putenv_s( key.c_str() , value.c_str() ) ;
696 }
697 }
698 inline bool messageBox( HWND hparent , const std::string & message , const std::string & title , DWORD type )
699 {
700 if( w )
701 {
702 auto rc = MessageBoxW( hparent , Convert::widen(message).c_str() , Convert::widen(title).c_str() , type ) ;
703 return rc == IDOK || rc == IDYES ;
704 }
705 else
706 {
707 auto rc = MessageBoxA( hparent , message.c_str() , title.c_str() , type ) ;
708 return rc == IDOK || rc == IDYES ;
709 }
710 }
711 inline bool setWindowText( HWND hwnd , const std::string & text )
712 {
713 if( w )
714 return SetWindowTextW( hwnd , Convert::widen(text).c_str() ) ;
715 else
716 return SetWindowTextA( hwnd , text.c_str() ) ;
717 }
718 inline std::string getWindowText( HWND hwnd )
719 {
720 if( w )
721 {
722 int length = GetWindowTextLengthW( hwnd ) ;
723 if( length <= 0 ) return {} ;
724 std::vector<wchar_t> buffer( static_cast<std::size_t>(length)+2U ) ;
725 GetWindowTextW( hwnd , buffer.data() , length+1 ) ;
726 buffer[buffer.size()-1U] = L'\0' ;
727 return Convert::narrow( buffer.data() ) ;
728 }
729 else
730 {
731 int length = GetWindowTextLengthA( hwnd ) ;
732 if( length <= 0 ) return {} ;
733 std::vector<char> buffer( static_cast<std::size_t>(length)+2U ) ;
734 GetWindowTextA( hwnd , buffer.data() , length+1 ) ;
735 buffer[buffer.size()-1U] = '\0' ;
736 return {buffer.data()} ;
737 }
738 }
739 inline int getWindowTextLength( HWND hwnd ) noexcept
740 {
741 if( w )
742 return GetWindowTextLengthW( hwnd ) ;
743 else
744 return GetWindowTextLengthA( hwnd ) ;
745 }
746 inline HICON loadIcon( HINSTANCE hinstance , unsigned int icon_id ) noexcept
747 {
748 if( w )
749 return LoadIconW( hinstance , MAKEINTRESOURCEW(icon_id) ) ;
750 else
751 return LoadIconA( hinstance , MAKEINTRESOURCEA(icon_id) ) ;
752 }
753 inline HICON loadIconApplication() noexcept
754 {
755 // IDI_APPLICATION uses MAKEINTRESOURCE, which depends on
756 // _UNICODE, so use the default definitions for both
757 // IDI_APPLICATION and LoadIcon() -- it doesn't matter
758 // whether that's A() or W() in practice, as long as they match
759 return LoadIcon( HNULL , IDI_APPLICATION ) ; // not A() or W()
760 }
761 inline HCURSOR loadCursor( HINSTANCE hinstance , int resource_id ) noexcept
762 {
763 if( w )
764 return LoadCursorW( hinstance , MAKEINTRESOURCEW(resource_id) ) ;
765 else
766 return LoadCursorA( hinstance , MAKEINTRESOURCEA(resource_id) ) ;
767 }
768 inline HCURSOR loadCursorArrow() noexcept
769 {
770 return LoadCursor( HNULL , IDC_ARROW ) ; // not A() or W(), as above
771 }
772 inline HCURSOR loadCursorWait() noexcept
773 {
774 return LoadCursor( HNULL , IDC_WAIT ) ; // not A() or W(), as above
775 }
776 inline int shellNotifyIcon( HINSTANCE hinstance , DWORD , NOTIFYICONDATAW * data ,
777 unsigned int icon_id , std::string_view tip )
778 {
779 // (modifies the caller's structure)
780 data->hIcon = LoadIconW( hinstance , MAKEINTRESOURCEW(icon_id) ) ;
781 if( data->hIcon == HNULL ) return 2 ;
782
783 std::wstring wtip = Convert::widen( tip ) ;
784 constexpr std::size_t n = sizeof(data->szTip) / sizeof(data->szTip[0]) ;
785 static_assert( n > 0U , "" ) ;
786 for( std::size_t i = 0U ; i < n ; i++ )
787 data->szTip[i] = ( i < wtip.size() ? wtip[i] : L'\0' ) ;
788 data->szTip[n-1U] = L'\0' ;
789
790 return Shell_NotifyIconW( NIM_ADD , data ) ? 0 : 1 ;
791 }
792 inline int shellNotifyIcon( HINSTANCE hinstance , DWORD , NOTIFYICONDATAA * data ,
793 unsigned int icon_id , std::string_view tip )
794 {
795 // (modifies the caller's structure)
796 data->hIcon = LoadIconA( hinstance , MAKEINTRESOURCEA(icon_id) ) ;
797 if( data->hIcon == HNULL ) return 2 ;
798
799 constexpr std::size_t n = sizeof(data->szTip) / sizeof(data->szTip[0]) ;
800 static_assert( n > 0U , "" ) ;
801 for( std::size_t i = 0U ; i < n ; i++ )
802 data->szTip[i] = ( i < tip.size() ? tip[i] : '\0' ) ;
803 data->szTip[n-1U] = '\0' ;
804
805 return Shell_NotifyIconA( NIM_ADD , data ) ? 0 : 1 ;
806 }
807 inline bool shellNotifyIcon( DWORD message , NOTIFYICONDATAW * data , std::nothrow_t ) noexcept
808 {
809 return Shell_NotifyIconW( message , data ) ;
810 }
811 inline bool shellNotifyIcon( DWORD message , NOTIFYICONDATAA * data , std::nothrow_t ) noexcept
812 {
813 return Shell_NotifyIconA( message , data ) ;
814 }
815 inline unsigned int dragQueryFile( HDROP hdrop ) noexcept
816 {
817 if( w )
818 return DragQueryFileW( hdrop , 0xFFFFFFFF , nullptr , 0 ) ;
819 else
820 return DragQueryFileA( hdrop , 0xFFFFFFFF , nullptr , 0 ) ;
821 }
822 inline std::string dragQueryFile( HDROP hdrop , unsigned int i )
823 {
824 if( w )
825 {
826 unsigned int n = DragQueryFileW( hdrop , i , nullptr , 0U ) ;
827 std::vector<wchar_t> buffer( std::size_t(n)+1U , L'\0' ) ;
828 n = DragQueryFileW( hdrop , i , buffer.data() , n+1U ) ;
829 return Convert::narrow( buffer.data() , std::min(std::size_t(n),buffer.size()) ) ;
830 }
831 else
832 {
833 unsigned int n = DragQueryFileA( hdrop , i , nullptr , 0U ) ;
834 std::vector<char> buffer( std::size_t(n)+1U , '\0' ) ;
835 n = DragQueryFileA( hdrop , i , buffer.data() , n+1U ) ;
836 return { buffer.data() , std::min(std::size_t(n),buffer.size()) } ;
837 }
838 }
839 inline INT_PTR dialogBoxParam( HINSTANCE hinstance , int resource_id , HWND parent , DLGPROC fn , LPARAM lparam )
840 {
841 if( w )
842 return DialogBoxParamW( hinstance , MAKEINTRESOURCEW(resource_id) , parent , fn , lparam ) ;
843 else
844 return DialogBoxParamA( hinstance , MAKEINTRESOURCEA(resource_id) , parent , fn , lparam ) ;
845 }
846 inline INT_PTR dialogBoxParam( HINSTANCE hinstance , const std::string & resource , HWND parent , DLGPROC fn , LPARAM lparam )
847 {
848 if( w )
849 return DialogBoxParamW( hinstance , Convert::widen(resource).c_str() , parent , fn , lparam ) ;
850 else
851 return DialogBoxParamA( hinstance , resource.c_str() , parent , fn , lparam ) ;
852 }
853 inline HWND createDialogParam( HINSTANCE hinstance , int resource_id , HWND parent , DLGPROC fn , LPARAM lparam )
854 {
855 if( w )
856 return CreateDialogParamW( hinstance , MAKEINTRESOURCEW(resource_id) , parent , fn , lparam ) ;
857 else
858 return CreateDialogParamA( hinstance , MAKEINTRESOURCEA(resource_id) , parent , fn , lparam ) ;
859 }
860 inline HWND createDialogParam( HINSTANCE hinstance , const std::string & resource , HWND parent , DLGPROC fn , LPARAM lparam )
861 {
862 if( w )
863 return CreateDialogParamW( hinstance , Convert::widen(resource).c_str() , parent , fn , lparam ) ;
864 else
865 return CreateDialogParamA( hinstance , resource.c_str() , parent , fn , lparam ) ;
866 }
867 inline void getClassInfo( HINSTANCE hinstance , std::string_view name , WNDCLASSW * info )
868 {
869 GetClassInfoW( hinstance , Convert::widen(name).c_str() , info ) ;
870 }
871 inline void getClassInfo( HINSTANCE hinstance , const std::string & name , WNDCLASSA * info )
872 {
873 GetClassInfoA( hinstance , name.c_str() , info ) ;
874 }
875 inline ATOM registerClass( WNDCLASSW info , std::string_view name , unsigned int menu_resource_id = 0U )
876 {
877 std::wstring wname = Convert::widen( name ) ;
878 info.lpszClassName = wname.c_str() ;
879 if( menu_resource_id )
880 info.lpszMenuName = MAKEINTRESOURCEW(menu_resource_id) ;
881 return RegisterClassW( &info ) ;
882 }
883 inline ATOM registerClass( WNDCLASSA info , const std::string & name , unsigned int menu_resource_id = 0U )
884 {
885 info.lpszClassName = name.c_str() ;
886 if( menu_resource_id )
887 info.lpszMenuName = MAKEINTRESOURCEA(menu_resource_id) ;
888 return RegisterClassA( &info ) ;
889 }
890 inline std::string getClassName( HWND hwnd )
891 {
892 if( w )
893 {
894 std::vector<wchar_t> buffer( 257U ) ; // atom size limit
895 buffer[0] = L'\0' ;
896 GetClassNameW( hwnd , buffer.data() , static_cast<int>(buffer.size()-1U) ) ;
897 buffer[buffer.size()-1U] = L'\0' ;
898 return Convert::narrow( buffer.data() ) ;
899 }
900 else
901 {
902 std::vector<char> buffer( 257U ) ; // atom size limit
903 buffer[0] = '\0' ;
904 GetClassNameA( hwnd , buffer.data() , static_cast<int>(buffer.size()-1U) ) ;
905 buffer[buffer.size()-1U] = '\0' ;
906 return {buffer.data()} ;
907 }
908 }
909 inline HWND createWindowEx( DWORD extended_style , const std::string & class_name ,
910 const std::string & title , DWORD style , int x , int y , int dx , int dy ,
911 HWND parent , HMENU menu , HINSTANCE hinstance , void * vp )
912 {
913 if( w )
914 return CreateWindowExW( extended_style ,
915 Convert::widen(class_name).c_str() , Convert::widen(title).c_str() ,
916 style , x , y , dx , dy , parent , menu , hinstance , vp ) ;
917 else
918 return CreateWindowExA( extended_style ,
919 class_name.c_str() , title.c_str() ,
920 style , x , y , dx , dy , parent , menu , hinstance , vp ) ;
921 }
922 inline void check_hwnd( HWND hwnd )
923 {
924 if( w != !!IsWindowUnicode(hwnd) )
925 throw std::runtime_error( "unicode window mismatch" ) ;
926 }
927 inline LRESULT callWindowProc( LONG_PTR fn , HWND hwnd , UINT message , WPARAM wparam , LPARAM lparam )
928 {
929 check_hwnd( hwnd ) ;
930 if( w )
931 return CallWindowProcW( reinterpret_cast<WNDPROC>(fn) , hwnd , message , wparam , lparam ) ;
932 else
933 return CallWindowProcA( reinterpret_cast<WNDPROC>(fn) , hwnd , message , wparam , lparam ) ;
934
935 }
936 inline LRESULT defWindowProc( HWND hwnd , UINT message , WPARAM wparam , LPARAM lparam )
937 {
938 check_hwnd( hwnd ) ;
939 if( w )
940 return DefWindowProcW( hwnd , message , wparam , lparam ) ;
941 else
942 return DefWindowProcA( hwnd , message , wparam , lparam ) ;
943 }
944 inline LRESULT defDlgProc( HWND hwnd , UINT message , WPARAM wparam , LPARAM lparam )
945 {
946 check_hwnd( hwnd ) ;
947 if( w )
948 return DefDlgProcW( hwnd , message , wparam , lparam ) ;
949 else
950 return DefDlgProcA( hwnd , message , wparam , lparam ) ;
951 }
952 inline bool isDialogMessage( HWND hdlg , MSG * msg ) noexcept
953 {
954 if( w )
955 return IsDialogMessageW( hdlg , msg ) ;
956 else
957 return IsDialogMessageA( hdlg , msg ) ;
958 }
959 inline bool winHelp( HWND hwnd , const G::Path & path , unsigned int id )
960 {
961 if( w )
962 return WinHelpW( hwnd , G::Convert::widen(path.str()).c_str() , id , 0 ) ;
963 else
964 return WinHelpA( hwnd , path.cstr() , id , 0 ) ;
965 }
966 inline HMENU loadMenu( HINSTANCE hinstance , int id )
967 {
968 if( w )
969 return LoadMenuW( hinstance , MAKEINTRESOURCEW(id) ) ;
970 else
971 return LoadMenuA( hinstance , MAKEINTRESOURCEA(id) ) ;
972 }
973 inline std::string getMenuString( HMENU hmenu , UINT id , UINT flags )
974 {
975 if( w )
976 {
977 int n = GetMenuStringW( hmenu , id , nullptr , 0 , flags ) ;
978 if( n <= 0 )
979 return {} ;
980 std::vector<wchar_t> buffer( static_cast<std::size_t>(n)+1U ) ;
981 n = GetMenuStringW( hmenu , id , buffer.data() , static_cast<int>(buffer.size()) , flags ) ;
982 if( n <= 0 || static_cast<std::size_t>(n) != (buffer.size()-1U) )
983 return {} ;
984 return G::Convert::narrow( buffer.data() , buffer.size()-1U ) ;
985 }
986 else
987 {
988 int n = GetMenuStringA( hmenu , id , nullptr , 0 , flags ) ;
989 if( n <= 0 )
990 return {} ;
991 std::vector<char> buffer( static_cast<std::size_t>(n)+1U ) ;
992 n = GetMenuStringA( hmenu , id , buffer.data() , static_cast<int>(buffer.size()) , flags ) ;
993 if( n <= 0 || static_cast<std::size_t>(n) != (buffer.size()-1U) )
994 return {} ;
995 return std::string( buffer.data() , buffer.size()-1U ) ;
996 }
997 }
998 inline void insertMenuItem( HMENU hmenu , UINT id , const std::string & name )
999 {
1000 if( w )
1001 {
1002 std::wstring wname = Convert::widen( name ) ;
1003 MENUITEMINFOW item {} ;
1004 item.cbSize = sizeof( item ) ;
1005 item.fMask = MIIM_STRING | MIIM_ID ; // setting dwTypeData & wID
1006 item.fType = MFT_STRING ;
1007 item.wID = id ;
1008 item.dwTypeData = const_cast<wchar_t*>( wname.c_str() ) ;
1009 item.cch = static_cast<UINT>( wname.size() ) ;
1010 InsertMenuItemW( hmenu , 0 , TRUE , &item ) ;
1011 }
1012 else
1013 {
1014 MENUITEMINFOA item {} ;
1015 item.cbSize = sizeof( item ) ;
1016 item.fMask = MIIM_STRING | MIIM_ID ; // setting dwTypeData & wID
1017 item.fType = MFT_STRING ;
1018 item.wID = id ;
1019 item.dwTypeData = const_cast<char*>( name.c_str() ) ;
1020 item.cch = static_cast<UINT>( name.size() ) ;
1021 InsertMenuItemA( hmenu , 0 , TRUE , &item ) ;
1022 }
1023 }
1024 inline SC_HANDLE openSCManagerW( DWORD access ) noexcept
1025 {
1026 return OpenSCManagerW( nullptr , nullptr , access ) ; // no machine or database name
1027 }
1028 inline SC_HANDLE openSCManager( DWORD access ) noexcept
1029 {
1030 if( w ) // fwiw
1031 return OpenSCManagerW( nullptr , nullptr , access ) ; // no machine or database name
1032 else
1033 return OpenSCManagerA( nullptr , nullptr , access ) ; // no machine or database name
1034 }
1035 inline BOOL startServiceW( SC_HANDLE hservice ) noexcept
1036 {
1037 return StartServiceW( hservice , 0 , nullptr ) ; // (no args)
1038 }
1039 inline BOOL startService( SC_HANDLE hservice ) noexcept
1040 {
1041 if( w )
1042 return StartServiceW( hservice , 0 , nullptr ) ;
1043 else
1044 return StartServiceA( hservice , 0 , nullptr ) ;
1045 }
1046 using ServiceMainWFn = void (WINAPI *)( DWORD , wchar_t ** ) ;
1047 using ServiceMainAFn = void (WINAPI *)( DWORD , char ** ) ;
1048 inline BOOL startServiceCtrlDispatcherW( ServiceMainWFn w_fn ) noexcept
1049 {
1050 SERVICE_TABLE_ENTRYW table [2] = { { const_cast<wchar_t*>(L"") , w_fn } , { nullptr , nullptr } } ;
1051 return StartServiceCtrlDispatcherW( table ) ;
1052 }
1053 inline BOOL startServiceCtrlDispatcher( ServiceMainWFn w_fn , ServiceMainAFn a_fn ) noexcept
1054 {
1055 if( w )
1056 {
1057 SERVICE_TABLE_ENTRYW table [2] = { { const_cast<wchar_t*>(L"") , w_fn } , { nullptr , nullptr } } ;
1058 return StartServiceCtrlDispatcherW( table ) ;
1059 }
1060 else
1061 {
1062 SERVICE_TABLE_ENTRYA table [2] = { { const_cast<char*>("") , a_fn } , { nullptr , nullptr } } ;
1063 return StartServiceCtrlDispatcherA( table ) ;
1064 }
1065 }
1066 inline SC_HANDLE openServiceW( SC_HANDLE hmanager , const std::string & name , DWORD flags )
1067 {
1068 return OpenServiceW( hmanager , Convert::widen(name).c_str() , flags ) ;
1069 }
1070 inline SC_HANDLE openService( SC_HANDLE hmanager , const std::string & name , DWORD flags )
1071 {
1072 if( w )
1073 return OpenServiceW( hmanager , Convert::widen(name).c_str() , flags ) ;
1074 else
1075 return OpenServiceA( hmanager , name.c_str() , flags ) ;
1076 }
1077 inline SC_HANDLE createServiceW( SC_HANDLE hmanager , const std::string & name ,
1078 const std::string & display_name , DWORD start_type , const std::string & commandline )
1079 {
1080 return CreateServiceW( hmanager ,
1081 Convert::widen(name).c_str() , Convert::widen(display_name).c_str() ,
1082 SERVICE_ALL_ACCESS , SERVICE_WIN32_OWN_PROCESS , start_type , SERVICE_ERROR_NORMAL ,
1083 Convert::widen(commandline).c_str() ,
1084 nullptr , nullptr , nullptr , nullptr , nullptr ) ;
1085 }
1086 inline SC_HANDLE createService( SC_HANDLE hmanager , const std::string & name ,
1087 const std::string & display_name , DWORD start_type , const std::string & commandline )
1088 {
1089 if( w )
1090 return CreateServiceW( hmanager ,
1091 Convert::widen(name).c_str() , Convert::widen(display_name).c_str() ,
1092 SERVICE_ALL_ACCESS , SERVICE_WIN32_OWN_PROCESS , start_type , SERVICE_ERROR_NORMAL ,
1093 Convert::widen(commandline).c_str() ,
1094 nullptr , nullptr , nullptr , nullptr , nullptr ) ;
1095 else
1096 return CreateServiceA( hmanager ,
1097 name.c_str() , display_name.c_str() ,
1098 SERVICE_ALL_ACCESS , SERVICE_WIN32_OWN_PROCESS , start_type , SERVICE_ERROR_NORMAL ,
1099 commandline.c_str() ,
1100 nullptr , nullptr , nullptr , nullptr , nullptr ) ;
1101 }
1102 inline SERVICE_STATUS_HANDLE registerServiceCtrlHandlerW( const std::string & service_name , void (WINAPI *handler_fn)(DWORD) )
1103 {
1104 return RegisterServiceCtrlHandlerW( Convert::widen(service_name).c_str() , handler_fn ) ;
1105 }
1106 inline SERVICE_STATUS_HANDLE registerServiceCtrlHandler( const std::string & service_name , void (WINAPI *handler_fn)(DWORD) )
1107 {
1108 if( w )
1109 return RegisterServiceCtrlHandlerW( Convert::widen(service_name).c_str() , handler_fn ) ;
1110 else
1111 return RegisterServiceCtrlHandlerA( service_name.c_str() , handler_fn ) ;
1112 }
1113 inline bool changeServiceConfigW( SC_HANDLE hmanager , const std::string & description )
1114 {
1115 std::wstring wdescription = Convert::widen( description ) ;
1116 SERVICE_DESCRIPTIONW service_description {} ;
1117 service_description.lpDescription = const_cast<wchar_t*>( wdescription.c_str() ) ;
1118 return ChangeServiceConfig2W( hmanager , SERVICE_CONFIG_DESCRIPTION , &service_description ) ;
1119 }
1120 inline bool changeServiceConfig( SC_HANDLE hmanager , const std::string & description )
1121 {
1122 if( w )
1123 {
1124 std::wstring wdescription = Convert::widen( description ) ;
1125 SERVICE_DESCRIPTIONW service_description {} ;
1126 service_description.lpDescription = const_cast<wchar_t*>( wdescription.c_str() ) ;
1127 return ChangeServiceConfig2W( hmanager , SERVICE_CONFIG_DESCRIPTION , &service_description ) ;
1128 }
1129 else
1130 {
1131 SERVICE_DESCRIPTIONA service_description {} ;
1132 service_description.lpDescription = const_cast<char*>( description.c_str() ) ;
1133 return ChangeServiceConfig2A( hmanager , SERVICE_CONFIG_DESCRIPTION , &service_description ) ;
1134 }
1135 }
1136 inline LONG setWindowLong( HWND hwnd , int index , LONG value ) noexcept
1137 {
1138 if( w )
1139 return SetWindowLongW( hwnd , index , value ) ;
1140 else
1141 return SetWindowLongA( hwnd , index , value ) ;
1142 }
1143 inline LONG_PTR setWindowLongPtr( HWND hwnd , int index , LONG_PTR value ) noexcept
1144 {
1145 if( w )
1146 return SetWindowLongPtrW( hwnd , index , value ) ;
1147 else
1148 return SetWindowLongPtrA( hwnd , index , value ) ;
1149 }
1150 inline LONG getWindowLong( HWND hwnd , int index ) noexcept
1151 {
1152 if( w )
1153 return GetWindowLongW( hwnd , index ) ;
1154 else
1155 return GetWindowLongA( hwnd , index ) ;
1156 }
1157 inline LONG_PTR getWindowLongPtr( HWND hwnd , int index ) noexcept
1158 {
1159 if( w )
1160 return GetWindowLongPtrW( hwnd , index ) ;
1161 else
1162 return GetWindowLongPtrA( hwnd , index ) ;
1163 }
1164 inline LRESULT sendMessage( HWND hwnd , UINT msg , WPARAM wparam , LPARAM lparam ) noexcept
1165 {
1166 if( w )
1167 return SendMessageW( hwnd , msg , wparam , lparam ) ;
1168 else
1169 return SendMessageA( hwnd , msg , wparam , lparam ) ;
1170 }
1171 inline LRESULT sendMessageString( HWND hwnd , UINT msg , WPARAM wparam , const std::string & s )
1172 {
1173 check_hwnd( hwnd ) ;
1174 if( IsWindowUnicode(hwnd) )
1175 return SendMessageW( hwnd , msg , wparam , reinterpret_cast<LPARAM>(Convert::widen(s).c_str()) ) ;
1176 else
1177 return SendMessageA( hwnd , msg , wparam , reinterpret_cast<LPARAM>(s.c_str()) ) ;
1178 }
1179 inline std::string sendMessageGetString( HWND hwnd , UINT msg , WPARAM wparam )
1180 {
1181 check_hwnd( hwnd ) ;
1182 if( IsWindowUnicode(hwnd) )
1183 {
1184 std::vector<wchar_t> buffer( 1024 , L'\0' ) ;
1185 SendMessageW( hwnd , msg , wparam , reinterpret_cast<LPARAM>(buffer.data()) ) ;
1186 return Convert::narrow( buffer.data() ) ;
1187 }
1188 else
1189 {
1190 std::vector<char> buffer( 1024 , '\0' ) ;
1191 SendMessageA( hwnd , msg , wparam , reinterpret_cast<LPARAM>(buffer.data()) ) ;
1192 return {buffer.data()} ;
1193 }
1194 }
1195 inline LRESULT sendMessageInsertColumn( HWND hwnd , int sub_item , const std::string & text , int width )
1196 {
1197 check_hwnd( hwnd ) ;
1198 if( IsWindowUnicode(hwnd) )
1199 {
1200 std::wstring wtext = Convert::widen( text ) ;
1201 LVCOLUMNW column ;
1202 column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM ;
1203 column.iSubItem = sub_item ;
1204 column.pszText = const_cast<wchar_t*>( wtext.c_str() ) ;
1205 column.cx = width ;
1206 column.fmt = LVCFMT_LEFT ;
1207 return SendMessageW( hwnd , LVM_INSERTCOLUMNW , static_cast<WPARAM>(sub_item) , reinterpret_cast<LPARAM>(&column) ) ;
1208 }
1209 else
1210 {
1211 LVCOLUMNA column ;
1212 column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM ;
1213 column.iSubItem = sub_item ;
1214 column.pszText = const_cast<char*>( text.c_str() ) ;
1215 column.cx = width ;
1216 column.fmt = LVCFMT_LEFT ;
1217 return SendMessageA( hwnd , LVM_INSERTCOLUMNA , static_cast<WPARAM>(sub_item) , reinterpret_cast<LPARAM>(&column) ) ;
1218 }
1219 }
1220 inline void sendMessageInsertItem( HWND hwnd , int item , int sub_item , const std::string & text )
1221 {
1222 check_hwnd( hwnd ) ;
1223 if( IsWindowUnicode(hwnd) )
1224 {
1225 std::wstring wtext = Convert::widen( text ) ;
1226 LVITEMW lvitem {} ;
1227 lvitem.mask = LVIF_TEXT ;
1228 lvitem.iItem = item ;
1229 lvitem.iSubItem = sub_item ;
1230 lvitem.pszText = const_cast<wchar_t*>( wtext.c_str() ) ;
1231 sendMessage( hwnd , sub_item == 0 ? LVM_INSERTITEMW : LVM_SETITEMW , 0 , reinterpret_cast<LPARAM>(&lvitem) ) ;
1232 }
1233 else
1234 {
1235 LVITEMA lvitem {} ;
1236 lvitem.mask = LVIF_TEXT ;
1237 lvitem.iItem = item ;
1238 lvitem.iSubItem = sub_item ;
1239 lvitem.pszText = const_cast<char*>( text.c_str() ) ;
1240 sendMessage( hwnd , sub_item == 0 ? LVM_INSERTITEMA : LVM_SETITEMA , 0 , reinterpret_cast<LPARAM>(&lvitem) ) ;
1241 }
1242 }
1243 inline BOOL postMessage( HWND hwnd , UINT msg , WPARAM wparam , LPARAM lparam )
1244 {
1245 if( w )
1246 return PostMessageW( hwnd , msg , wparam , lparam ) ;
1247 else
1248 return PostMessageA( hwnd , msg , wparam , lparam ) ;
1249 }
1250 inline BOOL getMessage( MSG * msg_p , HWND hwnd , UINT filter_min , UINT filter_max )
1251 {
1252 if( w )
1253 return GetMessageW( msg_p , hwnd , filter_min , filter_max ) ;
1254 else
1255 return GetMessageA( msg_p , hwnd , filter_min , filter_max ) ;
1256 }
1257 inline BOOL peekMessage( MSG * msg_p , HWND hwnd , UINT filter_min , UINT filter_max , UINT remove_type )
1258 {
1259 if( w )
1260 return PeekMessageW( msg_p , hwnd , filter_min , filter_max , remove_type ) ;
1261 else
1262 return PeekMessageA( msg_p , hwnd , filter_min , filter_max , remove_type ) ;
1263 }
1264 inline LRESULT dispatchMessage( MSG * msg_p )
1265 {
1266 if( w )
1267 return DispatchMessageW( msg_p ) ;
1268 else
1269 return DispatchMessageA( msg_p ) ;
1270 }
1271 inline IID iidShellLink() noexcept
1272 {
1273 if( w )
1274 return IID_IShellLinkW ;
1275 else
1276 return IID_IShellLinkA ;
1277 }
1278 inline HRESULT shellLinkSetPath( IShellLinkW * link_p , const Path & path )
1279 {
1280 return link_p->SetPath( Convert::widen(path.str()).c_str() ) ;
1281 }
1282 inline HRESULT shellLinkSetPath( IShellLinkA * link_p , const Path & path ) noexcept
1283 {
1284 return link_p->SetPath( path.cstr() ) ;
1285 }
1286 inline HRESULT shellLinkSetWorkingDirectory( IShellLinkW * link_p , const Path & dir )
1287 {
1288 return link_p->SetWorkingDirectory( Convert::widen(dir.str()).c_str() ) ;
1289 }
1290 inline HRESULT shellLinkSetWorkingDirectory( IShellLinkA * link_p , const Path & dir ) noexcept
1291 {
1292 return link_p->SetWorkingDirectory( dir.cstr() ) ;
1293 }
1294 inline HRESULT shellLinkSetDescription( IShellLinkW * link_p , std::string_view s )
1295 {
1296 return link_p->SetDescription( Convert::widen(s).c_str() ) ;
1297 }
1298 inline HRESULT shellLinkSetDescription( IShellLinkA * link_p , const std::string & s ) noexcept
1299 {
1300 return link_p->SetDescription( s.c_str() ) ;
1301 }
1302 inline HRESULT shellLinkSetArguments( IShellLinkW * link_p , std::string_view s )
1303 {
1304 return link_p->SetArguments( Convert::widen(s).c_str() ) ;
1305 }
1306 inline HRESULT shellLinkSetArguments( IShellLinkA * link_p , const std::string & s ) noexcept
1307 {
1308 return link_p->SetArguments( s.c_str() ) ;
1309 }
1310 inline HRESULT shellLinkSetIconLocation( IShellLinkW * link_p , const Path & icon , unsigned int i )
1311 {
1312 return link_p->SetIconLocation( Convert::widen(icon.str()).c_str() , i ) ;
1313 }
1314 inline HRESULT shellLinkSetIconLocation( IShellLinkA * link_p , const Path & icon , unsigned int i ) noexcept
1315 {
1316 return link_p->SetIconLocation( icon.cstr() , i ) ;
1317 }
1318 inline HRESULT shellLinkSetShowCmd( IShellLinkW * link_p , int show ) noexcept
1319 {
1320 return link_p->SetShowCmd( show ) ;
1321 }
1322 inline HRESULT shellLinkSetShowCmd( IShellLinkA * link_p , int show ) noexcept
1323 {
1324 return link_p->SetShowCmd( show ) ;
1325 }
1326 inline HRESULT persistFileSave( IPersistFile * persist_file_p , const G::Path & link_path , BOOL remember )
1327 {
1328 return persist_file_p->Save( Convert::widen(link_path.str()).c_str() , remember ) ;
1329 }
1330 inline Path shGetFolderPath( HWND hwnd , int csidl , HANDLE user_token , DWORD flags )
1331 {
1332 if( w )
1333 {
1334 std::vector<wchar_t> buffer( MAX_PATH+1U , L'\0' ) ;
1335 if( S_OK != SHGetFolderPathW( hwnd , csidl , user_token , flags , buffer.data() ) )
1336 return {} ;
1337 buffer[buffer.size()-1U] = L'\0' ;
1338 return Path( Convert::narrow(buffer.data()) ) ;
1339 }
1340 else
1341 {
1342 std::vector<char> buffer( MAX_PATH+1U , '\0' ) ;
1343 if( S_OK != SHGetFolderPathA( hwnd , csidl , user_token , flags , buffer.data() ) )
1344 return {} ;
1345 buffer[buffer.size()-1U] = '\0' ;
1346 return Path( buffer.data() ) ;
1347 }
1348 }
1349 inline std::string loadString( HINSTANCE hinstance , UINT id )
1350 {
1351 if( w )
1352 {
1353 std::vector<wchar_t> buffer( 1024U , L'\0' ) ;
1354 int n = LoadStringW( hinstance , id , buffer.data() , static_cast<int>(buffer.size()-1U) ) ;
1355 if( n <= 0 ) return {} ;
1356 return Convert::narrow( buffer.data() , static_cast<std::size_t>(n) ) ;
1357 }
1358 else
1359 {
1360 std::vector<char> buffer( 1024U , L'\0' ) ;
1361 int n = LoadStringA( hinstance , id , buffer.data() , static_cast<int>(buffer.size()-1U) ) ;
1362 if( n <= 0 ) return {} ;
1363 return {buffer.data(),static_cast<std::size_t>(n)} ;
1364 }
1365 }
1366 inline HANDLE createWaitableTimer( LPSECURITY_ATTRIBUTES attributes , BOOL manual_reset , const std::string & name )
1367 {
1368 if( w )
1369 {
1370 std::wstring wname = G::Convert::widen( name ) ;
1371 return CreateWaitableTimerW( attributes , manual_reset , wname.c_str() ) ;
1372 }
1373 else
1374 {
1375 return CreateWaitableTimerA( attributes , manual_reset , name.c_str() ) ;
1376 }
1377 }
1378 inline INT getAddrInfo( std::string_view host , std::string_view service , const ADDRINFOW * hints , ADDRINFOW ** results )
1379 {
1380 return GetAddrInfoW( Convert::widen(host).c_str() , Convert::widen(service).c_str() , hints , results ) ;
1381 }
1382 inline INT getAddrInfo( const std::string & host , const std::string & service , const ADDRINFOA * hints , ADDRINFOA ** results )
1383 {
1384 return GetAddrInfoA( host.c_str() , service.c_str() , hints , results ) ;
1385 }
1386 inline std::string canonicalName( const ADDRINFOW & ai )
1387 {
1388 return ai.ai_canonname ? Convert::narrow(ai.ai_canonname) : std::string() ;
1389 }
1390 inline std::string canonicalName( const ADDRINFOA & ai )
1391 {
1392 return ai.ai_canonname ? std::string(ai.ai_canonname) : std::string() ;
1393 }
1394 inline void freeAddrInfo( ADDRINFOW * results )
1395 {
1396 if( results )
1397 FreeAddrInfoW( results ) ;
1398 }
1399 inline void freeAddrInfo( ADDRINFOA * results )
1400 {
1401 if( results )
1402 FreeAddrInfoA( results ) ;
1403 }
1404 }
1405}
1406
1407#endif
1408
1409#endif
static std::wstring widen(std::string_view)
Widens from UTF-8 to UTF-16/UCS-4 wstring.
Definition: gconvert.cpp:38
static std::string narrow(const std::wstring &)
Narrows from UTF-16/UCS-4 wstring to UTF-8.
Definition: gconvert.cpp:53
A Path object represents a file system path.
Definition: gpath.h:82
const value_type * cstr() const noexcept
Returns the path's c-string.
Definition: gpath.h:249
std::string str() const
Returns the path string.
Definition: gpath.h:243
std::string fromCodePageAnsi(std::string_view)
Converts from the active OEM codepage (see GetACP(), 1252 on unix) to UTF-8.
Definition: gcodepage.cpp:257
std::string toCodePageAnsi(std::string_view)
Converts from UTF-8 to the active "ansi" codepage (see GetACP(), 1252 on unix).
Definition: gcodepage.cpp:214
Low-level classes.
Definition: garg.h:36
STL namespace.