diff --git a/fccs_export.py b/fccs_export.py index 512d144..a57ffe6 100755 --- a/fccs_export.py +++ b/fccs_export.py @@ -146,41 +146,52 @@ def perform_export(dlg, ctrl, timeouts): def dismiss_any_dialog(app, ctrl, log): """Try to find and dismiss any stale dialogs left from a previous failure.""" - try: - for w in app.windows(): - if not (w.class_name() == "#32770" and w.is_visible()): - continue - title = w.window_text() - # Dismiss the Send To File dialog (Cancel) - if title == ctrl["dialog_title"]: - try: - w.child_window(title="Cancel", class_name="Button").click() - log(f" Dismissed stale Send To File dialog.") - time.sleep(0.5) - except Exception: - pass - continue - # Dismiss any other dialog (OK) - try: - w.child_window(title="OK", class_name="Button").click() - log(f" Dismissed stale dialog: {title!r}") - time.sleep(0.5) - except Exception: - pass - except Exception: - pass + # Dismiss "Send to" confirmation dialog (OK) + w = _find_desktop_dialog("Send to") + if w: + try: + _click_dialog_button(w, "OK", log) + log(" Dismissed stale confirmation dialog.") + except Exception: + pass + + # Dismiss Send To File Location dialog (Cancel) + w = _find_desktop_dialog(ctrl["dialog_title"]) + if w: + try: + _click_dialog_button(w, "Cancel", log) + log(" Dismissed stale Send To File dialog.") + except Exception: + pass + + +def _find_desktop_dialog(title_match): + """Search all top-level windows for a visible #32770 dialog matching title.""" + for w in Desktop(backend="win32").windows(): + try: + if w.class_name() == "#32770" and w.is_visible() and title_match in w.window_text(): + return w + except Exception: + continue + return None + + +def _click_dialog_button(dialog, button_title, log): + """Connect to a desktop dialog and click a button on it.""" + app = Application(backend="win32").connect(handle=dialog.handle) + dlg = app.window(handle=dialog.handle) + dlg.child_window(title=button_title, class_name="Button").click() + dlg.wait_not("visible", timeout=10) def wait_for_export(app, ctrl, timeouts, log): """ Wait for the full export lifecycle to complete: 1. 'Exporting Documents' progress dialog appears (export running) - 2. Progress dialog disappears (export finished writing files) - 3. '"Send to" file saved' confirmation dialog appears (MODAL) - 4. Dismiss it by clicking OK + 2. Poll until '"Send to" file saved' confirmation dialog appears + 3. Click OK to dismiss it """ progress = app.window(title=ctrl["progress_title"], class_name=ctrl["progress_class"]) - saved = app.window(title=ctrl["saved_title"], class_name=ctrl["saved_class"]) try: progress.wait("visible", timeout=timeouts["progress_appear"]) @@ -189,51 +200,24 @@ def wait_for_export(app, ctrl, timeouts, log): log(" NOTE: progress dialog not seen; checking for confirmation dialog " "(drawer may have exported very quickly).") - # Poll until the confirmation dialog appears OR we time out. - # We do NOT rely on wait_not for the progress dialog because it can - # briefly disappear and reappear during long exports. + # Poll the entire desktop for the confirmation dialog. + # app.window() can miss it — the dialog may not be owned by the app. deadline = time.time() + timeouts["progress_finish"] + saved_win = None while time.time() < deadline: - # Check if the confirmation dialog has appeared - if saved.exists(timeout=0): + saved_win = _find_desktop_dialog("Send to") + if saved_win is not None: break time.sleep(2) - else: - log(f" ERROR: export did not finish within {timeouts['progress_finish']}s.") + + if saved_win is None: + log(f" ERROR: confirmation dialog never appeared within {timeouts['progress_finish']}s.") return False - try: - saved.wait("visible ready", timeout=timeouts["confirm"]) - log(" Confirmation dialog appeared - export succeeded.") - except timings.TimeoutError: - # Fallback: look for any #32770 dialog that appeared (title may differ) - log(" WARNING: expected confirmation dialog not found by title. " - "Checking for any popup dialog...") - found = False - try: - for w in app.windows(): - if w.class_name() == "#32770" and w.is_visible(): - log(f" Found dialog: {w.window_text()!r}") - try: - w.child_window(title="OK", class_name="Button").click() - w.wait_not("visible", timeout=10) - log(" Dismissed via fallback.") - found = True - break - except Exception: - pass - except Exception: - pass - if not found: - log(" ERROR: confirmation dialog never appeared. Export may have " - "failed or produced no output.") - return False - log(" Export complete.") - return True + log(f" Confirmation dialog found: {saved_win.window_text()!r}") try: - saved.child_window(title=ctrl["saved_ok_title"], class_name="Button").click() - saved.wait_not("visible", timeout=timeouts["confirm"]) + _click_dialog_button(saved_win, "OK", log) log(" Confirmation dismissed.") except Exception as e: log(f" WARNING: could not dismiss confirmation dialog: {e}")