Don't CoUninitialize, close MTA dialog.
This commit is contained in:
parent
1e77b878b5
commit
99f1a258bc
3 changed files with 48 additions and 9 deletions
|
@ -246,6 +246,18 @@ func fileOpenDialog(opts options, multi bool) (string, []string, bool, error) {
|
|||
}
|
||||
defer unhook()
|
||||
|
||||
if opts.ctx != nil && opts.ctx.Done() != nil {
|
||||
wait := make(chan struct{})
|
||||
defer close(wait)
|
||||
go func() {
|
||||
select {
|
||||
case <-opts.ctx.Done():
|
||||
dialog.Close(win.E_TIMEOUT)
|
||||
case <-wait:
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
err = dialog.Show(owner)
|
||||
if opts.ctx != nil && opts.ctx.Err() != nil {
|
||||
return "", nil, true, opts.ctx.Err()
|
||||
|
@ -352,6 +364,18 @@ func fileSaveDialog(opts options) (string, bool, error) {
|
|||
}
|
||||
defer unhook()
|
||||
|
||||
if opts.ctx != nil && opts.ctx.Done() != nil {
|
||||
wait := make(chan struct{})
|
||||
defer close(wait)
|
||||
go func() {
|
||||
select {
|
||||
case <-opts.ctx.Done():
|
||||
dialog.Close(win.E_TIMEOUT)
|
||||
case <-wait:
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
err = dialog.Show(owner)
|
||||
if opts.ctx != nil && opts.ctx.Err() != nil {
|
||||
return "", true, opts.ctx.Err()
|
||||
|
@ -428,14 +452,19 @@ func browseForFolderCallback(wnd win.HWND, msg uint32, lparam, data uintptr) uin
|
|||
|
||||
func coInitialize() (context.CancelFunc, error) {
|
||||
runtime.LockOSThread()
|
||||
err := win.CoInitializeEx(0, win.COINIT_APARTMENTTHREADED|win.COINIT_DISABLE_OLE1DDE)
|
||||
if err == nil || err == win.S_FALSE {
|
||||
return func() {
|
||||
win.CoUninitialize()
|
||||
runtime.UnlockOSThread()
|
||||
}, nil
|
||||
// .NET uses MTA for all background threads, so do the same.
|
||||
// If someone needs STA because they're doing UI,
|
||||
// they should initialize COM themselves before.
|
||||
err := win.CoInitializeEx(0, win.COINIT_MULTITHREADED|win.COINIT_DISABLE_OLE1DDE)
|
||||
if err == win.S_FALSE {
|
||||
// COM was already initialized, we simply increased the ref count.
|
||||
// Make this a no-op by decreasing our ref count.
|
||||
win.CoUninitialize()
|
||||
return runtime.UnlockOSThread, nil
|
||||
}
|
||||
if err == win.RPC_E_CHANGED_MODE {
|
||||
// Don't uninitialize COM; this is against the docs, but it's what .NET does.
|
||||
// Eventually all threads will have COM initialized.
|
||||
if err == nil || err == win.RPC_E_CHANGED_MODE {
|
||||
return runtime.UnlockOSThread, nil
|
||||
}
|
||||
runtime.UnlockOSThread()
|
||||
|
|
|
@ -23,6 +23,7 @@ const (
|
|||
CLSCTX_ALL = windows.CLSCTX_INPROC_SERVER | windows.CLSCTX_INPROC_HANDLER | windows.CLSCTX_LOCAL_SERVER | windows.CLSCTX_REMOTE_SERVER
|
||||
|
||||
E_CANCELED = windows.ERROR_CANCELLED | windows.FACILITY_WIN32<<16 | 0x80000000
|
||||
E_TIMEOUT = windows.ERROR_TIMEOUT | windows.FACILITY_WIN32<<16 | 0x80000000
|
||||
RPC_E_CHANGED_MODE = syscall.Errno(windows.RPC_E_CHANGED_MODE)
|
||||
S_FALSE = syscall.Errno(windows.S_FALSE)
|
||||
)
|
||||
|
|
|
@ -251,6 +251,15 @@ func (u *IFileDialog) SetTitle(title *uint16) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func (u *IFileDialog) GetResult() (item *IShellItem, err error) {
|
||||
vtbl := *(**iFileDialogVtbl)(unsafe.Pointer(u))
|
||||
hr, _, _ := u.call(vtbl.GetResult, uintptr(unsafe.Pointer(&item)))
|
||||
if hr != 0 {
|
||||
err = syscall.Errno(hr)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (u *IFileDialog) SetDefaultExtension(extension *uint16) (err error) {
|
||||
vtbl := *(**iFileDialogVtbl)(unsafe.Pointer(u))
|
||||
hr, _, _ := u.call(vtbl.SetDefaultExtension, uintptr(unsafe.Pointer(extension)))
|
||||
|
@ -260,9 +269,9 @@ func (u *IFileDialog) SetDefaultExtension(extension *uint16) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func (u *IFileDialog) GetResult() (item *IShellItem, err error) {
|
||||
func (u *IFileDialog) Close(res syscall.Errno) (err error) {
|
||||
vtbl := *(**iFileDialogVtbl)(unsafe.Pointer(u))
|
||||
hr, _, _ := u.call(vtbl.GetResult, uintptr(unsafe.Pointer(&item)))
|
||||
hr, _, _ := u.call(vtbl.Close, uintptr(res))
|
||||
if hr != 0 {
|
||||
err = syscall.Errno(hr)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue