Wine-Devel
By thread
wine-devel@list.winehq.org
By month
Messages by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
June 2018
- 68 participants
- 1149 messages
Re: [PATCH 3/4] msi: Store the current script in the package.
by Hans Leidekker
Signed-off-by: Hans Leidekker <hans(a)codeweavers.com>
June 6, 2018
Re: [PATCH 2/4] msi: Resolve source when executing InstallFiles.
by Hans Leidekker
Signed-off-by: Hans Leidekker <hans(a)codeweavers.com>
June 6, 2018
Re: [PATCH 1/4] msi/tests: Test that some actions cause resolution of SourceDir.
by Hans Leidekker
Signed-off-by: Hans Leidekker <hans(a)codeweavers.com>
June 6, 2018
Re: [PATCH] ntoskrnl: Have MmIsAddressValid use IsBadReadPtr.
by Thomas Faber
On 2018-06-06 04:36, Zhiyi Zhang wrote:
> The function is meant to be used in nt kernel space, however wineserver is
> in user space as far as I know. So we would need different implementation.
>
> May be we could do something like return !IsBadWritePtr(VirtualAddress, 1) || !IsBadReadPtr(VirtualAddress, 1).
> And write a test to verify such behavior.
IsBadReadPtr(x) implies IsBadWritePtr(x), since Windows does not have a
concept of "write-only" access to pages. So checking both seems
unnecessary.
The real difference between IsBadReadPtr and MmIsAddressValid is that
the former can actually _make_ the address valid by causing a page
fault (and paging in or zeroing the page). MmIsAddressValid on the
other hand would simply look at the current state of the page table
entry without side effects.
This stuff isn't hard to test per se, but a full test that's correct for
Windows kernel land will not currently work in Wine due to unimplemented
Mm stuff, e.g.
for (protection in [PAGE_NOACCESS, PAGE_READONLY, PAGE_READWRITE])
{
ZwAllocateVirtualMemory(..., &Base, ..., MEM_COMMIT, protection);
// physical page is not assigned until first access
todo_wine ok(!MmIsAddressValid(Base, 1), ...);
// force a physical page to appear and prevent it from getting paged out
mdl = IoAllocateMdl(Base, 1, FALSE, FALSE, NULL);
__TRY { MmProbeAndLockPages(mdl, UserMode, IoModifyAccess); todo_wine ok(protection != PAGE_NOACCESS, ...); }
__EXCEPT_PAGE_FAULT { ok(protection == PAGE_NOACCESS, ...); goto Next; }
// the system address is now guaranteed to be valid
todo_wine ok(MmIsAddressValid(MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority), 1), ...);
MmUnlockPages...
Next:
IoFreeMdl...
ZwFreeVirtualMemory...
}
... has a todo with pretty much every ok(), with or without the patch :\
With some luck, the simpler
void test_function()
{
ok(MmIsAddressValid((void*)test_function, ...); // fails in master, succeeds with patch?
ptr = ExAllocatePoolWithTag(NonPagedPool, ...)
ok(MmIsAddressValid(ptr, ...);
ExFreePoolWithTag...
ok(!MmIsAddressValid(NULL), ...);
}
might be enough to show that the patch is correct though.
June 6, 2018
[PATCH] shellpath.c: Fix creation of HOME directory symbolic links
by Rob Walker
Fixes: https://bugs.winehq.org/show_bug.cgi?id=41668 (1)
https://bugs.winehq.org/show_bug.cgi?id=28216 (2)
(1) Introduces a "WINESYMLINK" env variable that allows a user to
control what shell folder links are created to the HOME folder, when
a WINEPREFIX is initially created.
The Wineprefix Shell Folders, that Wine symlinks to the user's HOME directory,
are only (re-)created on each Wine boot if they: do not pre-exist or are broken
symbolic links.
(2) The XDG Directory specification automatically falls back to the user HOME
directory for any XDG_*_DIR that does not exist (xdg-user-dirs-update).
The implemented solution is to block Wine from symlinking directly
to HOME directory.
Test on Gentoo GNU/Linux.
Signed-off-by: Rob Walker <bob.mt.wya(a)gmail.com>
---
dlls/shell32/shellpath.c | 554 ++++++++++++++++++++++++---------------
1 file changed, 343 insertions(+), 211 deletions(-)
diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c
index a551e93aa8..b8c74273c6 100644
--- a/dlls/shell32/shellpath.c
+++ b/dlls/shell32/shellpath.c
@@ -4326,252 +4326,259 @@ static HRESULT _SHRegisterCommonShellFolders(void)
}
/******************************************************************************
- * _SHAppendToUnixPath [Internal]
+ * append_to_unix_path [Internal]
*
- * Helper function for _SHCreateSymbolicLinks. Appends pwszSubPath (or the
- * corresponding resource, if IS_INTRESOURCE) to the unix base path 'szBasePath'
- * and replaces backslashes with slashes.
+ * Helper function for create_home_subdir_symbolic_link.
+ * Appends 'subpath', or the corresponding resource (if it is a
+ * resource identifier), to the Unix base path 'base_dir'.
+ * Replace backslashes with forward slashes.
*
* PARAMS
- * szBasePath [IO] The unix base path, which will be appended to (CP_UNXICP).
- * pwszSubPath [I] Sub-path or resource id (use MAKEINTRESOURCEW).
+ * base_dir [IO] The Unix base path, which will be appended to (CP_UNXICP).
+ * subpath [I] Sub-path or resource id (use MAKEINTRESOURCEW, pre-call).
*
* RETURNS
- * Success: TRUE,
+ * Success: TRUE
* Failure: FALSE
*/
-static inline BOOL _SHAppendToUnixPath(char *szBasePath, LPCWSTR pwszSubPath) {
- WCHAR wszSubPath[MAX_PATH];
- int cLen = strlen(szBasePath);
- char *pBackslash;
-
- if (IS_INTRESOURCE(pwszSubPath)) {
- if (!LoadStringW(shell32_hInstance, LOWORD(pwszSubPath), wszSubPath, MAX_PATH)) {
- /* Fall back to hard coded defaults. */
- switch (LOWORD(pwszSubPath)) {
- case IDS_PERSONAL:
- lstrcpyW(wszSubPath, DocumentsW);
- break;
- case IDS_MYMUSIC:
- lstrcpyW(wszSubPath, My_MusicW);
- break;
- case IDS_MYPICTURES:
- lstrcpyW(wszSubPath, My_PicturesW);
- break;
- case IDS_MYVIDEOS:
- lstrcpyW(wszSubPath, My_VideosW);
- break;
- default:
- ERR("LoadString(%d) failed!\n", LOWORD(pwszSubPath));
- return FALSE;
- }
+static inline BOOL append_to_unix_path(char *base_dir, LPCWSTR subpath)
+{
+ WCHAR ws_subpath[MAX_PATH];
+ int cLen = strlen(base_dir);
+ char *back_slash;
+
+ if (!IS_INTRESOURCE(subpath))
+ {
+ lstrcpyW(ws_subpath, subpath);
+ }
+ else if (!LoadStringW(shell32_hInstance, LOWORD(subpath), ws_subpath, MAX_PATH))
+ {
+ /* Fall back to hard coded defaults. */
+ switch (LOWORD(subpath)) {
+ case IDS_PERSONAL:
+ lstrcpyW(ws_subpath, DocumentsW);
+ break;
+ case IDS_MYMUSIC:
+ lstrcpyW(ws_subpath, My_MusicW);
+ break;
+ case IDS_MYPICTURES:
+ lstrcpyW(ws_subpath, My_PicturesW);
+ break;
+ case IDS_MYVIDEOS:
+ lstrcpyW(ws_subpath, My_VideosW);
+ break;
+ case IDS_DESKTOP:
+ lstrcpyW(ws_subpath, DesktopW);
+ break;
+ default:
+ ERR("LoadString(%d) failed!\n", LOWORD(subpath));
+ return FALSE;
}
- } else {
- lstrcpyW(wszSubPath, pwszSubPath);
}
-
- if (szBasePath[cLen-1] != '/') szBasePath[cLen++] = '/';
-
- if (!WideCharToMultiByte(CP_UNIXCP, 0, wszSubPath, -1, szBasePath + cLen,
+
+ if (!cLen || (base_dir[cLen-1] != '/')) base_dir[cLen++] = '/';
+
+ if (!WideCharToMultiByte(CP_UNIXCP, 0, ws_subpath, -1, base_dir + cLen,
FILENAME_MAX - cLen, NULL, NULL))
{
return FALSE;
}
-
- pBackslash = szBasePath + cLen;
- while ((pBackslash = strchr(pBackslash, '\\'))) *pBackslash = '/';
-
+
+ back_slash = base_dir + cLen;
+ while ((back_slash = strchr(back_slash, '\\'))) *back_slash = '/';
+
return TRUE;
}
/******************************************************************************
- * _SHCreateSymbolicLinks [Internal]
+ * compare_pathft_to_bootft [Internal]
*
- * Sets up symbol links for various shell folders to point into the users home
- * directory. We do an educated guess about what the user would probably want:
- * - If there is a 'My Documents' directory in $HOME, the user probably wants
- * wine's 'My Documents' to point there. Furthermore, we imply that the user
- * is a Windows lover and has no problem with wine creating 'My Pictures',
- * 'My Music' and 'My Videos' subfolders under '$HOME/My Documents', if those
- * do not already exits. We put appropriate symbolic links in place for those,
- * too.
- * - If there is no 'My Documents' directory in $HOME, we let 'My Documents'
- * point directly to $HOME. We assume the user to be a unix hacker who does not
- * want wine to create anything anywhere besides the .wine directory. So, if
- * there already is a 'My Music' directory in $HOME, we symlink the 'My Music'
- * shell folder to it. But if not, then we check XDG_MUSIC_DIR - "well known"
- * directory, and try to link to that. If that fails, then we symlink to
- * $HOME directly. The same holds fo 'My Pictures' and 'My Videos'.
- * - The Desktop shell folder is symlinked to XDG_DESKTOP_DIR. If that does not
- * exist, then we try '$HOME/Desktop'. If that does not exist, then we leave
- * it alone.
- * ('My Music',... above in fact means LoadString(IDS_MYMUSIC))
+ * Function to compare the FILETIME of ws_path (a Windows path) to the (estimated)
+ * Wine System boot time.
+ *
+ * PARAMS
+ * ws_path [I] The Windows path, for which provides the FS write time.
+ * time_difference [O] -1 Windows path last written before time of Wine boot.
+ * 0 Windows path last written at time of Wine boot.
+ * +1 Windows path last written after time of Wine boot.
+ * RETURNS
+ * Success: S_OK
+ * Failure: E_FAIL
+ *
+ * NOTES
+ * Pre-allocate storage for time_difference pointer variable externally.
*/
-static void _SHCreateSymbolicLinks(void)
-{
- UINT aidsMyStuff[] = { IDS_MYPICTURES, IDS_MYVIDEOS, IDS_MYMUSIC }, i;
- const WCHAR* MyOSXStuffW[] = { PicturesW, MoviesW, MusicW };
- int acsidlMyStuff[] = { CSIDL_MYPICTURES, CSIDL_MYVIDEO, CSIDL_MYMUSIC };
- static const char * const xdg_dirs[] = { "PICTURES", "VIDEOS", "MUSIC", "DOCUMENTS", "DESKTOP" };
- static const unsigned int num = ARRAY_SIZE(xdg_dirs);
- WCHAR wszTempPath[MAX_PATH];
- char szPersonalTarget[FILENAME_MAX], *pszPersonal;
- char szMyStuffTarget[FILENAME_MAX], *pszMyStuff;
- char szDesktopTarget[FILENAME_MAX], *pszDesktop;
- struct stat statFolder;
- const char *pszHome;
- HRESULT hr;
- char ** xdg_results;
- char * xdg_desktop_dir;
-
- /* Create all necessary profile sub-dirs up to 'My Documents' and get the unix path. */
- hr = SHGetFolderPathW(NULL, CSIDL_PERSONAL|CSIDL_FLAG_CREATE, NULL,
- SHGFP_TYPE_DEFAULT, wszTempPath);
- if (FAILED(hr)) return;
- pszPersonal = wine_get_unix_file_name(wszTempPath);
- if (!pszPersonal) return;
+static HRESULT compare_pathft_to_bootft(const WCHAR * ws_path, int * time_difference)
+{
+ static ULONG64 time_system_start = 0;
+ SYSTEMTIME system_time_st;
+ FILETIME dummy_ft, system_time_ft, last_write_ft;
+ ULONG64 tick_count, time_last_write;
+ HANDLE fhandle;
+ DWORD ft_errorc = 0;
- hr = XDG_UserDirLookup(xdg_dirs, num, &xdg_results);
- if (FAILED(hr)) xdg_results = NULL;
+ if (!time_difference) return E_FAIL;
- pszHome = getenv("HOME");
- if (pszHome && !stat(pszHome, &statFolder) && S_ISDIR(statFolder.st_mode))
+ if (!time_system_start)
{
- while (1)
+ tick_count = (ULONG64) GetTickCount64();
+ GetSystemTime(&system_time_st);
+ if (!SystemTimeToFileTime( &system_time_st, &system_time_ft))
{
- /* Check if there's already a Wine-specific 'My Documents' folder */
- strcpy(szPersonalTarget, pszHome);
- if (_SHAppendToUnixPath(szPersonalTarget, MAKEINTRESOURCEW(IDS_PERSONAL)) &&
- !stat(szPersonalTarget, &statFolder) && S_ISDIR(statFolder.st_mode))
- {
- /* '$HOME/My Documents' exists. Create 'My Pictures',
- * 'My Videos' and 'My Music' subfolders or fail silently if
- * they already exist.
- */
- for (i = 0; i < ARRAY_SIZE(aidsMyStuff); i++)
- {
- strcpy(szMyStuffTarget, szPersonalTarget);
- if (_SHAppendToUnixPath(szMyStuffTarget, MAKEINTRESOURCEW(aidsMyStuff[i])))
- mkdir(szMyStuffTarget, 0777);
- }
- break;
- }
-
- /* Try to point to the XDG Documents folder */
- if (xdg_results && xdg_results[num-2] &&
- !stat(xdg_results[num-2], &statFolder) &&
- S_ISDIR(statFolder.st_mode))
- {
- strcpy(szPersonalTarget, xdg_results[num-2]);
- break;
- }
-
- /* Or the hardcoded / OS X Documents folder */
- strcpy(szPersonalTarget, pszHome);
- if (_SHAppendToUnixPath(szPersonalTarget, DocumentsW) &&
- !stat(szPersonalTarget, &statFolder) &&
- S_ISDIR(statFolder.st_mode))
- break;
-
- /* As a last resort point to $HOME. */
- strcpy(szPersonalTarget, pszHome);
- break;
+ ERR("SystemTimeToFileTime call failed (%d)\n", GetLastError());
+ return E_FAIL;
}
-
- /* Replace 'My Documents' directory with a symlink or fail silently if not empty. */
- remove(pszPersonal);
- symlink(szPersonalTarget, pszPersonal);
+ time_system_start = (((ULONG64)system_time_ft.dwHighDateTime) << 32)
+ + system_time_ft.dwLowDateTime
+ - (tick_count * 10000);
}
- else
+ fhandle = CreateFileW( ws_path, 0, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if (fhandle == INVALID_HANDLE_VALUE)
{
- /* '$HOME' doesn't exist. Create 'My Pictures', 'My Videos' and 'My Music' subdirs
- * in '%USERPROFILE%\\My Documents' or fail silently if they already exist. */
- pszHome = NULL;
- strcpy(szPersonalTarget, pszPersonal);
- for (i = 0; i < ARRAY_SIZE(aidsMyStuff); i++) {
- strcpy(szMyStuffTarget, szPersonalTarget);
- if (_SHAppendToUnixPath(szMyStuffTarget, MAKEINTRESOURCEW(aidsMyStuff[i])))
- mkdir(szMyStuffTarget, 0777);
- }
+ ERR("Open file handle failed for path: %s (%d)\n",
+ debugstr_w(ws_path), GetLastError());
+ return E_FAIL;
}
-
- /* Create symbolic links for 'My Pictures', 'My Videos' and 'My Music'. */
- for (i=0; i < ARRAY_SIZE(aidsMyStuff); i++)
+ if (!GetFileTime(fhandle, &dummy_ft, &dummy_ft, &last_write_ft))
+ ft_errorc = GetLastError();
+ if (!CloseHandle(fhandle))
{
- /* Create the current 'My Whatever' folder and get its unix path. */
- hr = SHGetFolderPathW(NULL, acsidlMyStuff[i]|CSIDL_FLAG_CREATE, NULL,
- SHGFP_TYPE_DEFAULT, wszTempPath);
- if (FAILED(hr)) continue;
-
- pszMyStuff = wine_get_unix_file_name(wszTempPath);
- if (!pszMyStuff) continue;
-
- while (1)
- {
- /* Check for the Wine-specific '$HOME/My Documents' subfolder */
- strcpy(szMyStuffTarget, szPersonalTarget);
- if (_SHAppendToUnixPath(szMyStuffTarget, MAKEINTRESOURCEW(aidsMyStuff[i])) &&
- !stat(szMyStuffTarget, &statFolder) && S_ISDIR(statFolder.st_mode))
- break;
+ ERR("Close file handle failed: %p (%d)\n",
+ fhandle, GetLastError());
+ return E_FAIL;
+ }
+ if (ft_errorc)
+ {
+ ERR("Get file time failed: %p (%d)\n",
+ fhandle, ft_errorc);
+ return E_FAIL;
+ }
+ time_last_write = (((ULONG64)last_write_ft.dwHighDateTime) << 32)
+ + last_write_ft.dwLowDateTime;
+ *time_difference = ((time_last_write > time_system_start) ? 1 :
+ ((time_last_write < time_system_start) ? -1 :
+ 0));
- /* Try the XDG_XXX_DIR folder */
- if (xdg_results && xdg_results[i])
- {
- strcpy(szMyStuffTarget, xdg_results[i]);
- break;
- }
+ return S_OK;
+}
- /* Or the OS X folder (these are never localized) */
- if (pszHome)
- {
- strcpy(szMyStuffTarget, pszHome);
- if (_SHAppendToUnixPath(szMyStuffTarget, MyOSXStuffW[i]) &&
- !stat(szMyStuffTarget, &statFolder) &&
- S_ISDIR(statFolder.st_mode))
- break;
- }
+/******************************************************************************
+ * create_homedir_symbolic_link [Internal]
+ *
+ * Creates a symbolic link from the current Wineprefix to an appropriate
+ * HOME subdirectory (if one is found).
+ *
+ * Creates 'XXXX' directory in Wineprefix.
+ * Then create a 'My XXXX' symbolic link in Wineprefix:
+ * 1) If '$HOME/XXXX' (IDS directory) exists then target this.
+ * 2) If '$HOME/XXXX' (XDG_XXXX_DIR) exists then target this.
+ * 3) If '$HOME/XXXX' (MacOS XXXX media directory) exists then target this.
+ *
+ * PARAMS
+ * env_enabled [I]
+ * TRUE The user has enabled this Shell Folder to be symlinked (default).
+ * FALSE The user has chosen to disable symlinking this Shell Folder.
+ * The Shell Folder will be created, in the current Wineprefix (if not pre-existing).
+ * ids_dir [I] Windows Resource Identifier code for current Shell Folder.
+ * csidl_dir [I] Constant Special Item ID List identifier for current Shell Folder.
+ * xdg_dir [I] Full path of external Unix XDG directory corresponding to current Shell Folder.
+ * ws_osx_dir [I] Fallback directory name to use, corresponding to current Shell Folder (OSX specific).
+ *
+ */
+void create_homedir_symbolic_link(BOOL env_enabled,
+ UINT ids_dir,
+ int csidl_dir,
+ const char * xdg_dir,
+ const WCHAR * ws_osx_dir)
+{
+ static const char * env_homedir = NULL;
+ WCHAR ws_temp_path[MAX_PATH];
+ char home_target[FILENAME_MAX], * prefix_dir;
+ struct stat stat_folder, stat_home_folder;
+ HRESULT hr;
+ BOOL target_ok;
+ int time_difference;
- /* As a last resort point to the same location as 'My Documents' */
- strcpy(szMyStuffTarget, szPersonalTarget);
- break;
+ hr = SHGetFolderPathW(NULL, csidl_dir, NULL,
+ SHGFP_TYPE_DEFAULT, ws_temp_path);
+ if (SUCCEEDED(hr))
+ {
+ if (ids_dir != IDS_DESKTOPDIRECTORY) return;
+
+ if ((compare_pathft_to_bootft(ws_temp_path, &time_difference) == S_OK)
+ && (time_difference < 0))
+ {
+ TRACE("%s directory created before wineboot\n",
+ debugstr_w(ws_temp_path));
+ return;
}
- remove(pszMyStuff);
- symlink(szMyStuffTarget, pszMyStuff);
- heap_free(pszMyStuff);
}
-
- /* Last but not least, the Desktop folder */
- if (pszHome)
- strcpy(szDesktopTarget, pszHome);
+ else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
+ {
+ hr = SHGetFolderPathW(NULL, csidl_dir|CSIDL_FLAG_CREATE, NULL,
+ SHGFP_TYPE_DEFAULT, ws_temp_path);
+ if (FAILED(hr)) return;
+ }
else
- strcpy(szDesktopTarget, pszPersonal);
- heap_free(pszPersonal);
+ {
+ ERR("Failed to get Wineprefix path corresponding to %d CSIDL\n",
+ csidl_dir);
+ return;
+ }
+ if (!env_enabled) return;
+ prefix_dir = wine_get_unix_file_name(ws_temp_path);
+ if (!prefix_dir)
+ {
+ ERR("Failed to get Unix Wineprefix directory for: %s\n",
+ debugstr_w(ws_temp_path));
+ return;
+ }
+ if (!env_homedir) env_homedir = getenv("HOME");
+ if (!(env_homedir
+ && (stat(env_homedir, &stat_home_folder) != 1)
+ && S_ISDIR(stat_home_folder.st_mode)))
+ {
+ if (prefix_dir) heap_free(prefix_dir);
+ return;
+ }
- xdg_desktop_dir = xdg_results ? xdg_results[num - 1] : NULL;
- if (xdg_desktop_dir ||
- (_SHAppendToUnixPath(szDesktopTarget, DesktopW) &&
- !stat(szDesktopTarget, &statFolder) && S_ISDIR(statFolder.st_mode)))
+ /* Check for:
+ * '$HOME/XXXX' (IDS directory)
+ * or '$HOME/XXXX' (XDG directory)
+ * or '$HOME/XXXX' (MacOS directory)
+ */
+ target_ok = FALSE;
+ strcpy(home_target, env_homedir);
+ if (append_to_unix_path(home_target, MAKEINTRESOURCEW(ids_dir))
+ && (stat(home_target, &stat_folder) != -1)
+ && S_ISDIR(stat_folder.st_mode))
{
- hr = SHGetFolderPathW(NULL, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, NULL,
- SHGFP_TYPE_DEFAULT, wszTempPath);
- if (SUCCEEDED(hr) && (pszDesktop = wine_get_unix_file_name(wszTempPath)))
- {
- remove(pszDesktop);
- if (xdg_desktop_dir)
- symlink(xdg_desktop_dir, pszDesktop);
- else
- symlink(szDesktopTarget, pszDesktop);
- heap_free(pszDesktop);
- }
+ target_ok = TRUE;
+ }
+ else if (xdg_dir && stat(xdg_dir, &stat_folder))
+ {
+ strcpy(home_target, xdg_dir);
+ /* Only link to the XDG directory, if it does not point directly
+ * to the user's HOME directory (XDG specification fallback path). */
+ target_ok = (stat_folder.st_ino != stat_home_folder.st_ino);
+ }
+ else
+ {
+ strcpy(home_target, env_homedir);
+ target_ok = append_to_unix_path(home_target, ws_osx_dir)
+ && (stat(home_target, &stat_folder) != -1)
+ && S_ISDIR(stat_folder.st_mode);
}
- /* Free resources allocated by XDG_UserDirLookup() */
- if (xdg_results)
+ if (target_ok)
{
- for (i = 0; i < num; i++)
- heap_free(xdg_results[i]);
- heap_free(xdg_results);
+ remove(prefix_dir);
+ symlink(home_target, prefix_dir);
}
+
+
+ if (prefix_dir) heap_free(prefix_dir);
}
/******************************************************************************
@@ -6126,15 +6133,139 @@ static void register_system_knownfolders(void)
}
}
+/******************************************************************************
+ * parse_symlinks_env_variable [Internal]
+ *
+ * PARAMS
+ * xdg_dir [I] Unix XDG directory name (without "XDG_" prefix and "_DIR" suffix).
+ *
+ * RETURNS
+ * TRUE "WINESYMLINK" contains the specified XDG directory string.
+ * FALSE "WINESYMLINK" does not contain the specified XDG directory string.
+ * Any error condition.
+ *
+ * Note: "WINESYMLINK", defaults to "ALL", when unset. This enables all symlinks.
+ * "WINESYMLINK" can also be manually set to "ALL", enabling all symlinks.
+ *
+ */
+static BOOL parse_symlinks_env_variable(const char * xdg_dir)
+{
+ static const char * matchall_env_var = "ALL";
+ static char env_var[MAX_PATH+1];
+ static char * env_winesymlink = NULL;
+ char * sstr, * sstr_stop, * tstr, * word_start = NULL;
+ char seperator_ch = '\0';
+ BOOL end_string, in_word = FALSE, matched = FALSE;
+ size_t slength = 0, matchall_length, xdg_dir_slength;
+
+ if (!xdg_dir) return matched;
+
+ if (!env_winesymlink)
+ {
+ env_winesymlink = getenv("WINESYMLINK");
+ if (!env_winesymlink) env_winesymlink = (char*) matchall_env_var;
+ tstr = env_var;
+ sstr_stop = env_winesymlink + MAX_PATH;
+ for (sstr = env_winesymlink; *sstr && (sstr != sstr_stop); ++sstr)
+ {
+ if (!seperator_ch && (ispunct(*sstr) || isspace(*sstr)))
+ seperator_ch = *sstr;
+ if (!isalpha(*sstr)) continue;
+
+ if (seperator_ch && in_word)
+ {
+ *tstr++ = seperator_ch;
+ ++slength;
+ }
+ in_word = TRUE;
+ seperator_ch = '\0';
+ *tstr++ = toupper(*sstr);
+ ++slength;
+ }
+ env_var[slength] = '\0';
+ }
+
+ TRACE("processed env variable: %s\n", debugstr_a(&env_var[0]));
+ matchall_length = strlen(matchall_env_var);
+ xdg_dir_slength = strlen(xdg_dir);
+ end_string = !(env_var[0]);
+ for (sstr = &env_var[0]; !end_string; ++sstr)
+ {
+ end_string = !(*(sstr+1));
+ in_word = isalpha(*sstr);
+ if (in_word && !word_start) word_start = sstr;
+ in_word = in_word && !end_string;
+ if (in_word || !word_start) continue;
+
+ slength = ((size_t) (sstr-word_start))+(end_string ? 1 : 0);
+ matched = ( (slength == xdg_dir_slength) && (strncmp(word_start, xdg_dir, slength) == 0) )
+ || ( (slength == matchall_length) && (strncmp(word_start, "ALL", slength) == 0) );
+ if (matched) break;
+
+ word_start = NULL;
+ }
+ TRACE("%s symlinking for %s\n", matched ? "Enabled" : "Disabled", debugstr_a(xdg_dir));
+
+ return matched;
+}
+
+/******************************************************************************
+ * create_homedir_symbolic_links [Internal]
+ *
+ * Parse WINESYMLINK env variable, for each XDG directory argument. To test if symlinking is
+ * enabled for that XDG directory / Wine Profile Folder.
+ * Then calls the function create_homedir_symbolic_link to potentially symlink from a Shell Folder,
+ * in the current Wineprefix, to a subdirectory of the current user's HOME directory.
+ *
+ * PARAMS
+ * xdg_dirnames [I] Pointer to an array of Unix XDG directory names
+ * (without "XDG_" prefix and "_DIR" suffix).
+ * xdg_dir_count [I] Item count of array (above).
+ *
+ */
+static void create_homedir_symbolic_links(const char * const xdg_dirnames[], const UINT xdg_dir_count)
+{
+ char ** xdg_dirs_array;
+ char * xdg_dir;
+ HRESULT hr;
+ UINT i;
+ BOOL env_enabled;
+
+ if (!xdg_dirnames) return;
+
+ hr = XDG_UserDirLookup(xdg_dirnames, xdg_dir_count, &xdg_dirs_array);
+ if (FAILED(hr)) xdg_dirs_array = NULL;
+
+ for (i = 0; i < xdg_dir_count; ++i)
+ {
+ env_enabled = parse_symlinks_env_variable(xdg_dirnames[i]);
+ xdg_dir = xdg_dirs_array ? xdg_dirs_array[i] : NULL;
+ if (!strcmp(xdg_dirnames[i],"DOCUMENTS"))
+ create_homedir_symbolic_link(env_enabled, IDS_PERSONAL, CSIDL_PERSONAL, xdg_dir, DocumentsW);
+ else if (!strcmp(xdg_dirnames[i],"PICTURES"))
+ create_homedir_symbolic_link(env_enabled, IDS_MYPICTURES, CSIDL_MYPICTURES, xdg_dir, PicturesW);
+ else if (!strcmp(xdg_dirnames[i],"VIDEOS"))
+ create_homedir_symbolic_link(env_enabled, IDS_MYVIDEOS, CSIDL_MYVIDEO, xdg_dir, MoviesW);
+ else if (!strcmp(xdg_dirnames[i],"MUSIC"))
+ create_homedir_symbolic_link(env_enabled, IDS_MYMUSIC, CSIDL_MYMUSIC, xdg_dir, MusicW);
+ else if (!strcmp(xdg_dirnames[i],"DESKTOP"))
+ create_homedir_symbolic_link(env_enabled, IDS_DESKTOPDIRECTORY, CSIDL_DESKTOPDIRECTORY, xdg_dir, DesktopW);
+ else
+ ERR("XDG directory name specifier invalid: %s\n", debugstr_a(xdg_dirnames[i]));
+ if (xdg_dir) heap_free(xdg_dirs_array[i]);
+ }
+ if (xdg_dirs_array) heap_free(xdg_dirs_array);
+}
+
HRESULT SHELL_RegisterShellFolders(void)
{
+ static const char * const xdg_dirnames[] = { "DOCUMENTS", "PICTURES", "VIDEOS", "MUSIC", "DESKTOP" };
+ const UINT xdg_dir_count = 5;
HRESULT hr;
- /* Set up '$HOME' targeted symlinks for 'My Documents', 'My Pictures',
- * 'My Videos', 'My Music' and 'Desktop' in advance, so that the
- * _SHRegister*ShellFolders() functions will find everything nice and clean
- * and thus will not attempt to create them in the profile directory. */
- _SHCreateSymbolicLinks();
+ /* Early setup of symlinks from specific User Shell Folders, in
+ * current Wineprefix, to subdirecties of the user's HOME directory. */
+ create_homedir_symbolic_links(xdg_dirnames, xdg_dir_count);
hr = _SHRegisterUserShellFolders(TRUE);
if (SUCCEEDED(hr))
@@ -6147,5 +6278,6 @@ HRESULT SHELL_RegisterShellFolders(void)
hr = set_folder_attributes();
if (SUCCEEDED(hr))
register_system_knownfolders();
+
return hr;
}
--
2.17.1
June 6, 2018
Re: [PATCH 4/4] msi: Implement deferral for standard and custom actions.
by Marvin
Hi,
While running your changed tests on Windows, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at
https://testbot.winehq.org/JobDetails.pl?Key=39008
Your paranoid android.
=== wvistau64_he (32 bit action) ===
action.c:2676: Test failed: Expected 20180605, got 20180606
action.c:2717: Test failed: Expected 20180605, got 20180606
action.c:2781: Test failed: Expected 20180605, got 20180606
action.c:2822: Test failed: Expected 20180605, got 20180606
June 6, 2018
[PATCH 2/2] schedsvc: Add support for running tasks at specified time.
by Dmitry Timoshkov
Signed-off-by: Dmitry Timoshkov <dmitry(a)baikal.ru>
---
dlls/schedsvc/atsvc.c | 263 +++++++++++++++++++++++++++++++++++++++
dlls/schedsvc/schedsvc_private.h | 2 +
dlls/schedsvc/svc_main.c | 35 +++++-
3 files changed, 296 insertions(+), 4 deletions(-)
diff --git a/dlls/schedsvc/atsvc.c b/dlls/schedsvc/atsvc.c
index 8f6cf03936..91ef3edca0 100644
--- a/dlls/schedsvc/atsvc.c
+++ b/dlls/schedsvc/atsvc.c
@@ -20,6 +20,7 @@
#include <stdarg.h>
+#define NONAMELESSUNION
#include "windef.h"
#include "atsvc.h"
#include "mstask.h"
@@ -90,6 +91,235 @@ static CRITICAL_SECTION_DEBUG cs_debug =
};
static CRITICAL_SECTION at_job_list_section = { &cs_debug, -1, 0, 0, 0, 0 };
+static void filetime_add_ms(FILETIME *ft, LONGLONG ms)
+{
+ union u_ftll
+ {
+ FILETIME ft;
+ LONGLONG ll;
+ } *ftll = (union u_ftll *)ft;
+
+ ftll->ll += ms * (ULONGLONG)10000;
+}
+
+static void filetime_add_minutes(FILETIME *ft, LONG minutes)
+{
+ filetime_add_ms(ft, (LONGLONG)minutes * 60 * 1000);
+}
+
+static void filetime_add_hours(FILETIME *ft, LONG hours)
+{
+ filetime_add_minutes(ft, (LONGLONG)hours * 60);
+}
+
+static void filetime_add_days(FILETIME *ft, LONG days)
+{
+ filetime_add_hours(ft, (LONGLONG)days * 24);
+}
+
+static void filetime_add_weeks(FILETIME *ft, ULONG weeks)
+{
+ filetime_add_days(ft, (LONGLONG)weeks * 7);
+}
+
+static void get_begin_time(const TASK_TRIGGER *trigger, FILETIME *ft)
+{
+ SYSTEMTIME st;
+
+ st.wYear = trigger->wBeginYear;
+ st.wMonth = trigger->wBeginMonth;
+ st.wDay = trigger->wBeginDay;
+ st.wDayOfWeek = 0;
+ st.wHour = 0;
+ st.wMinute = 0;
+ st.wSecond = 0;
+ st.wMilliseconds = 0;
+ SystemTimeToFileTime(&st, ft);
+}
+
+static void get_end_time(const TASK_TRIGGER *trigger, FILETIME *ft)
+{
+ SYSTEMTIME st;
+
+ if (!(trigger->rgFlags & TASK_TRIGGER_FLAG_HAS_END_DATE))
+ {
+ ft->dwHighDateTime = ~0u;
+ ft->dwLowDateTime = ~0u;
+ return;
+ }
+
+ st.wYear = trigger->wEndYear;
+ st.wMonth = trigger->wEndMonth;
+ st.wDay = trigger->wEndDay;
+ st.wDayOfWeek = 0;
+ st.wHour = 0;
+ st.wMinute = 0;
+ st.wSecond = 0;
+ st.wMilliseconds = 0;
+ SystemTimeToFileTime(&st, ft);
+}
+
+static BOOL trigger_get_next_runtime(const TASK_TRIGGER *trigger, const FILETIME *current_ft, FILETIME *rt)
+{
+ SYSTEMTIME st, current_st;
+ FILETIME begin_ft, end_ft, trigger_ft;
+
+ if (trigger->rgFlags & TASK_TRIGGER_FLAG_DISABLED)
+ return FALSE;
+
+ FileTimeToSystemTime(current_ft, ¤t_st);
+
+ get_begin_time(trigger, &begin_ft);
+ get_end_time(trigger, &end_ft);
+
+ switch (trigger->TriggerType)
+ {
+ case TASK_EVENT_TRIGGER_ON_IDLE:
+ case TASK_EVENT_TRIGGER_AT_SYSTEMSTART:
+ case TASK_EVENT_TRIGGER_AT_LOGON:
+ return FALSE;
+
+ case TASK_TIME_TRIGGER_ONCE:
+ st = current_st;
+ st.wHour = trigger->wStartHour;
+ st.wMinute = trigger->wStartMinute;
+ st.wSecond = 0;
+ st.wMilliseconds = 0;
+ SystemTimeToFileTime(&st, &trigger_ft);
+ if (CompareFileTime(&begin_ft, &trigger_ft) <= 0 && CompareFileTime(&trigger_ft, &end_ft) < 0)
+ {
+ *rt = trigger_ft;
+ return TRUE;
+ }
+ break;
+
+ case TASK_TIME_TRIGGER_DAILY:
+ st = current_st;
+ st.wHour = trigger->wStartHour;
+ st.wMinute = trigger->wStartMinute;
+ st.wSecond = 0;
+ st.wMilliseconds = 0;
+ SystemTimeToFileTime(&st, &trigger_ft);
+ while (CompareFileTime(&trigger_ft, &end_ft) < 0)
+ {
+ if (CompareFileTime(&trigger_ft, &begin_ft) >= 0)
+ {
+ *rt = trigger_ft;
+ return TRUE;
+ }
+
+ filetime_add_days(&trigger_ft, trigger->Type.Daily.DaysInterval);
+ }
+ break;
+
+ case TASK_TIME_TRIGGER_WEEKLY:
+ if (!trigger->Type.Weekly.rgfDaysOfTheWeek)
+ break; /* avoid infinite loop */
+
+ st = current_st;
+ st.wHour = trigger->wStartHour;
+ st.wMinute = trigger->wStartMinute;
+ st.wSecond = 0;
+ st.wMilliseconds = 0;
+ SystemTimeToFileTime(&st, &trigger_ft);
+ while (CompareFileTime(&trigger_ft, &end_ft) < 0)
+ {
+ FileTimeToSystemTime(&trigger_ft, &st);
+
+ if (CompareFileTime(&trigger_ft, &begin_ft) >= 0)
+ {
+ if (trigger->Type.Weekly.rgfDaysOfTheWeek & (1 << st.wDayOfWeek))
+ {
+ *rt = trigger_ft;
+ return TRUE;
+ }
+ }
+
+ if (st.wDayOfWeek == 0 && trigger->Type.Weekly.WeeksInterval > 1) /* Sunday, goto next week */
+ filetime_add_weeks(&trigger_ft, trigger->Type.Weekly.WeeksInterval - 1);
+ else /* check next weekday */
+ filetime_add_days(&trigger_ft, 1);
+ }
+ break;
+
+ default:
+ FIXME("trigger type %u is not handled\n", trigger->TriggerType);
+ break;
+ }
+
+ return FALSE;
+}
+
+static BOOL job_get_next_runtime(struct job_t *job, FILETIME *current_ft, FILETIME *next_rt)
+{
+ FILETIME trigger_rt;
+ BOOL have_next_rt = FALSE;
+ USHORT i;
+
+ for (i = 0; i < job->trigger_count; i++)
+ {
+ if (trigger_get_next_runtime(&job->trigger[i], current_ft, &trigger_rt))
+ {
+ if (!have_next_rt || CompareFileTime(&trigger_rt, next_rt) < 0)
+ {
+ *next_rt = trigger_rt;
+ have_next_rt = TRUE;
+ }
+ }
+ }
+
+ return have_next_rt;
+}
+
+/* Returns next runtime in UTC */
+BOOL get_next_runtime(LARGE_INTEGER *rt)
+{
+ FILETIME current_ft, job_rt, next_job_rt;
+ BOOL have_next_rt = FALSE;
+ struct job_t *job;
+
+ GetSystemTimeAsFileTime(¤t_ft);
+ FileTimeToLocalFileTime(¤t_ft, ¤t_ft);
+
+ EnterCriticalSection(&at_job_list_section);
+
+ LIST_FOR_EACH_ENTRY(job, &at_job_list, struct job_t, entry)
+ {
+ if (job_get_next_runtime(job, ¤t_ft, &job_rt))
+ {
+ if (!have_next_rt || CompareFileTime(&job_rt, &next_job_rt) < 0)
+ {
+ next_job_rt = job_rt;
+ have_next_rt = TRUE;
+ }
+ }
+ }
+
+ LeaveCriticalSection(&at_job_list_section);
+
+ if (have_next_rt)
+ {
+ LocalFileTimeToFileTime(&next_job_rt, &next_job_rt);
+ rt->u.LowPart = next_job_rt.dwLowDateTime;
+ rt->u.HighPart = next_job_rt.dwHighDateTime;
+ }
+
+ return have_next_rt;
+}
+
+static BOOL job_runs_at(struct job_t *job, FILETIME *begin_ft, FILETIME *end_ft)
+{
+ FILETIME job_ft;
+
+ if (job_get_next_runtime(job, begin_ft, &job_ft))
+ {
+ if (CompareFileTime(&job_ft, end_ft) < 0)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
static DWORD load_unicode_strings(const char *data, DWORD limit, struct job_t *job)
{
DWORD i, data_size = 0;
@@ -729,6 +959,39 @@ void check_task_state(void)
LeaveCriticalSection(&at_job_list_section);
}
+static void run_job(struct job_t *job)
+{
+ job->data.flags |= 0x04000000;
+ update_job_status(job);
+}
+
+void check_task_time(void)
+{
+ FILETIME current_ft, begin_ft, end_ft;
+ struct job_t *job;
+
+ GetSystemTimeAsFileTime(¤t_ft);
+ FileTimeToLocalFileTime(¤t_ft, ¤t_ft);
+
+ /* Give -1/+1 minute margin */
+ begin_ft = current_ft;
+ filetime_add_minutes(&begin_ft, -1);
+ end_ft = current_ft;
+ filetime_add_minutes(&end_ft, 1);
+
+ EnterCriticalSection(&at_job_list_section);
+
+ LIST_FOR_EACH_ENTRY(job, &at_job_list, struct job_t, entry)
+ {
+ if (job_runs_at(job, &begin_ft, &end_ft))
+ {
+ run_job(job);
+ }
+ }
+
+ LeaveCriticalSection(&at_job_list_section);
+}
+
void remove_job(const WCHAR *name)
{
struct job_t *job;
diff --git a/dlls/schedsvc/schedsvc_private.h b/dlls/schedsvc/schedsvc_private.h
index f5cec2a7cb..d601030e78 100644
--- a/dlls/schedsvc/schedsvc_private.h
+++ b/dlls/schedsvc/schedsvc_private.h
@@ -28,6 +28,8 @@ void remove_job(const WCHAR *name) DECLSPEC_HIDDEN;
void check_task_state(void) DECLSPEC_HIDDEN;
void add_process_to_queue(HANDLE hproc) DECLSPEC_HIDDEN;
void update_process_status(DWORD pid) DECLSPEC_HIDDEN;
+BOOL get_next_runtime(LARGE_INTEGER *rt) DECLSPEC_HIDDEN;
+void check_task_time(void) DECLSPEC_HIDDEN;
static inline WCHAR *heap_strdupW(const WCHAR *src)
{
diff --git a/dlls/schedsvc/svc_main.c b/dlls/schedsvc/svc_main.c
index 2298926193..0dfac818fd 100644
--- a/dlls/schedsvc/svc_main.c
+++ b/dlls/schedsvc/svc_main.c
@@ -46,12 +46,20 @@ static DWORD WINAPI tasks_monitor_thread(void *arg)
{
static const WCHAR tasksW[] = { '\\','T','a','s','k','s','\\',0 };
WCHAR path[MAX_PATH];
- HANDLE htasks, hport;
+ HANDLE htasks, hport, htimer;
JOBOBJECT_ASSOCIATE_COMPLETION_PORT info;
OVERLAPPED ov;
+ LARGE_INTEGER period;
TRACE("Starting...\n");
+ htimer = CreateWaitableTimerW(NULL, FALSE, NULL);
+ if (htimer == NULL)
+ {
+ ERR("CreateWaitableTimer failed\n");
+ return -1;
+ }
+
GetWindowsDirectoryW(path, MAX_PATH);
lstrcatW(path, tasksW);
@@ -98,7 +106,7 @@ static DWORD WINAPI tasks_monitor_thread(void *arg)
FILE_NOTIFY_INFORMATION data;
WCHAR name_buffer[MAX_PATH];
} info;
- HANDLE events[3];
+ HANDLE events[4];
DWORD ret;
/* the buffer must be DWORD aligned */
@@ -115,12 +123,22 @@ static DWORD WINAPI tasks_monitor_thread(void *arg)
FIXME("got multiple entries\n");
events[0] = done_event;
- events[1] = ov.hEvent;
+ events[1] = htimer;
events[2] = hport;
+ events[3] = ov.hEvent;
- ret = WaitForMultipleObjects(3, events, FALSE, INFINITE);
+ ret = WaitForMultipleObjects(4, events, FALSE, INFINITE);
+ /* Done event */
if (ret == WAIT_OBJECT_0) break;
+ /* Next runtime timer */
+ if (ret == WAIT_OBJECT_0 + 1)
+ {
+ check_task_time();
+ continue;
+ }
+
+ /* Job queue */
if (ret == WAIT_OBJECT_0 + 2)
{
DWORD msg;
@@ -139,6 +157,7 @@ static DWORD WINAPI tasks_monitor_thread(void *arg)
continue;
}
+ /* Directory change notification */
info.data.FileName[info.data.FileNameLength/sizeof(WCHAR)] = 0;
switch (info.data.Action)
@@ -176,8 +195,16 @@ static DWORD WINAPI tasks_monitor_thread(void *arg)
}
check_task_state();
+
+ if (get_next_runtime(&period))
+ {
+ if (!SetWaitableTimer(htimer, &period, 0, NULL, NULL, FALSE))
+ ERR("SetWaitableTimer failed\n");
+ }
}
+ CancelWaitableTimer(htimer);
+ CloseHandle(htimer);
CloseHandle(ov.hEvent);
CloseHandle(hport);
CloseHandle(hjob_queue);
--
2.16.3
June 6, 2018
[PATCH 1/2] schedsvc: Read triggers when loading a job file.
by Dmitry Timoshkov
Signed-off-by: Dmitry Timoshkov <dmitry(a)baikal.ru>
---
dlls/schedsvc/atsvc.c | 61 ++++++++++++++++++++++++++++++---------------------
1 file changed, 36 insertions(+), 25 deletions(-)
diff --git a/dlls/schedsvc/atsvc.c b/dlls/schedsvc/atsvc.c
index 9497c900a7..8f6cf03936 100644
--- a/dlls/schedsvc/atsvc.c
+++ b/dlls/schedsvc/atsvc.c
@@ -64,6 +64,8 @@ struct job_t
AT_ENUM info;
FIXDLEN_DATA data;
USHORT instance_count;
+ USHORT trigger_count;
+ TASK_TRIGGER *trigger;
};
struct running_job_t
@@ -143,7 +145,7 @@ static BOOL load_job_data(const char *data, DWORD size, struct job_t *info)
const FIXDLEN_DATA *fixed;
const SYSTEMTIME *st;
DWORD unicode_strings_size, data_size, triggers_size;
- USHORT triggers_count, i;
+ USHORT i;
const USHORT *signature;
const TASK_TRIGGER *trigger;
@@ -202,11 +204,10 @@ static BOOL load_job_data(const char *data, DWORD size, struct job_t *info)
TRACE("no space for triggers count\n");
return FALSE;
}
- triggers_count = *(const USHORT *)(data + fixed->trigger_offset);
- TRACE("triggers_count %u\n", triggers_count);
+ info->trigger_count = *(const USHORT *)(data + fixed->trigger_offset);
+ TRACE("trigger_count %u\n", info->trigger_count);
triggers_size = size - fixed->trigger_offset - sizeof(USHORT);
TRACE("triggers_size %u\n", triggers_size);
- trigger = (const TASK_TRIGGER *)(data + fixed->trigger_offset + sizeof(USHORT));
data += fixed->name_size_offset + unicode_strings_size;
size -= fixed->name_size_offset + unicode_strings_size;
@@ -249,42 +250,51 @@ static BOOL load_job_data(const char *data, DWORD size, struct job_t *info)
/* Trigger Data */
TRACE("trigger_offset %04x, triggers end at %04x\n", fixed->trigger_offset,
- (DWORD)(fixed->trigger_offset + sizeof(USHORT) + triggers_count * sizeof(TASK_TRIGGER)));
+ (DWORD)(fixed->trigger_offset + sizeof(USHORT) + info->trigger_count * sizeof(TASK_TRIGGER)));
- triggers_count = *(const USHORT *)data;
- TRACE("triggers_count %u\n", triggers_count);
+ info->trigger_count = *(const USHORT *)data;
+ TRACE("trigger_count %u\n", info->trigger_count);
trigger = (const TASK_TRIGGER *)(data + sizeof(USHORT));
- if (triggers_count * sizeof(TASK_TRIGGER) > triggers_size)
+ if (info->trigger_count * sizeof(TASK_TRIGGER) > triggers_size)
{
TRACE("no space for triggers data\n");
return FALSE;
}
- for (i = 0; i < triggers_count; i++)
+ info->trigger = heap_alloc(info->trigger_count * sizeof(info->trigger[0]));
+ if (!info->trigger)
+ {
+ TRACE("not enough memory for trigger data\n");
+ return FALSE;
+ }
+
+ for (i = 0; i < info->trigger_count; i++)
{
TRACE("%u: cbTriggerSize = %#x\n", i, trigger[i].cbTriggerSize);
if (trigger[i].cbTriggerSize != sizeof(TASK_TRIGGER))
TRACE("invalid cbTriggerSize\n");
TRACE("Reserved1 = %#x\n", trigger[i].Reserved1);
- TRACE("wBeginYear = %u\n", trigger->wBeginYear);
- TRACE("wBeginMonth = %u\n", trigger->wBeginMonth);
- TRACE("wBeginDay = %u\n", trigger->wBeginDay);
- TRACE("wEndYear = %u\n", trigger->wEndYear);
- TRACE("wEndMonth = %u\n", trigger->wEndMonth);
- TRACE("wEndDay = %u\n", trigger->wEndDay);
- TRACE("wStartHour = %u\n", trigger->wStartHour);
- TRACE("wStartMinute = %u\n", trigger->wStartMinute);
- TRACE("MinutesDuration = %u\n", trigger->MinutesDuration);
- TRACE("MinutesInterval = %u\n", trigger->MinutesInterval);
- TRACE("rgFlags = %u\n", trigger->rgFlags);
- TRACE("TriggerType = %u\n", trigger->TriggerType);
- TRACE("Reserved2 = %u\n", trigger->Reserved2);
- TRACE("wRandomMinutesInterval = %u\n", trigger->wRandomMinutesInterval);
+ TRACE("wBeginYear = %u\n", trigger[i].wBeginYear);
+ TRACE("wBeginMonth = %u\n", trigger[i].wBeginMonth);
+ TRACE("wBeginDay = %u\n", trigger[i].wBeginDay);
+ TRACE("wEndYear = %u\n", trigger[i].wEndYear);
+ TRACE("wEndMonth = %u\n", trigger[i].wEndMonth);
+ TRACE("wEndDay = %u\n", trigger[i].wEndDay);
+ TRACE("wStartHour = %u\n", trigger[i].wStartHour);
+ TRACE("wStartMinute = %u\n", trigger[i].wStartMinute);
+ TRACE("MinutesDuration = %u\n", trigger[i].MinutesDuration);
+ TRACE("MinutesInterval = %u\n", trigger[i].MinutesInterval);
+ TRACE("rgFlags = %u\n", trigger[i].rgFlags);
+ TRACE("TriggerType = %u\n", trigger[i].TriggerType);
+ TRACE("Reserved2 = %u\n", trigger[i].Reserved2);
+ TRACE("wRandomMinutesInterval = %u\n", trigger[i].wRandomMinutesInterval);
+
+ info->trigger[i] = trigger[i];
}
- size -= sizeof(USHORT) + triggers_count * sizeof(TASK_TRIGGER);
- data += sizeof(USHORT) + triggers_count * sizeof(TASK_TRIGGER);
+ size -= sizeof(USHORT) + info->trigger_count * sizeof(TASK_TRIGGER);
+ data += sizeof(USHORT) + info->trigger_count * sizeof(TASK_TRIGGER);
if (size < 2 * sizeof(USHORT) + 64)
{
@@ -353,6 +363,7 @@ static void free_job(struct job_t *job)
heap_free(job->name);
heap_free(job->params);
heap_free(job->curdir);
+ heap_free(job->trigger);
heap_free(job);
}
--
2.16.3
June 6, 2018
[PATCH 4/4] msi: Implement deferral for standard and custom actions.
by Zebediah Figura
Fixes https://bugs.winehq.org/show_bug.cgi?id=34989.
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
Tested for regressions against winetricks-test and Microsoft Office 2010.
dlls/msi/action.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++--
dlls/msi/assembly.c | 6 ++++
dlls/msi/classes.c | 24 +++++++++++++
dlls/msi/custom.c | 1 +
dlls/msi/files.c | 18 ++++++++++
dlls/msi/font.c | 6 ++++
dlls/msi/msipriv.h | 1 +
dlls/msi/tests/custom.c | 70 +------------------------------------
dlls/msi/tests/install.c | 1 -
9 files changed, 143 insertions(+), 73 deletions(-)
diff --git a/dlls/msi/action.c b/dlls/msi/action.c
index 7c71800..b22be7a 100644
--- a/dlls/msi/action.c
+++ b/dlls/msi/action.c
@@ -105,8 +105,6 @@ static const WCHAR szIsolateComponents[] =
{'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
static const WCHAR szMigrateFeatureStates[] =
{'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
-static const WCHAR szMsiUnpublishAssemblies[] =
- {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
static const WCHAR szInstallODBC[] =
{'I','n','s','t','a','l','l','O','D','B','C',0};
static const WCHAR szInstallServices[] =
@@ -824,6 +822,9 @@ static UINT ACTION_CreateFolders(MSIPACKAGE *package)
MSIQUERY *view;
UINT rc;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szCreateFolders);
+
rc = MSI_DatabaseOpenViewW( package->db, query, &view );
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
@@ -903,6 +904,9 @@ static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
MSIQUERY *view;
UINT rc;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szRemoveFolders);
+
rc = MSI_DatabaseOpenViewW( package->db, query, &view );
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
@@ -2977,6 +2981,9 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
MSIQUERY *view;
UINT rc;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szWriteRegistryValues);
+
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
@@ -3211,6 +3218,9 @@ static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
MSIQUERY *view;
UINT rc;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szRemoveRegistryValues);
+
rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
if (rc == ERROR_SUCCESS)
{
@@ -3529,9 +3539,13 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
TRACE("\n");
- squash_guid( package->ProductCode, squashed_pc );
msi_set_sourcedir_props(package, FALSE);
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szProcessComponents);
+
+ squash_guid( package->ProductCode, squashed_pc );
+
LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
{
MSIRECORD *uirow;
@@ -3805,6 +3819,9 @@ static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
MSIQUERY *view;
UINT rc;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szRegisterTypeLibraries);
+
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
@@ -3866,6 +3883,9 @@ static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
MSIQUERY *view;
UINT rc;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szUnregisterTypeLibraries);
+
rc = MSI_DatabaseOpenViewW( package->db, query, &view );
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
@@ -4050,6 +4070,9 @@ static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
HRESULT res;
UINT rc;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szCreateShortcuts);
+
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
@@ -4103,6 +4126,9 @@ static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
MSIQUERY *view;
UINT rc;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szRemoveShortcuts);
+
rc = MSI_DatabaseOpenViewW( package->db, query, &view );
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
@@ -4474,6 +4500,9 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package)
HKEY hukey = NULL, hudkey = NULL;
MSIRECORD *uirow;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szPublishProduct);
+
if (!list_empty(&package->patches))
{
rc = msi_publish_patches(package);
@@ -4636,6 +4665,9 @@ static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
MSIQUERY *view;
UINT rc;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szWriteIniValues);
+
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
@@ -4779,6 +4811,9 @@ static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
MSIQUERY *view;
UINT rc;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szRemoveIniValues);
+
rc = MSI_DatabaseOpenViewW( package->db, query, &view );
if (rc == ERROR_SUCCESS)
{
@@ -4864,6 +4899,9 @@ static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
MSIQUERY *view;
UINT rc;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szSelfRegModules);
+
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
@@ -4914,6 +4952,9 @@ static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
MSIQUERY *view;
UINT rc;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szSelfUnregModules);
+
rc = MSI_DatabaseOpenViewW( package->db, query, &view );
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
@@ -4929,6 +4970,9 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
UINT rc;
HKEY hkey = NULL, userdata = NULL;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szPublishFeatures);
+
if (!msi_check_publish(package))
return ERROR_SUCCESS;
@@ -5069,6 +5113,9 @@ static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
{
MSIFEATURE *feature;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szUnpublishFeatures);
+
if (!msi_check_unpublish(package))
return ERROR_SUCCESS;
@@ -5221,6 +5268,9 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
HKEY hkey, props, upgrade_key;
UINT rc;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szRegisterProduct);
+
/* FIXME: also need to publish if the product is in advertise mode */
if (!msi_check_publish(package))
return ERROR_SUCCESS;
@@ -5538,6 +5588,9 @@ static UINT ACTION_RegisterUser(MSIPACKAGE *package)
{0},
};
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szRegisterUser);
+
if (msi_check_unpublish(package))
{
MSIREG_DeleteUserDataProductKey(package->ProductCode, package->Context);
@@ -5860,6 +5913,9 @@ static UINT ACTION_PublishComponents(MSIPACKAGE *package)
MSIQUERY *view;
UINT rc;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szPublishComponents);
+
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
@@ -5932,6 +5988,9 @@ static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
MSIQUERY *view;
UINT rc;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szUnpublishComponents);
+
rc = MSI_DatabaseOpenViewW( package->db, query, &view );
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
@@ -6080,6 +6139,9 @@ static UINT ACTION_InstallServices( MSIPACKAGE *package )
MSIQUERY *view;
UINT rc;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szInstallServices);
+
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
@@ -6251,6 +6313,9 @@ static UINT ACTION_StartServices( MSIPACKAGE *package )
MSIQUERY *view;
UINT rc;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szStartServices);
+
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
@@ -6414,6 +6479,9 @@ static UINT ACTION_StopServices( MSIPACKAGE *package )
MSIQUERY *view;
UINT rc;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szStopServices);
+
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
@@ -6497,6 +6565,9 @@ static UINT ACTION_DeleteServices( MSIPACKAGE *package )
MSIQUERY *view;
UINT rc;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szDeleteServices);
+
rc = MSI_DatabaseOpenViewW( package->db, query, &view );
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
@@ -6767,6 +6838,9 @@ static UINT ACTION_InstallODBC( MSIPACKAGE *package )
MSIQUERY *view;
UINT rc;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szInstallODBC);
+
rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
if (rc == ERROR_SUCCESS)
{
@@ -6945,6 +7019,9 @@ static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
MSIQUERY *view;
UINT rc;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szRemoveODBC);
+
rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
if (rc == ERROR_SUCCESS)
{
@@ -7291,6 +7368,9 @@ static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
MSIQUERY *view;
UINT rc;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szWriteEnvironmentStrings);
+
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
@@ -7433,6 +7513,9 @@ static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
MSIQUERY *view;
UINT rc;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szRemoveEnvironmentStrings);
+
rc = MSI_DatabaseOpenViewW( package->db, query, &view );
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
diff --git a/dlls/msi/assembly.c b/dlls/msi/assembly.c
index bccd114..59fd332 100644
--- a/dlls/msi/assembly.c
+++ b/dlls/msi/assembly.c
@@ -652,6 +652,9 @@ UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
{
MSICOMPONENT *comp;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szMsiPublishAssemblies);
+
LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
{
LONG res;
@@ -717,6 +720,9 @@ UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
{
MSICOMPONENT *comp;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szMsiUnpublishAssemblies);
+
LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
{
LONG res;
diff --git a/dlls/msi/classes.c b/dlls/msi/classes.c
index 60cc3c1..293aa10 100644
--- a/dlls/msi/classes.c
+++ b/dlls/msi/classes.c
@@ -753,6 +753,9 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
MSICLASS *cls;
UINT r;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szRegisterClassInfo);
+
r = load_classes_and_such( package );
if (r != ERROR_SUCCESS)
return r;
@@ -918,6 +921,9 @@ UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
HKEY hkey, hkey2;
UINT r;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szUnregisterClassInfo);
+
r = load_classes_and_such( package );
if (r != ERROR_SUCCESS)
return r;
@@ -1083,6 +1089,9 @@ UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
MSIRECORD *uirow;
UINT r;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szRegisterProgIdInfo);
+
r = load_classes_and_such( package );
if (r != ERROR_SUCCESS)
return r;
@@ -1143,6 +1152,9 @@ UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
LONG res;
UINT r;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szUnregisterProgIdInfo);
+
r = load_classes_and_such( package );
if (r != ERROR_SUCCESS)
return r;
@@ -1255,6 +1267,9 @@ UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package)
LONG res;
UINT r;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szRegisterExtensionInfo);
+
r = load_classes_and_such( package );
if (r != ERROR_SUCCESS)
return r;
@@ -1363,6 +1378,9 @@ UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
LONG res;
UINT r;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szUnregisterExtensionInfo);
+
r = load_classes_and_such( package );
if (r != ERROR_SUCCESS)
return r;
@@ -1446,6 +1464,9 @@ UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package)
MSIMIME *mt;
UINT r;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szRegisterMIMEInfo);
+
r = load_classes_and_such( package );
if (r != ERROR_SUCCESS)
return r;
@@ -1500,6 +1521,9 @@ UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
MSIMIME *mime;
UINT r;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szUnregisterMIMEInfo);
+
r = load_classes_and_such( package );
if (r != ERROR_SUCCESS)
return r;
diff --git a/dlls/msi/custom.c b/dlls/msi/custom.c
index 8deebe5..2d66409 100644
--- a/dlls/msi/custom.c
+++ b/dlls/msi/custom.c
@@ -1159,6 +1159,7 @@ static BOOL action_type_matches_script( UINT type, UINT script )
switch (script)
{
case SCRIPT_NONE:
+ return FALSE;
case SCRIPT_INSTALL:
return !(type & msidbCustomActionTypeCommit) && !(type & msidbCustomActionTypeRollback);
case SCRIPT_COMMIT:
diff --git a/dlls/msi/files.c b/dlls/msi/files.c
index f6cf3e7..5a88c14 100644
--- a/dlls/msi/files.c
+++ b/dlls/msi/files.c
@@ -359,6 +359,9 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
msi_set_sourcedir_props(package, FALSE);
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szInstallFiles);
+
schedule_install_files(package);
mi = msi_alloc_zero( sizeof(MSIMEDIAINFO) );
@@ -584,6 +587,9 @@ UINT ACTION_PatchFiles( MSIPACKAGE *package )
TRACE("%p\n", package);
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szPatchFiles);
+
mi = msi_alloc_zero( sizeof(MSIMEDIAINFO) );
TRACE("extracting files\n");
@@ -1002,6 +1008,9 @@ UINT ACTION_MoveFiles( MSIPACKAGE *package )
MSIQUERY *view;
UINT rc;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szMoveFiles);
+
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
@@ -1134,6 +1143,9 @@ UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
MSIQUERY *view;
UINT rc;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szDuplicateFiles);
+
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
@@ -1210,6 +1222,9 @@ UINT ACTION_RemoveDuplicateFiles( MSIPACKAGE *package )
MSIQUERY *view;
UINT rc;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szRemoveDuplicateFiles);
+
rc = MSI_DatabaseOpenViewW( package->db, query, &view );
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
@@ -1350,6 +1365,9 @@ UINT ACTION_RemoveFiles( MSIPACKAGE *package )
MSIFILE *file;
UINT r;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szRemoveFiles);
+
r = MSI_DatabaseOpenViewW(package->db, query, &view);
if (r == ERROR_SUCCESS)
{
diff --git a/dlls/msi/font.c b/dlls/msi/font.c
index 5c1e59d..fc05006 100644
--- a/dlls/msi/font.c
+++ b/dlls/msi/font.c
@@ -294,6 +294,9 @@ UINT ACTION_RegisterFonts(MSIPACKAGE *package)
MSIQUERY *view;
UINT rc;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szRegisterFonts);
+
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
@@ -374,6 +377,9 @@ UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
MSIQUERY *view;
UINT r;
+ if (package->script == SCRIPT_NONE)
+ return msi_schedule_action(package, SCRIPT_INSTALL, szUnregisterFonts);
+
r = MSI_DatabaseOpenViewW( package->db, query, &view );
if (r != ERROR_SUCCESS)
return ERROR_SUCCESS;
diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h
index 8acace3..93c4cea 100644
--- a/dlls/msi/msipriv.h
+++ b/dlls/msi/msipriv.h
@@ -1180,6 +1180,7 @@ static const WCHAR szWow6432NodeCLSID[] = {'W','o','w','6','4','3','2','N','o','
static const WCHAR szStreams[] = {'_','S','t','r','e','a','m','s',0};
static const WCHAR szStorages[] = {'_','S','t','o','r','a','g','e','s',0};
static const WCHAR szMsiPublishAssemblies[] = {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
+static const WCHAR szMsiUnpublishAssemblies[] = {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
static const WCHAR szCostingComplete[] = {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0};
static const WCHAR szTempFolder[] = {'T','e','m','p','F','o','l','d','e','r',0};
static const WCHAR szDatabase[] = {'D','A','T','A','B','A','S','E',0};
diff --git a/dlls/msi/tests/custom.c b/dlls/msi/tests/custom.c
index 4d45c9e..cf1289e 100644
--- a/dlls/msi/tests/custom.c
+++ b/dlls/msi/tests/custom.c
@@ -1163,52 +1163,42 @@ static BOOL pf_exists(const char *file)
UINT WINAPI cf_present(MSIHANDLE hinst)
{
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
ok(hinst, pf_exists("msitest\\first"), "folder absent\n");
ok(hinst, pf_exists("msitest\\second"), "folder absent\n");
ok(hinst, pf_exists("msitest\\third"), "folder absent\n");
-}
return ERROR_SUCCESS;
}
UINT WINAPI cf_absent(MSIHANDLE hinst)
{
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
ok(hinst, !pf_exists("msitest\\first"), "folder present\n");
ok(hinst, !pf_exists("msitest\\second"), "folder present\n");
ok(hinst, !pf_exists("msitest\\third"), "folder present\n");
-}
return ERROR_SUCCESS;
}
UINT WINAPI file_present(MSIHANDLE hinst)
{
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
ok(hinst, pf_exists("msitest\\first\\one.txt"), "file absent\n");
ok(hinst, pf_exists("msitest\\second\\two.txt"), "file absent\n");
-}
return ERROR_SUCCESS;
}
UINT WINAPI file_absent(MSIHANDLE hinst)
{
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
ok(hinst, !pf_exists("msitest\\first\\one.txt"), "file present\n");
ok(hinst, !pf_exists("msitest\\second\\two.txt"), "file present\n");
-}
return ERROR_SUCCESS;
}
UINT WINAPI crs_present(MSIHANDLE hinst)
{
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED))
ok(hinst, pf_exists("msitest\\shortcut.lnk"), "shortcut absent\n");
return ERROR_SUCCESS;
}
UINT WINAPI crs_absent(MSIHANDLE hinst)
{
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED))
ok(hinst, !pf_exists("msitest\\shortcut.lnk"), "shortcut present\n");
return ERROR_SUCCESS;
}
@@ -1218,7 +1208,6 @@ UINT WINAPI sds_present(MSIHANDLE hinst)
SC_HANDLE manager, service;
manager = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);
service = OpenServiceA(manager, "TestService3", GENERIC_ALL);
-todo_wine
ok(hinst, !!service, "service absent: %u\n", GetLastError());
CloseServiceHandle(service);
CloseServiceHandle(manager);
@@ -1252,7 +1241,6 @@ UINT WINAPI sis_absent(MSIHANDLE hinst)
SC_HANDLE manager, service;
manager = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);
service = OpenServiceA(manager, "TestService", GENERIC_ALL);
-todo_wine
ok(hinst, !service, "service present\n");
if (service) CloseServiceHandle(service);
CloseServiceHandle(manager);
@@ -1269,7 +1257,6 @@ UINT WINAPI sss_started(MSIHANDLE hinst)
service = OpenServiceA(manager, "Spooler", SC_MANAGER_ALL_ACCESS);
ret = QueryServiceStatus(service, &status);
ok(hinst, ret, "QueryServiceStatus failed: %u\n", GetLastError());
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED))
ok(hinst, status.dwCurrentState == SERVICE_RUNNING, "got %u\n", status.dwCurrentState);
CloseServiceHandle(service);
@@ -1296,10 +1283,8 @@ UINT WINAPI sss_stopped(MSIHANDLE hinst)
UINT WINAPI rd_present(MSIHANDLE hinst)
{
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
ok(hinst, pf_exists("msitest\\original2.txt"), "file absent\n");
ok(hinst, pf_exists("msitest\\duplicate.txt"), "file absent\n");
-}
ok(hinst, !pf_exists("msitest\\original3.txt"), "file present\n");
ok(hinst, !pf_exists("msitest\\duplicate2.txt"), "file present\n");
return ERROR_SUCCESS;
@@ -1307,10 +1292,8 @@ todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
UINT WINAPI rd_absent(MSIHANDLE hinst)
{
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
ok(hinst, !pf_exists("msitest\\original2.txt"), "file present\n");
ok(hinst, !pf_exists("msitest\\duplicate.txt"), "file present\n");
-}
ok(hinst, !pf_exists("msitest\\original3.txt"), "file present\n");
ok(hinst, !pf_exists("msitest\\duplicate2.txt"), "file present\n");
return ERROR_SUCCESS;
@@ -1333,10 +1316,8 @@ UINT WINAPI odbc_present(MSIHANDLE hinst)
if (!strcmp(p, "ODBC test driver2"))
gotdriver2 = 1;
}
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
ok(hinst, gotdriver, "driver absent\n");
ok(hinst, gotdriver2, "driver 2 absent\n");
-}
return ERROR_SUCCESS;
}
@@ -1357,10 +1338,8 @@ UINT WINAPI odbc_absent(MSIHANDLE hinst)
if (!strcmp(p, "ODBC test driver2"))
gotdriver2 = 1;
}
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
ok(hinst, !gotdriver, "driver present\n");
ok(hinst, !gotdriver2, "driver 2 present\n");
-}
return ERROR_SUCCESS;
}
@@ -1373,10 +1352,8 @@ UINT WINAPI mov_present(MSIHANDLE hinst)
UINT WINAPI mov_absent(MSIHANDLE hinst)
{
-todo_wine {
ok(hinst, !pf_exists("msitest\\canada"), "file present\n");
ok(hinst, !pf_exists("msitest\\dominica"), "file present\n");
-}
return ERROR_SUCCESS;
}
@@ -1410,9 +1387,7 @@ UINT WINAPI pa_present(MSIHANDLE hinst)
res = RegOpenKeyA(HKEY_CURRENT_USER, path_dotnet, &key);
ok(hinst, !res, "got %d\n", res);
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
check_reg_str(hinst, key, name_dotnet, "rcHQPHq?CA(a)Uv-XqMI1e>Z'q,T*76M@=YEg6My?~]");
-}
RegCloseKey(key);
return ERROR_SUCCESS;
@@ -1427,9 +1402,7 @@ UINT WINAPI pa_absent(MSIHANDLE hinst)
ok(hinst, !res || res == ERROR_FILE_NOT_FOUND, "got %d\n", res);
if (!res)
{
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
check_reg_str(hinst, key, name_dotnet, NULL);
-}
RegCloseKey(key);
}
return ERROR_SUCCESS;
@@ -1462,7 +1435,6 @@ UINT WINAPI ppc_absent(MSIHANDLE hinst)
UINT r;
r = RegOpenKeyExA(HKEY_LOCAL_MACHINE, ppc_key, 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &key);
-todo_wine
ok(hinst, r == ERROR_FILE_NOT_FOUND, "got %u\n", r);
return ERROR_SUCCESS;
}
@@ -1474,12 +1446,10 @@ UINT WINAPI pub_present(MSIHANDLE hinst)
HKEY key;
LONG res;
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
res = RegOpenKeyA(HKEY_CURRENT_USER, pub_key, &key);
ok(hinst, !res, "got %u\n", res);
res = RegQueryValueExA(key, "english.txt", NULL, NULL, NULL, NULL);
ok(hinst, !res, "got %u\n", res);
-}
RegCloseKey(key);
return ERROR_SUCCESS;
}
@@ -1490,7 +1460,6 @@ UINT WINAPI pub_absent(MSIHANDLE hinst)
LONG res;
res = RegOpenKeyA(HKEY_CURRENT_USER, pub_key, &key);
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED))
ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %u\n", res);
return ERROR_SUCCESS;
}
@@ -1504,7 +1473,6 @@ UINT WINAPI pf_present(MSIHANDLE hinst)
HKEY key;
LONG res;
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
res = RegOpenKeyExA(HKEY_CLASSES_ROOT, pf_classkey, 0, KEY_READ | KEY_WOW64_64KEY, &key);
ok(hinst, !res, "got %u\n", res);
check_reg_str(hinst, key, "feature", "");
@@ -1516,7 +1484,6 @@ todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
check_reg_str(hinst, key, "feature", "VGtfp^p+,?82(a)JU1j_KE");
check_reg_str(hinst, key, "montecristo", "VGtfp^p+,?82(a)JU1j_KE");
RegCloseKey(key);
-}
return ERROR_SUCCESS;
}
@@ -1527,11 +1494,9 @@ UINT WINAPI pf_absent(MSIHANDLE hinst)
LONG res;
res = RegOpenKeyExA(HKEY_CLASSES_ROOT, pf_classkey, 0, KEY_READ | KEY_WOW64_64KEY, &key);
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED))
ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %u\n", res);
res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, pf_userkey, 0, KEY_READ | KEY_WOW64_64KEY, &key);
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED))
ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %u\n", res);
return ERROR_SUCCESS;
@@ -1560,7 +1525,6 @@ UINT WINAPI pp_absent(MSIHANDLE hinst)
LONG res;
res = RegOpenKeyExA(HKEY_CLASSES_ROOT, pp_prodkey, 0, KEY_READ | KEY_WOW64_64KEY, &key);
-todo_wine
ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %u\n", res);
return ERROR_SUCCESS;
@@ -1571,7 +1535,6 @@ UINT WINAPI rci_present(MSIHANDLE hinst)
HKEY key;
LONG res;
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
res = RegOpenKeyExA(HKEY_CLASSES_ROOT, "CLSID\\{110913E7-86D1-4BF3-9922-BA103FCDDDFA}",
0, KEY_READ | KEY_WOW64_32KEY, &key);
ok(hinst, !res, "got %u\n", res);
@@ -1584,7 +1547,6 @@ todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
res = RegOpenKeyA(HKEY_CLASSES_ROOT, "AppID\\{CFCC3B38-E683-497D-9AB4-CB40AAFE307F}", &key);
ok(hinst, !res, "got %u\n", res);
RegCloseKey(key);
-}
return ERROR_SUCCESS;
}
@@ -1594,7 +1556,6 @@ UINT WINAPI rci_absent(MSIHANDLE hinst)
HKEY key;
LONG res;
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
res = RegOpenKeyExA(HKEY_CLASSES_ROOT, "CLSID\\{110913E7-86D1-4BF3-9922-BA103FCDDDFA}",
0, KEY_READ | KEY_WOW64_32KEY, &key);
ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %u\n", res);
@@ -1604,7 +1565,6 @@ todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
res = RegOpenKeyA(HKEY_CLASSES_ROOT, "AppID\\{CFCC3B38-E683-497D-9AB4-CB40AAFE307F}", &key);
ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %u\n", res);
-}
return ERROR_SUCCESS;
}
@@ -1614,7 +1574,6 @@ UINT WINAPI rei_present(MSIHANDLE hinst)
HKEY key;
LONG res;
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
res = RegOpenKeyA(HKEY_CLASSES_ROOT, ".extension", &key);
ok(hinst, !res, "got %u\n", res);
RegCloseKey(key);
@@ -1622,7 +1581,6 @@ todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Prog.Id.1\\shell\\Open\\command", &key);
ok(hinst, !res, "got %u\n", res);
RegCloseKey(key);
-}
return ERROR_SUCCESS;
}
@@ -1632,13 +1590,11 @@ UINT WINAPI rei_absent(MSIHANDLE hinst)
HKEY key;
LONG res;
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
res = RegOpenKeyA(HKEY_CLASSES_ROOT, ".extension", &key);
ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %u\n", res);
res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Prog.Id.1\\shell\\Open\\command", &key);
ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %u\n", res);
-}
return ERROR_SUCCESS;
}
@@ -1653,7 +1609,6 @@ UINT WINAPI font_present(MSIHANDLE hinst)
res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, font_key, 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &key);
ok(hinst, !res, "got %u\n", res);
res = RegQueryValueExA(key, "msi test font", NULL, NULL, NULL, NULL);
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED))
ok(hinst, !res, "got %u\n", res);
RegCloseKey(key);
@@ -1667,9 +1622,7 @@ UINT WINAPI font_absent(MSIHANDLE hinst)
res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, font_key, 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &key);
ok(hinst, !res, "got %u\n", res);
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
check_reg_str(hinst, key, "msi test font", NULL);
-}
RegCloseKey(key);
return ERROR_SUCCESS;
@@ -1681,7 +1634,6 @@ UINT WINAPI rmi_present(MSIHANDLE hinst)
LONG res;
res = RegOpenKeyA(HKEY_CLASSES_ROOT, "MIME\\Database\\Content Type\\mime/type", &key);
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED))
ok(hinst, !res, "got %u\n", res);
return ERROR_SUCCESS;
@@ -1693,7 +1645,6 @@ UINT WINAPI rmi_absent(MSIHANDLE hinst)
LONG res;
res = RegOpenKeyA(HKEY_CLASSES_ROOT, "MIME\\Database\\Content Type\\mime/type", &key);
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED))
ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %u\n", res);
return ERROR_SUCCESS;
@@ -1721,7 +1672,6 @@ UINT WINAPI rp_absent(MSIHANDLE hinst)
LONG res;
res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, rp_key, 0, KEY_READ | KEY_WOW64_32KEY, &key);
-todo_wine
ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %u\n", res);
return ERROR_SUCCESS;
@@ -1732,7 +1682,6 @@ UINT WINAPI rpi_present(MSIHANDLE hinst)
HKEY key;
LONG res;
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
res = RegOpenKeyExA(HKEY_CLASSES_ROOT, "CLSID\\{110913E7-86D1-4BF3-9922-BA103FCDDDFA}",
0, KEY_READ | KEY_WOW64_32KEY, &key);
ok(hinst, !res, "got %u\n", res);
@@ -1749,7 +1698,6 @@ todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.Class.2", &key);
ok(hinst, !res, "got %u\n", res);
RegCloseKey(key);
-}
return ERROR_SUCCESS;
}
@@ -1759,7 +1707,6 @@ UINT WINAPI rpi_absent(MSIHANDLE hinst)
HKEY key;
LONG res;
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
res = RegOpenKeyExA(HKEY_CLASSES_ROOT, "CLSID\\{110913E7-86D1-4BF3-9922-BA103FCDDDFA}",
0, KEY_READ | KEY_WOW64_32KEY, &key);
ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %u\n", res);
@@ -1772,7 +1719,6 @@ todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.Class.2", &key);
ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %u\n", res);
-}
return ERROR_SUCCESS;
}
@@ -1799,7 +1745,6 @@ UINT WINAPI ru_absent(MSIHANDLE hinst)
LONG res;
res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, ru_key, 0, KEY_READ | KEY_WOW64_64KEY, &key);
-todo_wine
ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %u\n", res);
return ERROR_SUCCESS;
@@ -1814,10 +1759,8 @@ UINT WINAPI tl_present(MSIHANDLE hinst)
HRESULT hr;
hr = LoadRegTypeLib(&LIBID_register_test, 7, 1, 0, &tlb);
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED))
ok(hinst, hr == S_OK, "got %#x\n", hr);
- if (tlb)
- ITypeLib_Release(tlb);
+ ITypeLib_Release(tlb);
return ERROR_SUCCESS;
}
@@ -1828,7 +1771,6 @@ UINT WINAPI tl_absent(MSIHANDLE hinst)
HRESULT hr;
hr = LoadRegTypeLib(&LIBID_register_test, 7, 1, 0, &tlb);
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED))
ok(hinst, hr == TYPE_E_LIBNOTREGISTERED, "got %#x\n", hr);
return ERROR_SUCCESS;
@@ -1840,7 +1782,6 @@ UINT WINAPI sr_present(MSIHANDLE hinst)
LONG res;
res = RegOpenKeyA(HKEY_CLASSES_ROOT, "selfreg_test", &key);
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED))
ok(hinst, !res, "got %u\n", res);
RegCloseKey(key);
@@ -1853,7 +1794,6 @@ UINT WINAPI sr_absent(MSIHANDLE hinst)
LONG res;
res = RegOpenKeyA(HKEY_CLASSES_ROOT, "selfreg_test", &key);
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED))
ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %u\n", res);
return ERROR_SUCCESS;
@@ -1866,10 +1806,8 @@ UINT WINAPI env_present(MSIHANDLE hinst)
res = RegOpenKeyA(HKEY_CURRENT_USER, "Environment", &key);
ok(hinst, !res, "got %u\n", res);
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
check_reg_str(hinst, key, "MSITESTVAR3", "1");
check_reg_str(hinst, key, "MSITESTVAR4", "1");
-}
RegCloseKey(key);
return ERROR_SUCCESS;
@@ -1882,10 +1820,8 @@ UINT WINAPI env_absent(MSIHANDLE hinst)
res = RegOpenKeyA(HKEY_CURRENT_USER, "Environment", &key);
ok(hinst, !res, "got %u\n", res);
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
check_reg_str(hinst, key, "MSITESTVAR3", NULL);
check_reg_str(hinst, key, "MSITESTVAR4", NULL);
-}
RegCloseKey(key);
return ERROR_SUCCESS;
@@ -1901,7 +1837,6 @@ UINT WINAPI ini_present(MSIHANDLE hinst)
strcat(path, "\\msitest\\test.ini");
len = GetPrivateProfileStringA("section1", "key1", NULL, buf, sizeof(buf), path);
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED))
ok(hinst, len == 6, "got %u\n", len);
return ERROR_SUCCESS;
@@ -1917,7 +1852,6 @@ UINT WINAPI ini_absent(MSIHANDLE hinst)
strcat(path, "\\msitest\\test.ini");
len = GetPrivateProfileStringA("section1", "key1", NULL, buf, sizeof(buf), path);
-todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED))
ok(hinst, !len, "got %u\n", len);
return ERROR_SUCCESS;
@@ -1930,7 +1864,6 @@ UINT WINAPI wrv_present(MSIHANDLE hinst)
res = RegOpenKeyA(HKEY_CURRENT_USER, "msitest", &key);
ok(hinst, !res, "got %u\n", res);
- todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED))
check_reg_str(hinst, key, "sz", "string");
RegCloseKey(key);
@@ -1944,7 +1877,6 @@ UINT WINAPI wrv_absent(MSIHANDLE hinst)
res = RegOpenKeyA(HKEY_CURRENT_USER, "msitest", &key);
ok(hinst, !res, "got %u\n", res);
- todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED))
check_reg_str(hinst, key, "sz", NULL);
RegCloseKey(key);
diff --git a/dlls/msi/tests/install.c b/dlls/msi/tests/install.c
index 3eb6c80..d56a5ae 100644
--- a/dlls/msi/tests/install.c
+++ b/dlls/msi/tests/install.c
@@ -6077,7 +6077,6 @@ static void test_deferred_action(void)
}
ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
-todo_wine
check_file_matches(file, "onetwo");
ok(DeleteFileA(file), "Directory not created\n");
--
2.7.4
June 6, 2018
[PATCH 3/4] msi: Store the current script in the package.
by Zebediah Figura
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
This partially restores e1e668d41fce1dbd0270cd9de0d880a236ddb869, and
partially reverts f25501db4b9f79b69a6c569ab418e6f5a4d8fc94. It should not
however cause any change in behaviour.
dlls/msi/action.c | 25 +++++++++++++++----------
dlls/msi/custom.c | 4 ++--
dlls/msi/dialog.c | 2 +-
dlls/msi/install.c | 2 +-
dlls/msi/msi.c | 6 +++---
dlls/msi/msipriv.h | 5 +++--
dlls/msi/package.c | 1 +
7 files changed, 26 insertions(+), 19 deletions(-)
diff --git a/dlls/msi/action.c b/dlls/msi/action.c
index ddd676d..7c71800 100644
--- a/dlls/msi/action.c
+++ b/dlls/msi/action.c
@@ -510,7 +510,7 @@ static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
return ERROR_SUCCESS;
}
- rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
+ rc = ACTION_PerformAction(package, action);
msi_dialog_check_messages( NULL );
@@ -604,7 +604,7 @@ static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
/********************************************************
* ACTION helper functions and functions that perform the actions
*******************************************************/
-static UINT ACTION_HandleCustomAction(MSIPACKAGE *package, LPCWSTR action, UINT script)
+static UINT ACTION_HandleCustomAction(MSIPACKAGE *package, LPCWSTR action)
{
UINT arc;
INT uirc;
@@ -613,7 +613,7 @@ static UINT ACTION_HandleCustomAction(MSIPACKAGE *package, LPCWSTR action, UINT
if (uirc == IDCANCEL)
return ERROR_INSTALL_USEREXIT;
ui_actioninfo(package, action, TRUE, 0);
- arc = ACTION_CustomAction( package, action, script );
+ arc = ACTION_CustomAction(package, action);
uirc = !arc;
if (arc == ERROR_FUNCTION_NOT_CALLED && needs_ui_sequence(package))
@@ -1546,11 +1546,13 @@ static UINT execute_script( MSIPACKAGE *package, UINT script )
TRACE("executing script %u\n", script);
+ package->script = script;
+
if (script == SCRIPT_ROLLBACK)
{
for (i = package->script_actions_count[script]; i > 0; i--)
{
- rc = ACTION_PerformAction(package, package->script_actions[script][i-1], script);
+ rc = ACTION_PerformAction(package, package->script_actions[script][i-1]);
if (rc != ERROR_SUCCESS)
{
ERR("Execution of script %i halted; action %s returned %u\n",
@@ -1563,7 +1565,7 @@ static UINT execute_script( MSIPACKAGE *package, UINT script )
{
for (i = 0; i < package->script_actions_count[script]; i++)
{
- rc = ACTION_PerformAction(package, package->script_actions[script][i], script);
+ rc = ACTION_PerformAction(package, package->script_actions[script][i]);
if (rc != ERROR_SUCCESS)
{
ERR("Execution of script %i halted; action %s returned %u\n",
@@ -1572,6 +1574,9 @@ static UINT execute_script( MSIPACKAGE *package, UINT script )
}
}
}
+
+ package->script = SCRIPT_NONE;
+
msi_free_action_script(package, script);
return rc;
}
@@ -5672,7 +5677,7 @@ static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
msiobj_release(&uirow->hdr);
}
else
- rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
+ rc = ACTION_PerformAction(package, action);
/* Send all set properties. */
if (!MSI_OpenQuery(package->db, &view, prop_query))
@@ -7919,7 +7924,7 @@ static UINT ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action)
return rc;
}
-UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
+UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action)
{
UINT rc;
@@ -7929,7 +7934,7 @@ UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
rc = ACTION_HandleStandardAction(package, action);
if (rc == ERROR_FUNCTION_NOT_CALLED)
- rc = ACTION_HandleCustomAction(package, action, script);
+ rc = ACTION_HandleCustomAction(package, action);
if (rc == ERROR_FUNCTION_NOT_CALLED)
WARN("unhandled msi action %s\n", debugstr_w(action));
@@ -7982,7 +7987,7 @@ static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
return ERROR_FUNCTION_FAILED;
}
- rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
+ rc = ACTION_PerformAction(package, action);
msiobj_release(&row->hdr);
}
@@ -8071,7 +8076,7 @@ UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
msi_set_property( package->db, szRollbackDisabled, szOne, -1 );
}
- rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
+ rc = ACTION_PerformAction(package, action);
/* process the ending type action */
if (rc == ERROR_SUCCESS)
diff --git a/dlls/msi/custom.c b/dlls/msi/custom.c
index 07916ac..8deebe5 100644
--- a/dlls/msi/custom.c
+++ b/dlls/msi/custom.c
@@ -1208,7 +1208,7 @@ static UINT defer_custom_action( MSIPACKAGE *package, const WCHAR *action, UINT
return ERROR_SUCCESS;
}
-UINT ACTION_CustomAction( MSIPACKAGE *package, LPCWSTR action, UINT script )
+UINT ACTION_CustomAction(MSIPACKAGE *package, const WCHAR *action)
{
static const WCHAR query[] = {
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
@@ -1248,7 +1248,7 @@ UINT ACTION_CustomAction( MSIPACKAGE *package, LPCWSTR action, UINT script )
if (type & msidbCustomActionTypeNoImpersonate)
WARN("msidbCustomActionTypeNoImpersonate not handled\n");
- if (!action_type_matches_script( type, script ))
+ if (!action_type_matches_script(type, package->script))
{
rc = defer_custom_action( package, action, type );
goto end;
diff --git a/dlls/msi/dialog.c b/dlls/msi/dialog.c
index 61c6ab0..1e78aa9 100644
--- a/dlls/msi/dialog.c
+++ b/dlls/msi/dialog.c
@@ -4363,7 +4363,7 @@ static UINT event_spawn_wait_dialog( msi_dialog *dialog, const WCHAR *argument )
static UINT event_do_action( msi_dialog *dialog, const WCHAR *argument )
{
- ACTION_PerformAction( dialog->package, argument, SCRIPT_NONE );
+ ACTION_PerformAction(dialog->package, argument);
return ERROR_SUCCESS;
}
diff --git a/dlls/msi/install.c b/dlls/msi/install.c
index e043c04..0e224c9 100644
--- a/dlls/msi/install.c
+++ b/dlls/msi/install.c
@@ -83,7 +83,7 @@ UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction )
return remote_DoAction(remote, szAction);
}
- ret = ACTION_PerformAction( package, szAction, SCRIPT_NONE );
+ ret = ACTION_PerformAction(package, szAction);
msiobj_release( &package->hdr );
return ret;
diff --git a/dlls/msi/msi.c b/dlls/msi/msi.c
index 2ec94a1..2ae4db2 100644
--- a/dlls/msi/msi.c
+++ b/dlls/msi/msi.c
@@ -3742,7 +3742,7 @@ UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct)
if (!package)
return ERROR_CALL_NOT_IMPLEMENTED;
- rc = ACTION_PerformAction(package, szFirstRun, SCRIPT_NONE);
+ rc = ACTION_PerformAction(package, szFirstRun);
msiobj_release( &package->hdr );
MsiCloseHandle(handle);
@@ -3768,7 +3768,7 @@ UINT WINAPI MsiCollectUserInfoA(LPCSTR szProduct)
if (!package)
return ERROR_CALL_NOT_IMPLEMENTED;
- rc = ACTION_PerformAction(package, szFirstRun, SCRIPT_NONE);
+ rc = ACTION_PerformAction(package, szFirstRun);
msiobj_release( &package->hdr );
MsiCloseHandle(handle);
@@ -3849,7 +3849,7 @@ UINT WINAPI MsiConfigureFeatureW(LPCWSTR szProduct, LPCWSTR szFeature, INSTALLST
MsiSetInternalUI( INSTALLUILEVEL_BASIC, NULL );
- r = ACTION_PerformAction( package, szCostInitialize, SCRIPT_NONE );
+ r = ACTION_PerformAction(package, szCostInitialize);
if (r != ERROR_SUCCESS)
goto end;
diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h
index 707144f..8acace3 100644
--- a/dlls/msi/msipriv.h
+++ b/dlls/msi/msipriv.h
@@ -414,6 +414,7 @@ typedef struct tagMSIPACKAGE
struct list mimes;
struct list appids;
+ enum script script;
LPWSTR *script_actions[SCRIPT_MAX];
int script_actions_count[SCRIPT_MAX];
LPWSTR *unique_actions;
@@ -975,9 +976,9 @@ extern WCHAR *gszLogFile DECLSPEC_HIDDEN;
extern HINSTANCE msi_hInstance DECLSPEC_HIDDEN;
/* action related functions */
-extern UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script) DECLSPEC_HIDDEN;
+extern UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action) DECLSPEC_HIDDEN;
extern void ACTION_FinishCustomActions( const MSIPACKAGE* package) DECLSPEC_HIDDEN;
-extern UINT ACTION_CustomAction(MSIPACKAGE *, const WCHAR *, UINT) DECLSPEC_HIDDEN;
+extern UINT ACTION_CustomAction(MSIPACKAGE *package, const WCHAR *action) DECLSPEC_HIDDEN;
/* actions in other modules */
extern UINT ACTION_AppSearch(MSIPACKAGE *package) DECLSPEC_HIDDEN;
diff --git a/dlls/msi/package.c b/dlls/msi/package.c
index 2801efa..840e4a7 100644
--- a/dlls/msi/package.c
+++ b/dlls/msi/package.c
@@ -1119,6 +1119,7 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db )
msi_load_admin_properties( package );
package->log_file = INVALID_HANDLE_VALUE;
+ package->script = SCRIPT_NONE;
}
return package;
}
--
2.7.4
June 6, 2018