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