1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 /*
29  * Description: Put MSO in a state where it can be closed using
30  *              automation or kill it completely
31  */
32 
33 #include "stdafx.h"
34 #include <stdio.h>
35 
36 
37 void KillOffice();
38 BOOL KillAppFromWindow(HWND hWnd, char *appName);
39 BOOL CloseActiveDialogs();
40 void printUsage();
41 
42 //Callbacks used in closing
43 BOOL CALLBACK CloseOfficeDlgProc(HWND hwndChild, LPARAM lParam);
44 BOOL CALLBACK CountOfficeDlgProc(HWND hwndChild, LPARAM lParam);
45 
46 //Global counters for number of windows found
47 int gWDDlgCount = 0;
48 int gXLDlgCount = 0;
49 int gPPDlgCount = 0;
50 
51 //Dialog window class names for excel, powerpoint and word
52 //These are "Best guess" dialog names
53 const char *pWordDlg2k  = "bosa_sdm_Microsoft Word 9.0";
54 const char *pWordDlg2k3 = "bosa_sdm_Microsoft Office Word";
55 const char *pXLDlg2k    = "bosa_sdm_XL9";
56 const char *pPPDlg2k    = "#32770";
57 const char *pXLDlg2k3   = "bosa_sdm_XL9";
58 const char *pPPDlg2k3   = "#32770";
59 const char *pGenMSODlg  = "bosa_sdm_Mso96";
60 //consider adding - bosa_sdm_Mso96
61 
62 //Command Line Argument constants
63 const char *ARG_HELP  = "--help";
64 const char *ARG_KILL  = "--kill";
65 const char *ARG_CLOSE = "--close";
66 
67 //Window class names for MSO apps - if we need to look at other office instances
68 //then this list would need to be expanded
69 #define NUM_WINDOWCLASSNAMES 4
70 char *wndClassName[NUM_WINDOWCLASSNAMES] = {"OpusApp", "XLMAIN", "PP9FrameClass", "PP10FrameClass"};
71 
72 int main(int argc, char* argv[])
73 {
74 	if (argc < 2) {
75 		printUsage();
76 		return 0;
77 	}
78 
79 	if (strcmpi(argv[1], ARG_HELP) == 0) {
80 		printUsage();
81 		return 0;
82 	}
83 
84 	if (strcmpi(argv[1], ARG_KILL) == 0) {
85 		KillOffice();
86 		return 0;
87 	}
88 
89 	if (strcmpi(argv[1], ARG_CLOSE) == 0) {
90 		CloseActiveDialogs();
91 		return 0;
92 	}
93 
94 	return 0;
95 }
96 
97 /*--------------------------------------------------------------
98   Find the MSO window if it is available and explictly kill it
99   MSO apps in this case are Excel, Word and PP
100   Use FindWindow Win32 API to detect if they are available
101 
102   -------------------------------------------------------------*/
103 void KillOffice() {
104 	HWND hWnd;
105 
106 	for (int i=0;i<NUM_WINDOWCLASSNAMES;i++) {
107 		int j = 0;
108 		while (((hWnd = FindWindow(wndClassName[i], NULL )) != NULL) && (j < 10)) {
109 			KillAppFromWindow(hWnd, wndClassName[i]);
110 			j++;
111 		}
112 	}
113 }
114 
115 /*--------------------------------------------------------------
116   Using window handle, get process handle and try to kill the
117   app. This may not be successful if you do not have enough
118   privileges to kill the app.
119 
120   --------------------------------------------------------------*/
121 BOOL KillAppFromWindow(
122     HWND hWnd,
123     char *
124 #ifdef _DEBUG
125     appName
126 #endif
127 )
128 {
129 	BOOL bRet = TRUE;
130 
131 	if(hWnd == NULL) {
132 		//The app doesn't appear to be running
133 #ifdef _DEBUG
134 		printf("App %s: window not found.\n,", appName);
135 #endif
136 		bRet = FALSE;
137 	} else {
138 		DWORD pid;  // Variable to hold the process ID.
139 		DWORD dThread;  // Variable to hold (unused) thread ID.
140 		dThread = GetWindowThreadProcessId(hWnd, &pid);
141 		HANDLE hProcess; // Handle to existing process
142 
143 		hProcess = OpenProcess(SYNCHRONIZE | PROCESS_ALL_ACCESS, TRUE, pid);
144 		if (hProcess == NULL) {
145 #ifdef _DEBUG
146 			printf("App %s : Failed to get process handle",appName);
147 #endif
148 			bRet = FALSE;
149 		} else {
150 			if (!TerminateProcess(hProcess, 0)) {
151 				LPTSTR lpMsgBuf;
152 				FormatMessage(
153 					FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
154 					NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
155 					(LPTSTR) &lpMsgBuf, 0, NULL );
156 				printf("%s\n", lpMsgBuf);
157 				LocalFree( lpMsgBuf );
158 				bRet = FALSE;
159 			}
160 #ifdef _DEBUG
161 			else {
162 				printf("Kill %s appears to be successful.\n", appName);
163 			}
164 #endif
165 		}
166 	}
167 	return bRet;
168 }
169 
170 /*--------------------------------------------------------------
171   Close the dialogs if possible based on their window class
172   Use the EnumChildWindows win32 api for this
173   --------------------------------------------------------------*/
174 BOOL CloseActiveDialogs() {
175 	char buff[1024];
176 
177 	gWDDlgCount = 0;
178 	gXLDlgCount = 0;
179 	gPPDlgCount = 0;
180 
181 	EnumChildWindows(GetDesktopWindow(), CloseOfficeDlgProc, (LPARAM) 0);
182 	sprintf(buff, "Word: %d\tExcel: %d\tPP: %d", gWDDlgCount, gXLDlgCount, gPPDlgCount);
183 	return TRUE;
184 }
185 
186 /*--------------------------------------------------------------
187   Callback for EnumChildWindows that sends close message to
188   any dialogs that match window class of MSO dialogs
189 
190   --------------------------------------------------------------*/
191 BOOL CALLBACK CloseOfficeDlgProc(HWND hwndChild, LPARAM)
192 {
193 	//bosa_sdm_Microsoft Word 9.0
194 	//bosa_sdm_XL9
195 	//#32770 (Dialog)
196 
197  	char szBuff[4096];
198 	if (GetClassName(hwndChild, szBuff, 4096) == 0) {
199 
200 	} else {
201 		if ((strcmpi(szBuff, pWordDlg2k) == 0) || (strcmpi(szBuff, pWordDlg2k3) == 0)) {
202 			gWDDlgCount++;
203 			SendMessage(hwndChild, WM_CLOSE, 0, 0);
204 		}
205 		if (strcmpi(szBuff, pXLDlg2k) == 0) {
206 			gXLDlgCount++;
207 			SendMessage(hwndChild, WM_CLOSE, 0, 0);
208 		}
209 		if (strcmpi(szBuff, pPPDlg2k) == 0) {
210 			gPPDlgCount++;
211 			SendMessage(hwndChild, WM_CLOSE, 0, 0);
212 		}
213 		if (strcmpi(szBuff, pGenMSODlg) == 0) {
214 			SendMessage(hwndChild, WM_CLOSE, 0, 0);
215 		}
216 	}
217 
218     return TRUE;
219 }
220 
221 
222 /*--------------------------------------------------------------
223   Callback for EnumChildWindows that counts numnnber of
224   dialogs that match window class of MSO dialogs
225 
226   --------------------------------------------------------------*/
227 BOOL CALLBACK CountOfficeDlgProc(HWND hwndChild, LPARAM)
228 {
229  	char szBuff[4096];
230 	if (GetClassName(hwndChild, szBuff, 4096) == 0) {
231 
232 	} else {
233 		if ((strcmpi(szBuff, pWordDlg2k) == 0) || (strcmpi(szBuff, pWordDlg2k3) == 0)) {
234 			gWDDlgCount++;
235 		}
236 		if (strcmpi(szBuff, pXLDlg2k) == 0) {
237 			gXLDlgCount++;
238 		}
239 		if (strcmpi(szBuff, pPPDlg2k) == 0) {
240 			gPPDlgCount++;
241 		}
242 	}
243 
244 	return TRUE;
245 }
246 
247 /*--------------------------------------------------------------
248   Simple usage message...
249 
250   -------------------------------------------------------------*/
251 void printUsage() {
252 	printf("Recovery Assistant Utility - try and put MSO apps in a recoverable state\n");
253 	printf("Copyright Sun Microsystems 2008\n");
254 	printf("Options:\n");
255 	printf("   --help : This message\n");
256 	printf("   --close: Attempt to close any open dialogs owned by \n");
257 	printf("            MSO apps so Application.Quit() can succeed\n");
258 	printf("   --kill : Kill any open MSO apps. Use with caution and only as a last resort\n\n");
259 }