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