-
-
Notifications
You must be signed in to change notification settings - Fork 37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix crash issue on some special Windows machines. #89
Conversation
To be honest I don't feel very comfortable with this implementation. My implementation is definitely buggy, and I'd rather merge something that makes sense with the documentation, not something that ignores the recommendation to call Do you have access to the machine in question? |
https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-coinitializeex
I want to ignore the I don’t have access to the machine, but I can contact him to help with some testing. |
The documentation says |
There are several bugs. The last call to Another bug of mine is around testing for Problems with the current PR: To not call You say calling What I'd like to do, if I had access to a test machine is:
Only if those don't work would I consider not calling |
Actually, it's not crash in It crash in The application may set another concurrency flag before calling |
--- a/file_windows.go
+++ b/file_windows.go
@@ -3,6 +3,7 @@ package zenity
import (
"fmt"
"path/filepath"
+ "runtime"
"syscall"
"unicode/utf16"
"unsafe"
@@ -174,8 +205,10 @@ func pickFolders(opts options, multi bool) (string, []string, error) {
owner, _ := opts.attach.(win.HWND)
defer setup(owner)()
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
err := win.CoInitializeEx(0, win.COINIT_APARTMENTTHREADED|win.COINIT_DISABLE_OLE1DDE)
- if err != win.RPC_E_CHANGED_MODE {
+ if err != win.RPC_E_CHANGED_MODE && err != win.S_FALSE {
if err != nil {
return "", nil, err
}
--- a/internal/win/ole32.go
+++ b/internal/win/ole32.go
@@ -24,6 +24,7 @@ const (
E_CANCELED = windows.ERROR_CANCELLED | windows.FACILITY_WIN32<<16 | 0x80000000
RPC_E_CHANGED_MODE = syscall.Errno(windows.RPC_E_CHANGED_MODE)
+ S_FALSE = syscall.Errno(windows.S_FALSE)
) If we change it like this, then I call runtime.LockOSThread()
defer runtime.UnlockOSThread()
_ = windows.CoInitializeEx(0, windows.COINIT_APARTMENTTHREADED|windows.COINIT_DISABLE_OLE1DDE)
files, err := zenity.SelectFileMultiple(options...) |
--- a/file_windows.go
+++ b/file_windows.go
@@ -3,6 +3,7 @@ package zenity
import (
"fmt"
"path/filepath"
+ "runtime"
"syscall"
"unicode/utf16"
"unsafe"
@@ -59,6 +70,16 @@ func selectFileMultiple(opts options) ([]string, error) {
return res, err
}
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ err := win.CoInitializeEx(0, win.COINIT_APARTMENTTHREADED|win.COINIT_DISABLE_OLE1DDE)
+ if err != win.RPC_E_CHANGED_MODE && err != win.S_FALSE {
+ if err != nil {
+ return nil, err
+ }
+ defer win.CoUninitialize()
+ }
+
var args win.OPENFILENAME
args.StructSize = uint32(unsafe.Sizeof(args))
args.Owner, _ = opts.attach.(win.HWND) If we change it like this, and I don't call |
@ncruces If you want to keep |
Can you check if 3f5b602 fixes the issue? |
Thanks. I'll contact him to help test it out. He's probably on vacation and it's going to take some time. If |
Unfortunately it’s not working. It always crashes when calling |
Only Again my issue is with calling it all the time in all OS threads. And never undoing it. This increases a reference count, changes global state, and goes against the spirit of the project: no threading or initialization requirements. |
Not only We only need to initialize it once for each thread. If we initialize it every time, it will ensure that every thread is initialized. According to the documentation, the second initialization of the same thread will return |
|
The problem with “lets do it for every thread” is that goroutines don't map to threads, unless you Especially for something that looks like an (old?) Windows bug, or related to some explorer extension the user may have installed. |
That's better, yes. Can you confirm it fixes your issue? At that point, I'd do this in the general setup, that's already called for every Windows dialog. Though I've reviewed it, and I undo everything that can/should be undone. Let me read more about this. Otherwise, this is something that might be done app side, right? The “only” issue with this is that we pick the wrong apartment and we prevent the app from doing it right. |
He will help test it tomorrow. According to the results of the previous test, it should be solved. There is no need to do anything on the app side to solve that issue. If the app call CoInitializeEx itself, zenity will call CoInitializeEx once again, but only once for each thread. |
Does this also happen with |
84d5fe5 works.
|
c565889 uses This is a more modern API, hopefully it's less buggy. |
Assuming the above, PR #91 should fix this and use the more modern COM API everywhere it's available. |
@ncruces Thanks for your help. He may be on vacation until around 19th. I'll let you know when the fix is confirmed. |
The program crashed on Windows when selecting files for the second time, with the same behavior as
https://stackoverflow.com/questions/35366998/2nd-call-to-getopenfilename-crashes-without-error-on-win-8-1-64-bit-machine
The original issue: trzsz/trzsz-ssh#76