fix(windows): don't crash on startup from OCR apartment
All checks were successful
CI / Windows build (push) Successful in 8m7s
All checks were successful
CI / Windows build (push) Successful in 8m7s
The app showed no window because RegisterOcrChannel ran winrt::init_apartment() (defaults to MTA) on the Flutter platform thread, which main.cpp already put in an STA via CoInitializeEx. That throws RPC_E_CHANGED_MODE and kills the app before the window appears. Remove that call; run the WinRT OCR on a dedicated MTA worker thread per recognize call instead, joining before returning the result.
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <winrt/Windows.Foundation.h>
|
#include <winrt/Windows.Foundation.h>
|
||||||
@@ -70,8 +71,12 @@ std::unique_ptr<flutter::MethodChannel<flutter::EncodableValue>> g_ocr_channel;
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void RegisterOcrChannel(flutter::FlutterEngine* engine) {
|
void RegisterOcrChannel(flutter::FlutterEngine* engine) {
|
||||||
winrt::init_apartment();
|
// NOTE: do NOT call winrt::init_apartment() here. This runs on the Flutter
|
||||||
|
// platform thread, which main.cpp has already initialized as an STA via
|
||||||
|
// CoInitializeEx(COINIT_APARTMENTTHREADED). Calling init_apartment() (which
|
||||||
|
// defaults to multi-threaded) would throw RPC_E_CHANGED_MODE and crash the
|
||||||
|
// app before the window appears. The WinRT OCR work runs on its own
|
||||||
|
// dedicated MTA worker thread per call instead (see below).
|
||||||
g_ocr_channel =
|
g_ocr_channel =
|
||||||
std::make_unique<flutter::MethodChannel<flutter::EncodableValue>>(
|
std::make_unique<flutter::MethodChannel<flutter::EncodableValue>>(
|
||||||
engine->messenger(), "badnote/ocr",
|
engine->messenger(), "badnote/ocr",
|
||||||
@@ -91,14 +96,31 @@ void RegisterOcrChannel(flutter::FlutterEngine* engine) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
const auto png_bytes = ExtractBytes(*call.arguments());
|
||||||
const auto png_bytes = ExtractBytes(*call.arguments());
|
|
||||||
const auto text = RecognizePng(png_bytes);
|
// Run the WinRT OCR on a dedicated multi-threaded-apartment worker so
|
||||||
|
// its blocking .get() calls behave correctly and the platform thread's
|
||||||
|
// STA apartment is left untouched. We join before returning so the
|
||||||
|
// MethodResult is completed on the platform thread.
|
||||||
|
std::string text;
|
||||||
|
std::string error;
|
||||||
|
std::thread worker([&]() {
|
||||||
|
try {
|
||||||
|
winrt::init_apartment(winrt::apartment_type::multi_threaded);
|
||||||
|
text = RecognizePng(png_bytes);
|
||||||
|
winrt::uninit_apartment();
|
||||||
|
} catch (const winrt::hresult_error& e) {
|
||||||
|
error = winrt::to_string(e.message());
|
||||||
|
} catch (...) {
|
||||||
|
error = "Unknown OCR error";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
worker.join();
|
||||||
|
|
||||||
|
if (!error.empty()) {
|
||||||
|
result->Error("ocr_failed", error);
|
||||||
|
} else {
|
||||||
result->Success(flutter::EncodableValue(text));
|
result->Success(flutter::EncodableValue(text));
|
||||||
} catch (const winrt::hresult_error& error) {
|
|
||||||
result->Error("ocr_failed", winrt::to_string(error.message()));
|
|
||||||
} catch (...) {
|
|
||||||
result->Error("ocr_failed", "Unknown OCR error");
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user