-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
[SHELL32][BROWSEUI] Implement ShellBrowser Apply/Reset default folder settings #6912
[SHELL32][BROWSEUI] Implement ShellBrowser Apply/Reset default folder settings #6912
Conversation
Well that's precisely what we try to avoid doing in ReactOS (making the exported interfaces incompatible on purpose). Maybe one of the other shell guys could help you determine what the actual format is. |
FWF_NOSUBFOLDERS | FWF_NOSCROLL | FWF_NOENUMREFRESH | FWF_NOVISIBLE); | ||
} | ||
|
||
static void EnsureValid(DEFFOLDERSETTINGS &dfs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this EnsureValid helper meant to be used in more than one place in the future? (So far it's only used in CGlobalFolderSettings::Load )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
static void EnsureValid(DEFFOLDERSETTINGS &dfs) | |
static void EnsureValid(DEFFOLDERSETTINGS& dfs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No sure yet. Not in this PR anyway. External components should probably use IGlobalFolderSettings if they want to read but so far I think only CShellBrowser needs this data and I made its SBFOLDERSETTINGS look like the other structs it is currently reading with a .Load
method.
FWF_NOSUBFOLDERS | FWF_NOSCROLL | FWF_NOENUMREFRESH | FWF_NOVISIBLE); | ||
} | ||
|
||
static void EnsureValid(DEFFOLDERSETTINGS &dfs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
static void EnsureValid(DEFFOLDERSETTINGS &dfs) | |
static void EnsureValid(DEFFOLDERSETTINGS& dfs) |
FIXME("Save current as default\n"); | ||
break; | ||
case DVCMDID_RESETDEFAULTFOLDERSETTINGS: | ||
wsprintfW(SubKey, L"%s\\%s", REGSTR_PATH_EXPLORER, L"Streams\\Default"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wsprintfW(SubKey, L"%s\\%s", REGSTR_PATH_EXPLORER, L"Streams\\Default"); | |
StringCchPrintfW(SubKey, _countof(SubKey), L"%s\\%s", REGSTR_PATH_EXPLORER, L"Streams\\Default"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why? The string will always fit.
I see two options: A) Try to make it Windows compatible. The problem with this is that the registry value is 40 bytes and I'm not going to be able to figure out all the bytes. Making it 40 bytes and let Windows load garbage/unknown data is not a great option. This value is also 4 bytes smaller on 2000 than on XP and there is no size of it stored inside like a classic "cbSize". Every time I Apply/Reset, a member is incremented as some sort of counter, I assume so Windows knows if it has loaded the up to date version or a stale one. B) Be incompatible on purpose. This is not a problem. The only scenario where something goes "wrong" is when you first use ROS browseui and then Windows browseui on the same system (or vice versa). In this case it will fail to read the users default preference and you will end up with the "system defaults". When Windows reads our "corrupt" value, I believe it ends up in either VIEW_PRIORITY_STALECACHEHIT or VIEW_PRIORITY_CACHEMISS mode. Just being able to load/save this value is a big win for ROS, it means you can set a different view mode as the default for all FS folders if you don't like ListView report mode.
IStream is not a format! That is like saying "file X is probably of CreateFile format". It is not an OLE stream with the class CLSID stored first. |
Save/Restore the state of the ShellBrowser toolbar/addressbar/statusbar. This is related to CORE-9094. Windows shares the state of the Go button and the locked state between Explorer and Internet Explorer but the bar states are not shared. Notes: - This is not really related to PR reactos#6912. This PR deals with the ShellBrowser state that is saved every time you change the rebar while the other is only about the default folder settings.
Save/Restore the state of the ShellBrowser toolbar/addressbar/statusbar. This is related to CORE-9094. Windows shares the state of the Go button and the locked state between Explorer and Internet Explorer but the bar states are not shared. Notes: - This is not really related to PR reactos#6912. This PR deals with the ShellBrowser state that is saved every time you change the rebar while the other is only about the default folder settings.
Save/Restore the state of the ShellBrowser toolbar/addressbar/statusbar. This is related to CORE-9094. Windows shares the state of the Go button and the locked state between Explorer and Internet Explorer but the bar states are not shared. Notes: - This is not really related to PR reactos#6912. This PR deals with the ShellBrowser state that is saved every time you change the rebar while the other is only about the default folder settings.
Save/Restore the state of the ShellBrowser toolbar/addressbar/statusbar. This is related to CORE-9094. Windows shares the state of the Go button and the locked state between Explorer and Internet Explorer but the bar states are not shared. Notes: - This is not really related to PR reactos#6912. This PR deals with the ShellBrowser state that is saved every time you change the rebar while the other is only about the default folder settings.
I do second @HBelusca . We do want to be compatible. Many ShellBags-feature-reversing/documentation can be found in the description of the following ticket. https://jira.reactos.org/browse/CORE-9283 |
What we should also try to avoid, is painstakingly trying to be "binary compatible" with some internal interface that some version of Windows used to have 30 years ago and that not a single application outside of internal MS tools ever used.
|
As I said on mattermost: |
I can use a different name for the value but it should still be in the same subkey so that anyone nuking the key used by Windows also nukes us. |
|
||
static void InitializeDefaults(DEFFOLDERSETTINGS &dfs) | ||
{ | ||
C_ASSERT(FIELD_OFFSET(DEFFOLDERSETTINGS, FolderSettings) == 4); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this 4 corresponding to a sizeof(DWORD)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know what the Windows struct has as the first member, a DWORD or bit-field or two WORDs etc. I just know the ListView view mode is 4 bytes into the struct.
sdk/include/reactos/shellutils.h
Outdated
SHELL_ErrorBoxHelper(HWND hwndOwner, UINT Error) | ||
{ | ||
WCHAR buf[400]; | ||
UINT cch, u32_errstr = 2; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 ? What's this error corresponding to?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is the resource id for the string that says "Error" (and only used when there is no other option if FormatMessage
fails). This id is the same on Windows.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could do UINT cch, u32_errstr = IDS_ERROR;
Then at the top of the file you can add:
#ifndef IDS_ERROR
#define IDS_ERROR 2
#endif // IDS_ERROR
I'm guessing we call it IDS_ERROR in our resources, but double check that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is shellutils.h, I don't want to pollute globally with macros that may cause conflicts. I will however use a more descriptive name that includes "IDS_ERROR".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will not cause an issue. It's encouraged in fact.
From Microsoft's MSVC documentation:
"However, you can redefine the macro with exactly the same definition. Thus, the same definition may appear more than once in a program."
From GNU's GCC documentation:
"If the new definition is effectively the same, the redefinition is silently ignored. This allows, for instance, two different headers to define a common macro. The preprocessor will only complain if the definitions do not match."
https://learn.microsoft.com/en-us/cpp/preprocessor/macros-c-cpp?view=msvc-170
https://gcc.gnu.org/onlinedocs/cpp/Undefining-and-Redefining-Macros.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe MSI shouldn't redefine IDS_ERROR? MSI is winesynced, it would never use shellutils.h. And if you did end up forking it to use shellutils.h, you should give that resource a different name; it's poorly named.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those are fair points.
I still don't understand how a define is better than something contained inside the function in question.
No matter how we look at it, I'm relying on a user32 implementation detail and that is slightly hacky. But again, it's the best I can do...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The define points to why we set it to that value; it corresponds with IDS_ERROR resource in user32. You can add a comment to the top of the define block that says // From user32 resource IDS_ERROR
or something similar. It may be similarly hacky, but it is more apparent that it is deliberate this way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about an enum (inside function) with a comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess that's better, I would dismiss my rejection if you did that. But I still think the define is a better way to do this.
if (!cch) | ||
{ | ||
cch = LoadStringW(LoadLibraryW(L"USER32"), u32_errstr, buf, _countof(buf)); | ||
wsprintfW(buf + cch, L"\n\n%#x (%d)", Error, Error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like a candidate for StringCchPrintfW
here, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is shellutils.h, I don't want to pull in anything. Besides, the string "Error" in any language + two 32-bit formatted numbers is going to fit in WCHAR buf[400];
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not? It's not just about fitting into your buffer. Using unsafe buffer functions can lead to security issues.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not just about fitting into your buffer. Using unsafe buffer functions can lead to security issues.
It is only about fitting it into the buffer. We know the format string is safe because we control it here.
sdk/include/reactos/shellutils.h
Outdated
@@ -98,7 +98,7 @@ static inline UINT | |||
SHELL_ErrorBoxHelper(HWND hwndOwner, UINT Error) | |||
{ | |||
WCHAR buf[400]; | |||
UINT cch, u32_errstr = 2; | |||
UINT cch, user32_IDS_ERROR = 2; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still a magic constant. Please also see my other comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How would it be less magic if it was a define?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use a newly-added parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use a newly-added parameter
I have no idea what this even means in this context
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this needs to be reused elsewhere, adding a #define USER32_ERROR 2
in our sdk/include/reactos/undocuser.h
would make sense (+ a comment about what this define is for).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this needs to be reused elsewhere
That is a big if.
Kernel32 and advapi32 should not be displaying a lot of message boxes. Other components higher up?
Cross that bridge when we get there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed 👍
sdk/include/reactos/shellutils.h
Outdated
@@ -98,7 +98,7 @@ static inline UINT | |||
SHELL_ErrorBoxHelper(HWND hwndOwner, UINT Error) | |||
{ | |||
WCHAR buf[400]; | |||
UINT cch, u32_errstr = 2; | |||
UINT cch, user32_IDS_ERROR = 2; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this needs to be reused elsewhere, adding a #define USER32_ERROR 2
in our sdk/include/reactos/undocuser.h
would make sense (+ a comment about what this define is for).
Notes:
I don't know the format of the Windows "Settings" stream. I made our version incompatible on purpose, it is much smaller and uses a special signature.