JJ_MKVMaker/lib/platform/windows/com_guard.dart

45 lines
1.9 KiB
Dart

import 'dart:ffi';
import 'dart:io';
typedef _CoInitC = Int32 Function(Pointer<Void> reserved, Uint32 mode);
typedef _CoInitD = int Function(Pointer<Void> reserved, int mode);
typedef _CoUninitC = Void Function();
typedef _CoUninitD = void Function();
/// Windows COM 준비 상태를 다루는 도우미.
///
/// 앱 안 브라우저 (Edge WebView2) 는 화면을 그리는 스레드에 COM 이 준비되어 있어야 만들어진다.
/// 실행 파일이 시작할 때 준비해 두지만, 다른 구성 요소가 그것을 풀어 버리면
/// "CoInitialize 가 호출되지 않았습니다" 로 브라우저가 뜨지 않는다 → 만들기 직전에 다시 준비한다.
class ComGuard {
static final DynamicLibrary _ole = DynamicLibrary.open('ole32.dll');
static final _CoInitD _init = _ole.lookupFunction<_CoInitC, _CoInitD>('CoInitializeEx');
static final _CoUninitD _uninit = _ole.lookupFunction<_CoUninitC, _CoUninitD>('CoUninitialize');
static const _apartmentThreaded = 0x2;
/// 이 스레드에 COM 을 준비한다 (이미 되어 있으면 그대로). 돌려주는 값은 Windows 결과 코드:
/// 0 = 새로 준비함 (풀려 있었음), 1 = 이미 준비되어 있었음, 음수 = 다른 방식으로 이미 준비됨 · 실패
static int ensure() {
if (!Platform.isWindows) return 1;
try {
return _init(nullptr, _apartmentThreaded);
} catch (_) {
return -1;
}
}
/// 준비 상태를 확인하고, 풀려 있었으면 다시 준비한다. 다시 준비했으면 true.
/// (이미 준비되어 있었으면 확인하느라 올린 만큼 도로 내려 원래대로 둔다)
static bool repairIfNeeded() {
final hr = ensure();
if (hr == 1) _uninit();
return hr == 0;
}
/// 준비 상태를 한 단계 푼다 ([ensure] 와 짝 - CoUninitialize)
static void release() {
if (Platform.isWindows) _uninit();
}
}