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()
|
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)
|
err = dialog.Show(owner)
|
||||||
if opts.ctx != nil && opts.ctx.Err() != nil {
|
if opts.ctx != nil && opts.ctx.Err() != nil {
|
||||||
return "", nil, true, opts.ctx.Err()
|
return "", nil, true, opts.ctx.Err()
|
||||||
|
@ -352,6 +364,18 @@ func fileSaveDialog(opts options) (string, bool, error) {
|
||||||
}
|
}
|
||||||
defer unhook()
|
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)
|
err = dialog.Show(owner)
|
||||||
if opts.ctx != nil && opts.ctx.Err() != nil {
|
if opts.ctx != nil && opts.ctx.Err() != nil {
|
||||||
return "", true, opts.ctx.Err()
|
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) {
|
func coInitialize() (context.CancelFunc, error) {
|
||||||
runtime.LockOSThread()
|
runtime.LockOSThread()
|
||||||
err := win.CoInitializeEx(0, win.COINIT_APARTMENTTHREADED|win.COINIT_DISABLE_OLE1DDE)
|
// .NET uses MTA for all background threads, so do the same.
|
||||||
if err == nil || err == win.S_FALSE {
|
// If someone needs STA because they're doing UI,
|
||||||
return func() {
|
// 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()
|
win.CoUninitialize()
|
||||||
runtime.UnlockOSThread()
|
return runtime.UnlockOSThread, nil
|
||||||
}, 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
|
return runtime.UnlockOSThread, nil
|
||||||
}
|
}
|
||||||
runtime.UnlockOSThread()
|
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
|
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_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)
|
RPC_E_CHANGED_MODE = syscall.Errno(windows.RPC_E_CHANGED_MODE)
|
||||||
S_FALSE = syscall.Errno(windows.S_FALSE)
|
S_FALSE = syscall.Errno(windows.S_FALSE)
|
||||||
)
|
)
|
||||||
|
|
|
@ -251,6 +251,15 @@ func (u *IFileDialog) SetTitle(title *uint16) (err error) {
|
||||||
return
|
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) {
|
func (u *IFileDialog) SetDefaultExtension(extension *uint16) (err error) {
|
||||||
vtbl := *(**iFileDialogVtbl)(unsafe.Pointer(u))
|
vtbl := *(**iFileDialogVtbl)(unsafe.Pointer(u))
|
||||||
hr, _, _ := u.call(vtbl.SetDefaultExtension, uintptr(unsafe.Pointer(extension)))
|
hr, _, _ := u.call(vtbl.SetDefaultExtension, uintptr(unsafe.Pointer(extension)))
|
||||||
|
@ -260,9 +269,9 @@ func (u *IFileDialog) SetDefaultExtension(extension *uint16) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *IFileDialog) GetResult() (item *IShellItem, err error) {
|
func (u *IFileDialog) Close(res syscall.Errno) (err error) {
|
||||||
vtbl := *(**iFileDialogVtbl)(unsafe.Pointer(u))
|
vtbl := *(**iFileDialogVtbl)(unsafe.Pointer(u))
|
||||||
hr, _, _ := u.call(vtbl.GetResult, uintptr(unsafe.Pointer(&item)))
|
hr, _, _ := u.call(vtbl.Close, uintptr(res))
|
||||||
if hr != 0 {
|
if hr != 0 {
|
||||||
err = syscall.Errno(hr)
|
err = syscall.Errno(hr)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue