1 /**************************************************************************
2 *   Copyright (C) 2005-2020 by Oleksandr Shneyder                         *
3 *                              <o.shneyder@phoca-gmbh.de>                 *
4 *                                                                         *
5 *   This program is free software; you can redistribute it and/or modify  *
6 *   it under the terms of the GNU General Public License as published by  *
7 *   the Free Software Foundation; either version 2 of the License, or     *
8 *   (at your option) any later version.                                   *
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 <https://www.gnu.org/licenses/>. *
16 ***************************************************************************/
17 
18 #ifndef _WIN32_WINDOWS
19 #define _WIN32_WINDOWS 0x0500
20 #define _WIN32_WINNT 0x0500
21 #define WINVER 0x0500
22 #endif
23 #include "x2goclientconfig.h"
24 #ifdef Q_OS_WIN
25 #include <winsock2.h>
26 #include <windows.h>
27 #include <winerror.h>
28 #include <sddl.h>
29 #include "wapi.h"
30 #include "x2gologdebug.h"
31 
32 
wapiSetFSWindow(HWND hWnd,const QRect & desktopGeometry)33 long wapiSetFSWindow ( HWND hWnd, const QRect& desktopGeometry )
34 {
35     SetWindowLong(hWnd, GWL_STYLE,
36                   WS_VISIBLE);
37     SetWindowLong(hWnd, GWL_EXSTYLE,
38                   0);
39     SetWindowPos ( hWnd, HWND_TOPMOST, desktopGeometry.x(),
40                    desktopGeometry.y(),
41                    desktopGeometry.width(),
42                    desktopGeometry.height(),
43                    0);
44     return WS_VISIBLE;
45 }
46 
wapiRestoreWindow(HWND hWnd,long style,const QRect & desktopGeometry)47 void wapiRestoreWindow( HWND hWnd, long style, const QRect& desktopGeometry )
48 {
49     SetWindowLong ( hWnd, GWL_STYLE,style);
50     SetWindowPos ( hWnd, HWND_TOP, desktopGeometry.x(),
51                    desktopGeometry.y(),
52                    desktopGeometry.width(),
53                    desktopGeometry.height(),
54                    SWP_FRAMECHANGED );
55 }
56 
wapiHideFromTaskBar(HWND wnd)57 void wapiHideFromTaskBar ( HWND wnd )
58 {
59     ShowWindow ( wnd, SW_HIDE ) ;
60     SetWindowLong ( wnd, GWL_EXSTYLE, GetWindowLong ( wnd, GWL_EXSTYLE )  &
61                     ~WS_EX_APPWINDOW );
62     SetWindowLong ( wnd, GWL_EXSTYLE, GetWindowLong ( wnd, GWL_EXSTYLE )  |
63                     WS_EX_TOOLWINDOW );
64     ShowWindow ( wnd, SW_SHOW ) ;
65 }
66 
wapiSetParent(HWND child,HWND par)67 HWND wapiSetParent ( HWND child, HWND par )
68 {
69     HWND wn=SetParent ( child,par );
70     if ( par )
71         SetWindowLong ( child, GWL_STYLE,
72                         GetWindowLong ( child, GWL_STYLE ) | WS_CHILD );
73     else
74         SetWindowLong (
75             child, GWL_STYLE,
76             GetWindowLong ( child, GWL_STYLE ) &~ WS_CHILD );
77     SetWindowLong ( child, GWL_STYLE,
78                     GetWindowLong ( child, GWL_STYLE ) | WS_POPUP );
79     return wn;
80 }
81 
wapiClientRect(HWND wnd,QRect & rect)82 bool wapiClientRect ( HWND wnd, QRect& rect )
83 {
84     RECT rcWindow;
85     if ( GetClientRect ( wnd,&rcWindow ) )
86     {
87         rect.setCoords ( rcWindow.left,
88                          rcWindow.top,
89                          rcWindow.right,rcWindow.bottom );
90         return true;
91     }
92     return false;
93 }
94 
wapiWindowRectWithoutDecoration(HWND wnd,QRect & rect)95 bool wapiWindowRectWithoutDecoration ( HWND wnd, QRect& rect )
96 {
97     RECT rcWindow;
98     if ( GetClientRect ( wnd,&rcWindow ) )
99     {
100         POINT pnt;
101         pnt.x=0;
102         pnt.y=0;
103         ClientToScreen(wnd,&pnt);
104         rect.setRect ( pnt.x,
105                        pnt.y,
106                        rcWindow.right-rcWindow.left,rcWindow.bottom-rcWindow.top );
107         return true;
108     }
109     return false;
110 }
111 
112 
wapiWindowRect(HWND wnd,QRect & rect)113 bool wapiWindowRect ( HWND wnd, QRect& rect )
114 {
115     RECT rcWindow;
116     if ( GetWindowRect ( wnd,&rcWindow ) )
117     {
118         rect.setCoords ( rcWindow.left,
119                          rcWindow.top,
120                          rcWindow.right,rcWindow.bottom );
121         return true;
122     }
123     return false;
124 }
125 
wapiGetBorders(HWND wnd,int & vBorder,int & hBorder,int & barHeight)126 bool wapiGetBorders ( HWND wnd, int& vBorder, int& hBorder, int& barHeight )
127 {
128     WINDOWINFO wifo;
129     wifo.cbSize=sizeof ( WINDOWINFO );
130     if ( !GetWindowInfo ( wnd,&wifo ) )
131         return false;
132     vBorder=wifo.cxWindowBorders;
133     hBorder=wifo.cyWindowBorders;
134     TITLEBARINFO bifo;
135     bifo.cbSize=sizeof ( TITLEBARINFO );
136     if ( !GetTitleBarInfo ( wnd,&bifo ) )
137         return false;
138     barHeight=bifo.rcTitleBar.bottom-bifo.rcTitleBar.top;
139 
140     return true;
141 
142 }
143 
wapiShowWindow(HWND wnd,wapiCmdShow nCmdShow)144 bool wapiShowWindow ( HWND wnd, wapiCmdShow nCmdShow )
145 {
146     int cmd=WAPI_SHOWNORMAL;
147     switch ( nCmdShow )
148     {
149     case WAPI_FORCEMINIMIZE:
150         cmd=SW_FORCEMINIMIZE;
151         break;
152     case WAPI_HIDE:
153         cmd=SW_HIDE;
154         break;
155     case WAPI_MAXIMIZE:
156         cmd=SW_MAXIMIZE;
157         break;
158     case WAPI_MINIMIZE:
159         cmd=SW_MINIMIZE;
160         break;
161     case WAPI_RESTORE:
162         cmd=SW_RESTORE;
163         break;
164     case WAPI_SHOW:
165         cmd=SW_SHOW;
166         break;
167     case WAPI_SHOWDEFAULT:
168         cmd=SW_SHOWDEFAULT;
169         break;
170     case WAPI_SHOWMAXIMIZED:
171         cmd=SW_SHOWMAXIMIZED;
172         break;
173     case WAPI_SHOWMINIMIZED:
174         cmd=SW_SHOWMINIMIZED;
175         break;
176     case WAPI_SHOWMINNOACTIVE:
177         cmd=SW_SHOWMINNOACTIVE;
178         break;
179     case WAPI_SHOWNA:
180         cmd=SW_SHOWNA;
181         break;
182     case WAPI_SHOWNOACTIVATE:
183         cmd=SW_SHOWNOACTIVATE;
184         break;
185     case WAPI_SHOWNORMAL:
186         cmd=SW_SHOWNORMAL;
187         break;
188     }
189 
190     return ShowWindow ( wnd, cmd );
191 }
192 
wapiUpdateWindow(HWND wnd)193 bool wapiUpdateWindow ( HWND wnd )
194 {
195     return RedrawWindow ( wnd,0,0,RDW_INVALIDATE );
196 }
197 
wapiMoveWindow(HWND wnd,int x,int y,int width,int height,bool repaint)198 bool wapiMoveWindow ( HWND wnd, int x, int y, int width, int height,
199                       bool repaint )
200 {
201     return MoveWindow ( wnd, x, y, width, height, repaint );
202 }
203 
wapiFindWindow(const ushort * className,const ushort * text)204 HWND wapiFindWindow ( const ushort * className, const ushort * text )
205 {
206     return FindWindowEx ( 0,0, ( LPCTSTR ) className, ( LPCTSTR ) text );
207 }
208 
wapiSetWindowText(HWND wnd,const QString & text)209 bool wapiSetWindowText( HWND wnd, const QString& text)
210 {
211     return SetWindowText(wnd, (LPCTSTR)text.utf16() );
212 }
213 
wapiSetWindowIcon(HWND wnd,const QPixmap & icon)214 void wapiSetWindowIcon ( HWND wnd, const QPixmap& icon)
215 {
216     int iconx=GetSystemMetrics(SM_CXICON);
217     int icony=GetSystemMetrics(SM_CYICON);
218     int smallx=GetSystemMetrics(SM_CXSMICON);
219     int smally=GetSystemMetrics(SM_CXSMICON);
220 
221     HICON largeIcon=0;
222     HICON smallIcon=0;
223 
224     largeIcon=icon.scaled(iconx,icony, Qt::IgnoreAspectRatio,Qt::SmoothTransformation).toWinHICON ();
225     smallIcon=icon.scaled(smallx,smally, Qt::IgnoreAspectRatio,Qt::SmoothTransformation).toWinHICON ();
226 
227     x2goDebug<<"Large icon: "<<largeIcon<<iconx<<"x"<<icony;
228     x2goDebug<<"Small icon: "<<smallIcon<<smallx<<"x"<<smally;
229     int rez=SetClassLong(wnd,GCL_HICON, (LONG)largeIcon);
230     if (!rez)
231         x2goDebug<<"ERROR: "<<GetLastError()<<endl;
232     rez=SetClassLong(wnd,GCL_HICONSM,(LONG)smallIcon);
233     if (!rez)
234         x2goDebug<<"ERROR: "<<GetLastError()<<endl;
235     /*    ShowWindow(wnd, SW_HIDE);
236         ShowWindow(wnd, SW_SHOW);*/
237 }
238 
wapiShortFileName(const QString & longName)239 QString wapiShortFileName ( const QString& longName )
240 {
241     long     length = 0;
242     TCHAR*   buffer = NULL;
243 
244     length = GetShortPathName ( ( LPCTSTR ) longName.utf16(), NULL, 0 );
245     if ( !length )
246     {
247         return QString::null;
248     }
249 
250     buffer = new TCHAR[length];
251     length = GetShortPathName ( ( LPCTSTR ) longName.utf16(),
252                                 buffer,length );
253     if ( !length )
254     {
255         delete []buffer;
256         return QString::null;
257     }
258     QString spath=QString::fromUtf16 ( ( const ushort* ) buffer );
259     delete []buffer;
260     return spath;
261 }
262 
263 
wapiGetDriveByLabel(const QString & label)264 QString wapiGetDriveByLabel(const QString& label)
265 {
266     int len=GetLogicalDriveStrings(0,0);
267     if (len>0)
268     {
269         TCHAR* buf=new TCHAR[len+1];
270         len=GetLogicalDriveStrings(len,buf);
271         for (int i=0; i<len; i+=4)
272         {
273             QString drive=QString::fromUtf16 ( ( const ushort* ) buf+i );
274             x2goDebug<<"Drive: "<<drive;
275             TCHAR vol[MAX_PATH+1];
276             TCHAR fs[MAX_PATH+1];
277             GetVolumeInformation(buf+i,vol,MAX_PATH,0,0,0,fs,MAX_PATH);
278             QString volume=QString::fromUtf16 ( ( const ushort* ) vol );
279             x2goDebug<<"Volume: "<<volume<<
280                      "; fs: "<<QString::fromUtf16 ( ( const ushort* ) fs );
281             if (!volume.compare(label,Qt::CaseInsensitive))
282             {
283                 x2goDebug<<"matched! ";
284 
285                 delete []buf;
286                 return drive.replace(":\\","");
287             }
288         }
289         delete []buf;
290     }
291 
292     return label;
293 }
294 
295 
getNameFromSid(PSID psid,QString * systemName)296 QString getNameFromSid ( PSID psid, QString* systemName )
297 {
298     DWORD length=0;
299     DWORD dlength=0;
300     TCHAR* name=0;
301     TCHAR* sysName=0;
302     SID_NAME_USE eUse;
303 
304     LookupAccountSid ( 0,psid,
305                        name,&length,sysName,&dlength,&eUse );
306     if ( !length )
307     {
308         return QString::null;
309     }
310 
311     name=new TCHAR[length];
312     sysName=new TCHAR[dlength];
313 
314     if ( ! LookupAccountSid ( 0,psid,
315                               name,&length,sysName,
316                               &dlength,&eUse ) )
317     {
318         delete []name;
319         delete []sysName;
320         return QString::null;
321     }
322 
323     QString strName=QString::fromUtf16 (
324                         ( const ushort* ) name );
325     if ( systemName )
326         *systemName=QString::fromUtf16 (
327                         ( const ushort* ) sysName );
328     delete []sysName;
329     delete []name;
330     return strName;
331 }
332 
getStringFromSid(PSID psid)333 QString getStringFromSid ( PSID psid )
334 {
335     LPTSTR stringSid;
336     ConvertSidToStringSid ( psid,
337                             &stringSid );
338     QString str=QString::fromUtf16 (
339                     ( const ushort* ) stringSid );
340     LocalFree ( stringSid );
341     return str;
342 }
343 
wapiAccountInfo(QString * retSid,QString * retUname,QString * primaryGroupSID,QString * primaryGroupName,QString * retSysName)344 bool wapiAccountInfo ( QString* retSid, QString* retUname,
345                        QString* primaryGroupSID, QString* primaryGroupName,
346                        QString* retSysName )
347 {
348     HANDLE hToken;
349     if ( !OpenProcessToken ( GetCurrentProcess(),
350                              TOKEN_QUERY, &hToken ) )
351     {
352         return false;
353     }
354     if ( primaryGroupSID || primaryGroupName )
355     {
356         PTOKEN_PRIMARY_GROUP pGroupInfo=0;
357         DWORD dwResult=0;
358         DWORD dwSize=0;
359         if ( !GetTokenInformation ( hToken, TokenPrimaryGroup,
360                                     NULL, dwSize, &dwSize ) )
361         {
362             dwResult = GetLastError();
363             if ( dwResult != ERROR_INSUFFICIENT_BUFFER )
364             {
365                 CloseHandle ( hToken );
366                 return false;
367             }
368         }
369         pGroupInfo = ( PTOKEN_PRIMARY_GROUP ) GlobalAlloc ( GPTR,
370                      dwSize );
371 
372         if ( ! GetTokenInformation ( hToken, TokenPrimaryGroup,
373                                      pGroupInfo,
374                                      dwSize, &dwSize ) )
375         {
376             if ( pGroupInfo )
377                 GlobalFree ( pGroupInfo );
378             CloseHandle ( hToken );
379             return false;
380         }
381 
382         if ( primaryGroupSID )
383         {
384             *primaryGroupSID=getStringFromSid (
385                                  pGroupInfo->PrimaryGroup );
386         }
387         if ( primaryGroupName )
388         {
389             *primaryGroupName=getNameFromSid (
390                                   pGroupInfo->PrimaryGroup,
391                                   retSysName );
392         }
393 
394         if ( pGroupInfo )
395             GlobalFree ( pGroupInfo );
396     }
397     if ( retSid || retUname )
398     {
399         PTOKEN_USER pUserInfo=0;
400         DWORD dwResult=0;
401         DWORD dwSize=0;
402 
403         if ( !GetTokenInformation ( hToken, TokenUser,
404                                     NULL, dwSize, &dwSize ) )
405         {
406             dwResult = GetLastError();
407             if ( dwResult != ERROR_INSUFFICIENT_BUFFER )
408             {
409                 CloseHandle ( hToken );
410                 return false;
411             }
412         }
413         pUserInfo = ( PTOKEN_USER ) GlobalAlloc ( GPTR,
414                     dwSize );
415 
416         if ( ! GetTokenInformation ( hToken, TokenUser,
417                                      pUserInfo,
418                                      dwSize, &dwSize ) )
419         {
420             if ( pUserInfo )
421                 GlobalFree ( pUserInfo );
422             CloseHandle ( hToken );
423             return false;
424         }
425 
426         if ( retSid )
427         {
428             *retSid=getStringFromSid (
429                         pUserInfo->User.Sid );
430         }
431         if ( retUname )
432         {
433             *retUname=getNameFromSid (
434                           pUserInfo->User.Sid,
435                           retSysName );
436         }
437         if ( pUserInfo )
438             GlobalFree ( pUserInfo );
439     }
440     CloseHandle ( hToken );
441     return true;
442 }
443 
wapiShellExecute(const QString & operation,const QString & file,const QString & parameters,const QString & dir,HWND win)444 void wapiShellExecute ( const QString& operation, const QString& file,
445                         const QString& parameters,
446                         const QString& dir, HWND win )
447 {
448     if ( parameters==QString::null )
449         ShellExecute ( win, ( LPCTSTR ) ( operation.utf16() ),
450                        ( LPCTSTR ) ( file.utf16() ),0,
451                        ( LPCTSTR ) ( dir.utf16() ),SW_SHOWNORMAL );
452     else
453         ShellExecute ( win, ( LPCTSTR ) ( operation.utf16() ),
454                        ( LPCTSTR ) ( file.utf16() ),
455                        ( LPCTSTR ) ( parameters.utf16() ),
456                        ( LPCTSTR ) ( dir.utf16() ),SW_SHOWNORMAL );
457 }
458 
wapiGetDefaultPrinter()459 QString wapiGetDefaultPrinter()
460 {
461     TCHAR *prName;
462     DWORD length;
463     GetDefaultPrinter ( 0,&length );
464     if ( !length )
465         return QString::null;
466     prName=new TCHAR[length];
467     GetDefaultPrinter ( prName,&length );
468     if ( !length )
469     {
470         delete []prName;
471         return QString::null;
472     }
473     QString printer=QString::fromUtf16 ( ( const ushort* ) prName );
474     delete []prName;
475     return printer;
476 
477 }
478 
wapiGetLocalPrinters()479 QStringList wapiGetLocalPrinters()
480 {
481     QStringList printers;
482     PRINTER_INFO_4 *info_array;
483     DWORD sizeOfArray;
484     DWORD bufSize=0;
485     DWORD sizeNeeded=0;
486     EnumPrinters ( PRINTER_ENUM_LOCAL,0,4,NULL,bufSize,
487                    &sizeNeeded,&sizeOfArray );
488     if ( !sizeNeeded )
489     {
490         return printers;
491     }
492     info_array= ( PRINTER_INFO_4* ) new char[sizeNeeded];
493     if ( !info_array )
494         return printers;
495     bufSize=sizeNeeded;
496     EnumPrinters ( PRINTER_ENUM_LOCAL,0,4, ( LPBYTE ) info_array,bufSize,
497                    &sizeNeeded,&sizeOfArray );
498     if ( !sizeNeeded || !sizeOfArray )
499     {
500         delete []info_array;
501         return printers;
502     }
503     for ( uint i=0; i<sizeOfArray; ++i )
504     {
505         printers<<QString::fromUtf16 (
506                     ( const ushort* ) ( info_array[i].pPrinterName ) );
507     }
508     delete []info_array;
509     return printers;
510 }
511 
512 #define INFO_BUFFER_SIZE 32767
wapiGetUserName()513 QString wapiGetUserName()
514 {
515     TCHAR  infoBuf[INFO_BUFFER_SIZE];
516     DWORD bufCharCount=INFO_BUFFER_SIZE;
517     if( !GetUserName( infoBuf, &bufCharCount ) )
518         return QString::null;
519     return QString::fromUtf16 ( ( const ushort* ) infoBuf);
520 }
521 #endif
522