1 /*----------------------------------------------------------------------------
2 ** wpickclick.c
3 **  Utilty to pick clicks posted to Wine Windows
4 **
5 **
6 **---------------------------------------------------------------------------
7 **  Copyright 2004 Jozef Stefanka for CodeWeavers, Inc.
8 **  Copyright 2005 Francois Gouget for CodeWeavers, Inc.
9 **  Copyright 2005 Dmitry Timoshkov for CodeWeavers, Inc.
10 **
11 **     This program is free software; you can redistribute it and/or modify
12 **     it under the terms of the GNU General Public License as published by
13 **     the Free Software Foundation; either version 2 of the License, or
14 **     (at your option) any later version.
15 **
16 **     This program is distributed in the hope that it will be useful,
17 **     but WITHOUT ANY WARRANTY; without even the implied warranty of
18 **     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 **     GNU General Public License for more details.
20 **
21 **     You should have received a copy of the GNU General Public License
22 **     along with this program; if not, write to the Free Software
23 **     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24 **
25 **--------------------------------------------------------------------------*/
26 #include <stdio.h>
27 #include <fcntl.h>
28 #include <io.h>
29 #include <windows.h>
30 
31 #include "hook.h"
32 
33 
34 #define APP_NAME "wpickclick.exe"
35 
36 
37 static BOOL (WINAPI *pInstallHooks)(HMODULE hdll);
38 static void (WINAPI *pRemoveHooks)();
39 static action_t* (WINAPI *pGetAction)();
40 static void (WINAPI *pFreeAction)(action_t* action);
41 
42 
43 /*
44  * Provide some basic debugging support.
45  */
46 #ifdef __GNUC__
47 #define __PRINTF_ATTR(fmt,args) __attribute__((format (printf,fmt,args)))
48 #else
49 #define __PRINTF_ATTR(fmt,args)
50 #endif
51 static int debug_on=0;
52 static int init_debug()
53 {
54     char* str=getenv("CXTEST_DEBUG");
55     if (str && strstr(str, "+hook"))
56         debug_on=1;
57     return debug_on;
58 }
59 
60 static void cxlog(const char* format, ...) __PRINTF_ATTR(1,2);
61 static void cxlog(const char* format, ...)
62 {
63     va_list valist;
64 
65     if (debug_on)
66     {
67         va_start(valist, format);
68         vfprintf(stderr, format, valist);
69         va_end(valist);
70     }
71 }
72 
73 static HINSTANCE load_hook_dll()
74 {
75     HINSTANCE hinstDll;
76     char dllpath[MAX_PATH];
77     char* p;
78 
79     hinstDll=LoadLibrary("hook.dll");
80     if (hinstDll != NULL)
81         return hinstDll;
82 
83     if (!GetModuleFileName(NULL,dllpath,sizeof(dllpath)))
84         return NULL;
85 
86     p=strrchr(dllpath,'\\');
87     if (!p)
88         return NULL;
89     *p='\0';
90     p=strrchr(dllpath,'\\');
91     if (!p)
92         return NULL;
93     *p='\0';
94     strcat(dllpath,"\\hookdll\\hook.dll");
95     hinstDll=LoadLibrary(dllpath);
96     return hinstDll;
97 }
98 
99 char* cleanup(char* str)
100 {
101     char* s;
102 
103     while (*str==' ' || *str=='\t' || *str=='\r' || *str=='\n')
104         str++;
105     s=strchr(str,'\n');
106     if (!s)
107         s=str+strlen(str)-1;
108     while (s>str && (*s==' ' || *s=='\t' || *s=='\r' || *s=='\n'))
109         s--;
110     *(s+1)='\0';
111     return str;
112 }
113 
114 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
115                    LPSTR lpCmdLine, int nCmdShow)
116 {
117     HINSTANCE hDll;
118     action_t* action;
119 
120     init_debug();
121 
122     /* Our scripts expect Unix-style line ends */
123     _setmode(1,_O_BINARY);
124     _setmode(2,_O_BINARY);
125 
126     if (strstr(lpCmdLine,"--help"))
127     {
128         fprintf(stderr,"%s - Utility to print coordinates, component, window title, component class and window class name of a click\n", APP_NAME);
129         fprintf(stderr,"----------------------------------------------\n");
130         fprintf(stderr,"Usage: %s\n",APP_NAME);
131         fprintf(stderr,"The options are as follows:\n");
132         fprintf(stderr,"After starting you can\n");
133         fprintf(stderr,"select where to click.  If we properly track the click, it will be reported\n");
134         fprintf(stderr,"in the following format:\n");
135         fprintf(stderr,"    button-name x y component_name window_name component_class_name window_class_name\n");
136         fprintf(stderr,"Note that x and y can be negative; this typically happens if you click within the\n");
137         fprintf(stderr,"window manager decorations of a given window.\n");
138         fprintf(stderr,"On success, %s returns 0, non zero on some failure\n",APP_NAME);
139         exit(0);
140     };
141 
142     /* Load the hook library */
143     hDll = load_hook_dll();
144     if (!hDll)
145     {
146         fprintf(stderr, "Error: Unable to load 'hook.dll'\n");
147         printf("failed\n");
148         return 1;
149     }
150 
151     pInstallHooks=(void*)GetProcAddress(hDll, "InstallHooks");
152     pRemoveHooks=(void*)GetProcAddress(hDll, "RemoveHooks");
153     pGetAction=(void*)GetProcAddress(hDll, "GetAction");
154     pFreeAction=(void*)GetProcAddress(hDll, "FreeAction");
155     if (!pInstallHooks || !pRemoveHooks || !pGetAction)
156     {
157         fprintf(stderr, "Error: Unable to get the hook.dll functions (%ld)\n",
158                 GetLastError());
159         printf("failed\n");
160         return 1;
161     }
162 
163     if (!pInstallHooks(hDll))
164     {
165         fprintf(stderr, "Error: Unable to install the hooks (%ld)\n",
166                 GetLastError());
167         printf("failed\n");
168         return 1;
169     }
170 
171     fprintf(stderr, "Ready for capture...\n");
172     action=pGetAction();
173     if (!action)
174     {
175         fprintf(stderr, "Error: GetAction() failed\n");
176         printf("failed\n");
177         return 1;
178     }
179 
180     switch (action->action)
181     {
182     case ACTION_FAILED:
183         printf("failed\n");
184         break;
185     case ACTION_NONE:
186         printf("none\n");
187         break;
188     case ACTION_FIND:
189         printf("find\n");
190         break;
191     case ACTION_BUTTON1:
192     case ACTION_BUTTON2:
193     case ACTION_BUTTON3:
194         printf("button%d %ld %ld\n", action->action-ACTION_BUTTON1+1,
195                action->x, action->y);
196         break;
197     default:
198         fprintf(stderr, "Error: Unknown action %d\n",action->action);
199         printf("%d\n", action->action);
200         break;
201     }
202     printf("%s\n", action->window_class);
203     printf("%s\n", action->window_title);
204     printf("%ld\n", action->control_id);
205     printf("%s\n", action->control_class);
206     printf("%s\n", cleanup(action->control_caption));
207 
208     cxlog("\n%s: action=%d x=%ld y=%ld\n", __FILE__, action->action,
209           action->x, action->y);
210     cxlog("window_class='%s'\n", action->window_class);
211     cxlog("window_title='%s'\n", action->window_title);
212     cxlog("control_id=%ld\n", action->control_id);
213     cxlog("control_class='%s'\n", action->control_class);
214     cxlog("control_caption='%s'\n", action->control_caption);
215 
216     pFreeAction(action);
217     pRemoveHooks();
218     return 0;
219 }
220