Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-cw
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-cw
Commits
a547027b
Commit
a547027b
authored
Feb 27, 2014
by
Hans Leidekker
Committed by
Alexandre Julliard
Feb 27, 2014
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
msi: Correctly [un]register progids when associated class and extensions change state.
parent
28ecbec8
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
86 additions
and
69 deletions
+86
-69
classes.c
dlls/msi/classes.c
+62
-62
msipriv.h
dlls/msi/msipriv.h
+0
-1
action.c
dlls/msi/tests/action.c
+24
-6
No files found.
dlls/msi/classes.c
View file @
a547027b
...
...
@@ -698,45 +698,6 @@ static UINT load_classes_and_such( MSIPACKAGE *package )
return
load_all_mimes
(
package
);
}
static
void
mark_progid_for_install
(
MSIPACKAGE
*
package
,
MSIPROGID
*
progid
)
{
MSIPROGID
*
child
;
if
(
!
progid
)
return
;
if
(
progid
->
InstallMe
)
return
;
progid
->
InstallMe
=
TRUE
;
/* all children if this is a parent also install */
LIST_FOR_EACH_ENTRY
(
child
,
&
package
->
progids
,
MSIPROGID
,
entry
)
{
if
(
child
->
Parent
==
progid
)
mark_progid_for_install
(
package
,
child
);
}
}
static
void
mark_progid_for_uninstall
(
MSIPACKAGE
*
package
,
MSIPROGID
*
progid
)
{
MSIPROGID
*
child
;
if
(
!
progid
)
return
;
if
(
!
progid
->
InstallMe
)
return
;
progid
->
InstallMe
=
FALSE
;
LIST_FOR_EACH_ENTRY
(
child
,
&
package
->
progids
,
MSIPROGID
,
entry
)
{
if
(
child
->
Parent
==
progid
)
mark_progid_for_uninstall
(
package
,
child
);
}
}
static
UINT
register_appid
(
const
MSIAPPID
*
appid
,
LPCWSTR
app
)
{
static
const
WCHAR
szRemoteServerName
[]
=
...
...
@@ -843,7 +804,6 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
TRACE
(
"Registering class %s (%p)
\n
"
,
debugstr_w
(
cls
->
clsid
),
cls
);
cls
->
action
=
INSTALLSTATE_LOCAL
;
mark_progid_for_install
(
package
,
cls
->
ProgID
);
RegCreateKeyW
(
hkey
,
cls
->
clsid
,
&
hkey2
);
...
...
@@ -1001,7 +961,6 @@ UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
TRACE
(
"Unregistering class %s (%p)
\n
"
,
debugstr_w
(
cls
->
clsid
),
cls
);
cls
->
action
=
INSTALLSTATE_ABSENT
;
mark_progid_for_uninstall
(
package
,
cls
->
ProgID
);
res
=
RegDeleteTreeW
(
hkey
,
cls
->
clsid
);
if
(
res
!=
ERROR_SUCCESS
)
...
...
@@ -1089,6 +1048,35 @@ static UINT register_progid( const MSIPROGID* progid )
return
rc
;
}
static
const
MSICLASS
*
get_progid_class
(
const
MSIPROGID
*
progid
)
{
while
(
progid
)
{
if
(
progid
->
Parent
)
progid
=
progid
->
Parent
;
if
(
progid
->
Class
)
return
progid
->
Class
;
if
(
!
progid
->
Parent
)
break
;
}
return
NULL
;
}
static
BOOL
has_class_installed
(
const
MSIPROGID
*
progid
)
{
const
MSICLASS
*
class
=
get_progid_class
(
progid
);
if
(
!
class
||
!
class
->
ProgID
)
return
FALSE
;
return
(
class
->
action
==
INSTALLSTATE_LOCAL
);
}
static
BOOL
has_one_extension_installed
(
const
MSIPACKAGE
*
package
,
const
MSIPROGID
*
progid
)
{
const
MSIEXTENSION
*
extension
;
LIST_FOR_EACH_ENTRY
(
extension
,
&
package
->
extensions
,
MSIEXTENSION
,
entry
)
{
if
(
extension
->
ProgID
==
progid
&&
!
list_empty
(
&
extension
->
verbs
)
&&
extension
->
action
==
INSTALLSTATE_LOCAL
)
return
TRUE
;
}
return
FALSE
;
}
UINT
ACTION_RegisterProgIdInfo
(
MSIPACKAGE
*
package
)
{
MSIPROGID
*
progid
;
...
...
@@ -1101,16 +1089,11 @@ UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
LIST_FOR_EACH_ENTRY
(
progid
,
&
package
->
progids
,
MSIPROGID
,
entry
)
{
/* check if this progid is to be installed */
if
(
progid
->
Class
&&
progid
->
Class
->
action
==
INSTALLSTATE_LOCAL
)
progid
->
InstallMe
=
TRUE
;
if
(
!
progid
->
InstallMe
)
if
(
!
has_class_installed
(
progid
)
&&
!
has_one_extension_installed
(
package
,
progid
))
{
TRACE
(
"progid %s not scheduled to be installed
\n
"
,
debugstr_w
(
progid
->
ProgID
));
continue
;
}
TRACE
(
"Registering progid %s
\n
"
,
debugstr_w
(
progid
->
ProgID
));
register_progid
(
progid
);
...
...
@@ -1123,6 +1106,36 @@ UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
return
ERROR_SUCCESS
;
}
static
BOOL
has_class_removed
(
const
MSIPROGID
*
progid
)
{
const
MSICLASS
*
class
=
get_progid_class
(
progid
);
if
(
!
class
||
!
class
->
ProgID
)
return
FALSE
;
return
(
class
->
action
==
INSTALLSTATE_ABSENT
);
}
static
BOOL
has_extensions
(
const
MSIPACKAGE
*
package
,
const
MSIPROGID
*
progid
)
{
const
MSIEXTENSION
*
extension
;
LIST_FOR_EACH_ENTRY
(
extension
,
&
package
->
extensions
,
MSIEXTENSION
,
entry
)
{
if
(
extension
->
ProgID
==
progid
&&
!
list_empty
(
&
extension
->
verbs
))
return
TRUE
;
}
return
FALSE
;
}
static
BOOL
has_all_extensions_removed
(
const
MSIPACKAGE
*
package
,
const
MSIPROGID
*
progid
)
{
BOOL
ret
=
FALSE
;
const
MSIEXTENSION
*
extension
;
LIST_FOR_EACH_ENTRY
(
extension
,
&
package
->
extensions
,
MSIEXTENSION
,
entry
)
{
if
(
extension
->
ProgID
==
progid
&&
!
list_empty
(
&
extension
->
verbs
)
&&
extension
->
action
==
INSTALLSTATE_ABSENT
)
ret
=
TRUE
;
else
ret
=
FALSE
;
}
return
ret
;
}
UINT
ACTION_UnregisterProgIdInfo
(
MSIPACKAGE
*
package
)
{
MSIPROGID
*
progid
;
...
...
@@ -1136,16 +1149,12 @@ UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
LIST_FOR_EACH_ENTRY
(
progid
,
&
package
->
progids
,
MSIPROGID
,
entry
)
{
/* check if this progid is to be removed */
if
(
progid
->
Class
&&
progid
->
Class
->
action
!=
INSTALLSTATE_LOCAL
)
progid
->
InstallMe
=
FALSE
;
if
(
progid
->
InstallMe
)
if
(
!
has_class_removed
(
progid
)
||
(
has_extensions
(
package
,
progid
)
&&
!
has_all_extensions_removed
(
package
,
progid
)))
{
TRACE
(
"progid %s not scheduled to be removed
\n
"
,
debugstr_w
(
progid
->
ProgID
));
continue
;
}
TRACE
(
"Unregistering progid %s
\n
"
,
debugstr_w
(
progid
->
ProgID
));
res
=
RegDeleteTreeW
(
HKEY_CLASSES_ROOT
,
progid
->
ProgID
);
...
...
@@ -1289,12 +1298,6 @@ UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package)
ext
->
action
=
INSTALLSTATE_LOCAL
;
/* this is only registered if the extension has at least 1 verb
* according to MSDN
*/
if
(
ext
->
ProgID
&&
!
list_empty
(
&
ext
->
verbs
)
)
mark_progid_for_install
(
package
,
ext
->
ProgID
);
extension
=
msi_alloc
(
(
strlenW
(
ext
->
Extension
)
+
2
)
*
sizeof
(
WCHAR
)
);
if
(
extension
)
{
...
...
@@ -1393,9 +1396,6 @@ UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
ext
->
action
=
INSTALLSTATE_ABSENT
;
if
(
ext
->
ProgID
&&
!
list_empty
(
&
ext
->
verbs
))
mark_progid_for_uninstall
(
package
,
ext
->
ProgID
);
extension
=
msi_alloc
(
(
strlenW
(
ext
->
Extension
)
+
2
)
*
sizeof
(
WCHAR
)
);
if
(
extension
)
{
...
...
dlls/msi/msipriv.h
View file @
a547027b
...
...
@@ -642,7 +642,6 @@ struct tagMSIPROGID
LPWSTR
Description
;
LPWSTR
IconPath
;
/* not in the table, set during installation */
BOOL
InstallMe
;
MSIPROGID
*
CurVer
;
MSIPROGID
*
VersionInd
;
};
...
...
dlls/msi/tests/action.c
View file @
a547027b
...
...
@@ -1372,7 +1372,14 @@ static const char rpi_class_dat[] =
static
const
char
rpi_extension_dat
[]
=
"Extension
\t
Component_
\t
ProgId_
\t
MIME_
\t
Feature_
\n
"
"s255
\t
s72
\t
S255
\t
S64
\t
s38
\n
"
"Extension
\t
Extension
\t
Component_
\n
"
;
"Extension
\t
Extension
\t
Component_
\n
"
"winetest
\t
progid
\t
Winetest.Extension
\t\t
progid
\n
"
;
static
const
char
rpi_verb_dat
[]
=
"Extension_
\t
Verb
\t
Sequence
\t
Command
\t
Argument
\n
"
"s255
\t
s32
\t
I2
\t
L255
\t
L255
\n
"
"Verb
\t
Extension_
\t
Verb
\n
"
"winetest
\t
Open
\t
1
\t
&Open
\t
/argument
\n
"
;
static
const
char
rpi_progid_dat
[]
=
"ProgId
\t
ProgId_Parent
\t
Class_
\t
Description
\t
Icon_
\t
IconIndex
\n
"
...
...
@@ -1386,7 +1393,8 @@ static const char rpi_progid_dat[] =
"Winetest.NoProgIdClass.1
\t\t
{57C413FB-CA02-498A-81F6-7E769BDB7C97}
\t
description
\t\t\n
"
"Winetest.NoProgIdClass
\t
Winetest.NoProgIdClass.1
\t\t
description
\t\t\n
"
"Winetest.Orphaned
\t\t\t
description
\t\t\n
"
"Winetest.Orphaned2
\t\t\t
description
\t\t\n
"
;
"Winetest.Orphaned2
\t\t\t
description
\t\t\n
"
"Winetest.Extension
\t\t\t
description
\t\t\n
"
;
static
const
char
rpi_install_exec_seq_dat
[]
=
"Action
\t
Condition
\t
Sequence
\n
"
...
...
@@ -1400,10 +1408,12 @@ static const char rpi_install_exec_seq_dat[] =
"InstallInitialize
\t\t
1500
\n
"
"ProcessComponents
\t\t
1600
\n
"
"RemoveFiles
\t\t
1700
\n
"
"InstallFiles
\t\t
2000
\n
"
"UnregisterClassInfo
\t\t
3000
\n
"
"UnregisterExtensionInfo
\t\t
3200
\n
"
"UnregisterProgIdInfo
\t\t
3400
\n
"
"InstallFiles
\t\t
3600
\n
"
"RegisterClassInfo
\t\t
4000
\n
"
"RegisterExtensionInfo
\t\t
4200
\n
"
"RegisterProgIdInfo
\t\t
4400
\n
"
"RegisterProduct
\t\t
5000
\n
"
"PublishFeatures
\t\t
5100
\n
"
...
...
@@ -1984,6 +1994,7 @@ static const msi_table rpi_tables[] =
ADD_TABLE
(
rpi_appid
),
ADD_TABLE
(
rpi_class
),
ADD_TABLE
(
rpi_extension
),
ADD_TABLE
(
rpi_verb
),
ADD_TABLE
(
rpi_progid
),
ADD_TABLE
(
rpi_install_exec_seq
),
ADD_TABLE
(
media
),
...
...
@@ -6371,19 +6382,23 @@ static void test_register_progid_info(void)
RegCloseKey
(
hkey
);
res
=
RegOpenKeyA
(
HKEY_CLASSES_ROOT
,
"Winetest.NoProgIdClass.1"
,
&
hkey
);
todo_wine
ok
(
res
==
ERROR_FILE_NOT_FOUND
,
"key created
\n
"
);
ok
(
res
==
ERROR_FILE_NOT_FOUND
,
"key created
\n
"
);
if
(
res
==
ERROR_SUCCESS
)
RegCloseKey
(
hkey
);
res
=
RegOpenKeyA
(
HKEY_CLASSES_ROOT
,
"Winetest.NoProgIdClass"
,
&
hkey
);
ok
(
res
==
ERROR_FILE_NOT_FOUND
,
"key created
\n
"
);
res
=
RegOpenKeyA
(
HKEY_CLASSES_ROOT
,
"Winetest.Orphaned"
,
&
hkey
);
todo_wine
ok
(
res
==
ERROR_SUCCESS
,
"key deleted
\n
"
);
ok
(
res
==
ERROR_SUCCESS
,
"key deleted
\n
"
);
if
(
res
==
ERROR_SUCCESS
)
RegCloseKey
(
hkey
);
res
=
RegOpenKeyA
(
HKEY_CLASSES_ROOT
,
"Winetest.Orphaned2"
,
&
hkey
);
ok
(
res
==
ERROR_FILE_NOT_FOUND
,
"key created
\n
"
);
res
=
RegOpenKeyA
(
HKEY_CLASSES_ROOT
,
"Winetest.Extension"
,
&
hkey
);
ok
(
res
==
ERROR_SUCCESS
,
"key not created
\n
"
);
RegCloseKey
(
hkey
);
r
=
MsiInstallProductA
(
msifile
,
"REMOVE=ALL"
);
ok
(
r
==
ERROR_SUCCESS
,
"Expected ERROR_SUCCESS, got %u
\n
"
,
r
);
...
...
@@ -6415,12 +6430,15 @@ static void test_register_progid_info(void)
ok
(
res
==
ERROR_FILE_NOT_FOUND
,
"key not removed
\n
"
);
res
=
RegOpenKeyA
(
HKEY_CLASSES_ROOT
,
"Winetest.Orphaned"
,
&
hkey
);
todo_wine
ok
(
res
==
ERROR_SUCCESS
,
"key deleted
\n
"
);
ok
(
res
==
ERROR_SUCCESS
,
"key deleted
\n
"
);
if
(
res
==
ERROR_SUCCESS
)
RegCloseKey
(
hkey
);
res
=
RegOpenKeyA
(
HKEY_CLASSES_ROOT
,
"Winetest.Orphaned2"
,
&
hkey
);
ok
(
res
==
ERROR_FILE_NOT_FOUND
,
"key not removed
\n
"
);
res
=
RegOpenKeyA
(
HKEY_CLASSES_ROOT
,
"Winetest.Extension"
,
&
hkey
);
ok
(
res
==
ERROR_FILE_NOT_FOUND
,
"key not removed
\n
"
);
ok
(
!
delete_pf
(
"msitest
\\
progid.txt"
,
TRUE
),
"file not removed
\n
"
);
ok
(
!
delete_pf
(
"msitest"
,
FALSE
),
"directory not removed
\n
"
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment