Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
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-winehq
Commits
d757bfee
Commit
d757bfee
authored
May 27, 2005
by
Alexandre Julliard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Authors: Aric Stewart <aric@codeweavers.com>, Mike McCormack <mike@codeweavers.com>
Implement dialog events and hook up the dialog code.
parent
de832c92
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
506 additions
and
4 deletions
+506
-4
Makefile.in
dlls/msi/Makefile.in
+1
-0
action.c
dlls/msi/action.c
+21
-4
action.h
dlls/msi/action.h
+5
-0
events.c
dlls/msi/events.c
+478
-0
msipriv.h
dlls/msi/msipriv.h
+1
-0
No files found.
dlls/msi/Makefile.in
View file @
d757bfee
...
...
@@ -16,6 +16,7 @@ C_SRCS = \
delete.c
\
dialog.c
\
distinct.c
\
events.c
\
format.c
\
handle.c
\
insert.c
\
...
...
dlls/msi/action.c
View file @
d757bfee
...
...
@@ -685,6 +685,21 @@ void ACTION_free_package_structures( MSIPACKAGE* package)
HeapFree
(
GetProcessHeap
(),
0
,
package
->
CommitAction
);
HeapFree
(
GetProcessHeap
(),
0
,
package
->
PackagePath
);
/* cleanup control event subscriptions */
ControlEvent_CleanupSubscriptions
(
package
);
}
static
void
ce_actiontext
(
MSIPACKAGE
*
package
,
LPCWSTR
action
)
{
static
const
WCHAR
szActionText
[]
=
{
'A'
,
'c'
,
't'
,
'i'
,
'o'
,
'n'
,
'T'
,
'e'
,
'x'
,
't'
,
0
};
MSIRECORD
*
row
;
row
=
MSI_CreateRecord
(
1
);
MSI_RecordSetStringW
(
row
,
1
,
action
);
ControlEvent_FireSubscribedEvent
(
package
,
szActionText
,
row
);
msiobj_release
(
&
row
->
hdr
);
}
static
void
ui_progress
(
MSIPACKAGE
*
package
,
int
a
,
int
b
,
int
c
,
int
d
)
...
...
@@ -714,6 +729,8 @@ static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * recor
MSIQUERY
*
view
;
MSIRECORD
*
row
=
0
;
DWORD
size
;
static
const
WCHAR
szActionData
[]
=
{
'A'
,
'c'
,
't'
,
'i'
,
'o'
,
'n'
,
'D'
,
'a'
,
't'
,
'a'
,
0
};
if
(
!
package
->
LastAction
||
strcmpW
(
package
->
LastAction
,
action
))
{
...
...
@@ -764,6 +781,9 @@ static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * recor
MSI_RecordSetStringW
(
row
,
1
,
message
);
MSI_ProcessMessage
(
package
,
INSTALLMESSAGE_ACTIONDATA
,
row
);
ControlEvent_FireSubscribedEvent
(
package
,
szActionData
,
row
);
msiobj_release
(
&
row
->
hdr
);
}
...
...
@@ -1403,6 +1423,7 @@ BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action, UINT* rc)
{
if
(
strcmpW
(
StandardActions
[
i
].
action
,
action
)
==
0
)
{
ce_actiontext
(
package
,
action
);
ui_actioninfo
(
package
,
action
,
TRUE
,
0
);
ui_actionstart
(
package
,
action
);
if
(
StandardActions
[
i
].
handler
)
...
...
@@ -1427,15 +1448,11 @@ BOOL ACTION_HandleDialogBox(MSIPACKAGE *package, LPCWSTR dialog, UINT* rc)
{
BOOL
ret
=
FALSE
;
/*
* for the UI when we get that working
*
if
(
ACTION_DialogBox
(
package
,
dialog
)
==
ERROR_SUCCESS
)
{
*
rc
=
package
->
CurrentInstallState
;
ret
=
TRUE
;
}
*/
return
ret
;
}
...
...
dlls/msi/action.h
View file @
d757bfee
...
...
@@ -196,3 +196,8 @@ int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component );
int
get_loaded_feature
(
MSIPACKAGE
*
package
,
LPCWSTR
Feature
);
int
get_loaded_file
(
MSIPACKAGE
*
package
,
LPCWSTR
file
);
int
track_tempfile
(
MSIPACKAGE
*
package
,
LPCWSTR
name
,
LPCWSTR
path
);
/* control event stuff */
VOID
ControlEvent_FireSubscribedEvent
(
MSIPACKAGE
*
package
,
LPCWSTR
event
,
MSIRECORD
*
data
);
VOID
ControlEvent_CleanupSubscriptions
(
MSIPACKAGE
*
package
);
dlls/msi/events.c
0 → 100644
View file @
d757bfee
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2005 Aric Stewart for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/controlevent_overview.asp
*/
#include <stdarg.h>
#include <stdio.h>
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "winreg.h"
#include "msi.h"
#include "msipriv.h"
#include "action.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL
(
msi
);
typedef
void
(
*
EVENTHANDLER
)(
MSIPACKAGE
*
,
LPCWSTR
,
msi_dialog
*
);
struct
_events
{
LPSTR
event
;
EVENTHANDLER
handler
;
};
struct
_subscriber
{
LPWSTR
control
;
LPWSTR
attribute
;
struct
_subscriber
*
next
;
};
struct
_subscription_chain
{
LPWSTR
event
;
struct
_subscriber
*
chain
;
};
struct
_subscriptions
{
DWORD
chain_count
;
struct
_subscription_chain
*
chain
;
};
VOID
ControlEvent_HandleControlEvent
(
MSIPACKAGE
*
,
LPCWSTR
,
LPCWSTR
,
msi_dialog
*
);
/*
* Create a dialog box and run it if it's modal
*/
static
UINT
event_do_dialog
(
MSIPACKAGE
*
package
,
LPCWSTR
name
)
{
msi_dialog
*
dialog
;
UINT
r
;
/* kill the current modeless dialog */
if
(
package
->
dialog
)
msi_dialog_destroy
(
package
->
dialog
);
package
->
dialog
=
NULL
;
/* create a new dialog */
dialog
=
msi_dialog_create
(
package
,
name
,
ControlEvent_HandleControlEvent
);
if
(
dialog
)
{
/* modeless dialogs return an error message */
r
=
msi_dialog_run_message_loop
(
dialog
);
if
(
r
==
ERROR_SUCCESS
)
msi_dialog_destroy
(
dialog
);
else
package
->
dialog
=
dialog
;
}
else
r
=
ERROR_FUNCTION_FAILED
;
return
r
;
}
/*
* End a modal dialog box
*/
static
VOID
ControlEvent_EndDialog
(
MSIPACKAGE
*
package
,
LPCWSTR
argument
,
msi_dialog
*
dialog
)
{
static
const
WCHAR
szExit
[]
=
{
'E'
,
'x'
,
'i'
,
't'
,
0
};
static
const
WCHAR
szRetry
[]
=
{
'R'
,
'e'
,
't'
,
'r'
,
'y'
,
0
};
static
const
WCHAR
szIgnore
[]
=
{
'I'
,
'g'
,
'n'
,
'o'
,
'r'
,
'e'
,
0
};
static
const
WCHAR
szReturn
[]
=
{
'R'
,
'e'
,
't'
,
'u'
,
'r'
,
'n'
,
0
};
if
(
lstrcmpW
(
argument
,
szExit
)
==
0
)
package
->
CurrentInstallState
=
ERROR_INSTALL_USEREXIT
;
else
if
(
lstrcmpW
(
argument
,
szRetry
)
==
0
)
package
->
CurrentInstallState
=
ERROR_INSTALL_SUSPEND
;
else
if
(
lstrcmpW
(
argument
,
szIgnore
)
==
0
)
package
->
CurrentInstallState
=
-
1
;
else
if
(
lstrcmpW
(
argument
,
szReturn
)
==
0
)
package
->
CurrentInstallState
=
ERROR_SUCCESS
;
else
{
ERR
(
"Unknown argument string %s
\n
"
,
debugstr_w
(
argument
));
package
->
CurrentInstallState
=
ERROR_FUNCTION_FAILED
;
}
msi_dialog_end_dialog
(
dialog
);
}
/*
* transition from one modal dialog to another modal dialog
*/
static
VOID
ControlEvent_NewDialog
(
MSIPACKAGE
*
package
,
LPCWSTR
argument
,
msi_dialog
*
dialog
)
{
/* store the name of the next dialog, and signal this one to end */
package
->
next_dialog
=
strdupW
(
argument
);
msi_dialog_end_dialog
(
dialog
);
}
/*
* Create a new child dialog of an existing modal dialog
*/
static
VOID
ControlEvent_SpawnDialog
(
MSIPACKAGE
*
package
,
LPCWSTR
argument
,
msi_dialog
*
dialog
)
{
event_do_dialog
(
package
,
argument
);
if
(
package
->
CurrentInstallState
!=
ERROR_SUCCESS
)
msi_dialog_end_dialog
(
dialog
);
}
/*
* Creates a dialog that remains up for a period of time
* based on a condition
*/
static
VOID
ControlEvent_SpawnWaitDialog
(
MSIPACKAGE
*
package
,
LPCWSTR
argument
,
msi_dialog
*
dialog
)
{
FIXME
(
"Doing Nothing
\n
"
);
}
static
VOID
ControlEvent_DoAction
(
MSIPACKAGE
*
package
,
LPCWSTR
argument
,
msi_dialog
*
dialog
)
{
ACTION_PerformAction
(
package
,
argument
);
}
static
VOID
ControlEvent_AddLocal
(
MSIPACKAGE
*
package
,
LPCWSTR
argument
,
msi_dialog
*
dialog
)
{
static
const
WCHAR
szAll
[]
=
{
'A'
,
'L'
,
'L'
,
0
};
int
i
;
if
(
lstrcmpW
(
szAll
,
argument
))
{
MSI_SetFeatureStateW
(
package
,
argument
,
INSTALLSTATE_LOCAL
);
}
else
{
for
(
i
=
0
;
i
<
package
->
loaded_features
;
i
++
)
{
package
->
features
[
i
].
ActionRequest
=
INSTALLSTATE_LOCAL
;
package
->
features
[
i
].
Action
=
INSTALLSTATE_LOCAL
;
}
ACTION_UpdateComponentStates
(
package
,
argument
);
}
}
static
VOID
ControlEvent_Remove
(
MSIPACKAGE
*
package
,
LPCWSTR
argument
,
msi_dialog
*
dialog
)
{
static
const
WCHAR
szAll
[]
=
{
'A'
,
'L'
,
'L'
,
0
};
int
i
;
if
(
lstrcmpW
(
szAll
,
argument
))
{
MSI_SetFeatureStateW
(
package
,
argument
,
INSTALLSTATE_ABSENT
);
}
else
{
for
(
i
=
0
;
i
<
package
->
loaded_features
;
i
++
)
{
package
->
features
[
i
].
ActionRequest
=
INSTALLSTATE_ABSENT
;
package
->
features
[
i
].
Action
=
INSTALLSTATE_ABSENT
;
}
ACTION_UpdateComponentStates
(
package
,
argument
);
}
}
static
VOID
ControlEvent_AddSource
(
MSIPACKAGE
*
package
,
LPCWSTR
argument
,
msi_dialog
*
dialog
)
{
static
const
WCHAR
szAll
[]
=
{
'A'
,
'L'
,
'L'
,
0
};
int
i
;
if
(
lstrcmpW
(
szAll
,
argument
))
{
MSI_SetFeatureStateW
(
package
,
argument
,
INSTALLSTATE_SOURCE
);
}
else
{
for
(
i
=
0
;
i
<
package
->
loaded_features
;
i
++
)
{
package
->
features
[
i
].
ActionRequest
=
INSTALLSTATE_SOURCE
;
package
->
features
[
i
].
Action
=
INSTALLSTATE_SOURCE
;
}
ACTION_UpdateComponentStates
(
package
,
argument
);
}
}
/*
* Subscribed events
*/
static
void
free_subscriber
(
struct
_subscriber
*
who
)
{
HeapFree
(
GetProcessHeap
(),
0
,
who
->
control
);
HeapFree
(
GetProcessHeap
(),
0
,
who
->
attribute
);
HeapFree
(
GetProcessHeap
(),
0
,
who
);
}
VOID
ControlEvent_SubscribeToEvent
(
MSIPACKAGE
*
package
,
LPCWSTR
event
,
LPCWSTR
control
,
LPCWSTR
attribute
)
{
int
i
;
struct
_subscription_chain
*
chain
;
struct
_subscriber
*
subscriber
,
*
ptr
;
if
(
!
package
->
EventSubscriptions
)
{
package
->
EventSubscriptions
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
struct
_subscriptions
));
package
->
EventSubscriptions
->
chain_count
=
0
;
}
chain
=
NULL
;
for
(
i
=
0
;
i
<
package
->
EventSubscriptions
->
chain_count
;
i
++
)
{
if
(
lstrcmpiW
(
package
->
EventSubscriptions
->
chain
[
i
].
event
,
event
)
==
0
)
{
chain
=
&
package
->
EventSubscriptions
->
chain
[
i
];
break
;
}
}
if
(
chain
==
NULL
)
{
if
(
package
->
EventSubscriptions
->
chain_count
)
chain
=
HeapReAlloc
(
GetProcessHeap
(),
0
,
package
->
EventSubscriptions
->
chain
,
(
package
->
EventSubscriptions
->
chain_count
+
1
)
*
sizeof
(
struct
_subscription_chain
));
else
chain
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
struct
_subscription_chain
));
package
->
EventSubscriptions
->
chain
=
chain
;
chain
=
&
package
->
EventSubscriptions
->
chain
[
package
->
EventSubscriptions
->
chain_count
];
package
->
EventSubscriptions
->
chain_count
++
;
memset
(
chain
,
0
,
sizeof
(
struct
_subscription_chain
));
chain
->
event
=
strdupW
(
event
);
}
subscriber
=
ptr
=
chain
->
chain
;
while
(
ptr
)
{
subscriber
=
ptr
;
ptr
=
ptr
->
next
;
}
ptr
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
struct
_subscriber
));
ptr
->
control
=
strdupW
(
control
);
ptr
->
attribute
=
strdupW
(
attribute
);
ptr
->
next
=
NULL
;
if
(
subscriber
)
subscriber
->
next
=
ptr
;
else
chain
->
chain
=
ptr
;
}
VOID
ControlEvent_UnSubscribeToEvent
(
MSIPACKAGE
*
package
,
LPCWSTR
event
,
LPCWSTR
control
,
LPCWSTR
attribute
)
{
int
i
;
if
(
!
package
->
EventSubscriptions
)
return
;
for
(
i
=
0
;
i
<
package
->
EventSubscriptions
->
chain_count
;
i
++
)
{
if
(
lstrcmpiW
(
package
->
EventSubscriptions
->
chain
[
i
].
event
,
event
)
==
0
)
{
struct
_subscriber
*
who
;
struct
_subscriber
*
prev
=
NULL
;
who
=
package
->
EventSubscriptions
->
chain
[
i
].
chain
;
while
(
who
)
{
if
(
lstrcmpiW
(
who
->
control
,
control
)
==
0
&&
lstrcmpiW
(
who
->
attribute
,
attribute
)
==
0
)
{
if
(
prev
)
prev
->
next
=
who
->
next
;
else
package
->
EventSubscriptions
->
chain
[
i
].
chain
=
who
->
next
;
free_subscriber
(
who
);
}
else
{
prev
=
who
;
who
=
who
->
next
;
}
}
break
;
}
}
}
VOID
ControlEvent_FireSubscribedEvent
(
MSIPACKAGE
*
package
,
LPCWSTR
event
,
MSIRECORD
*
data
)
{
int
i
;
TRACE
(
"Firing Event %s
\n
"
,
debugstr_w
(
event
));
if
(
!
package
->
dialog
)
return
;
if
(
!
package
->
EventSubscriptions
)
return
;
for
(
i
=
0
;
i
<
package
->
EventSubscriptions
->
chain_count
;
i
++
)
{
if
(
lstrcmpiW
(
package
->
EventSubscriptions
->
chain
[
i
].
event
,
event
)
==
0
)
{
struct
_subscriber
*
who
;
who
=
package
->
EventSubscriptions
->
chain
[
i
].
chain
;
while
(
who
)
{
ERR
(
"Should Fire event for %s %s
\n
"
,
debugstr_w
(
who
->
control
),
debugstr_w
(
who
->
attribute
));
/*
msi_dialog_fire_subscribed_event(package->dialog, who->control,
who->attribute, data);
*/
who
=
who
->
next
;
}
break
;
}
}
}
VOID
ControlEvent_CleanupSubscriptions
(
MSIPACKAGE
*
package
)
{
int
i
;
if
(
!
package
->
EventSubscriptions
)
return
;
for
(
i
=
0
;
i
<
package
->
EventSubscriptions
->
chain_count
;
i
++
)
{
struct
_subscriber
*
who
;
struct
_subscriber
*
ptr
;
who
=
package
->
EventSubscriptions
->
chain
[
i
].
chain
;
while
(
who
)
{
ptr
=
who
;
who
=
who
->
next
;
free_subscriber
(
ptr
);
}
HeapFree
(
GetProcessHeap
(),
0
,
package
->
EventSubscriptions
->
chain
[
i
].
event
);
}
HeapFree
(
GetProcessHeap
(),
0
,
package
->
EventSubscriptions
->
chain
);
HeapFree
(
GetProcessHeap
(),
0
,
package
->
EventSubscriptions
);
package
->
EventSubscriptions
=
NULL
;
}
/*
* ACTION_DialogBox()
*
* Return ERROR_SUCCESS if dialog is process and ERROR_FUNCTION_FAILED
* if the given parameter is not a dialog box
*/
UINT
ACTION_DialogBox
(
MSIPACKAGE
*
package
,
LPCWSTR
szDialogName
)
{
UINT
r
=
ERROR_SUCCESS
;
if
(
package
->
next_dialog
)
ERR
(
"Already a next dialog... ignoring it
\n
"
);
package
->
next_dialog
=
NULL
;
/*
* Dialogs are chained by filling in the next_dialog member
* of the package structure, then terminating the current dialog.
* The code below sees the next_dialog member set, and runs the
* next dialog.
* We fall out of the loop below if we come across a modeless
* dialog, as it returns ERROR_IO_PENDING when we try to run
* its message loop.
*/
r
=
event_do_dialog
(
package
,
szDialogName
);
while
(
r
==
ERROR_SUCCESS
&&
package
->
next_dialog
)
{
LPWSTR
name
=
package
->
next_dialog
;
package
->
next_dialog
=
NULL
;
r
=
event_do_dialog
(
package
,
name
);
HeapFree
(
GetProcessHeap
(),
0
,
name
);
}
if
(
r
==
ERROR_IO_PENDING
)
r
=
ERROR_SUCCESS
;
return
r
;
}
struct
_events
Events
[]
=
{
{
"EndDialog"
,
ControlEvent_EndDialog
},
{
"NewDialog"
,
ControlEvent_NewDialog
},
{
"SpawnDialog"
,
ControlEvent_SpawnDialog
},
{
"SpawnWaitDialog"
,
ControlEvent_SpawnWaitDialog
},
{
"DoAction"
,
ControlEvent_DoAction
},
{
"AddLocal"
,
ControlEvent_AddLocal
},
{
"Remove"
,
ControlEvent_Remove
},
{
"AddSource"
,
ControlEvent_AddSource
},
{
NULL
,
NULL
},
};
VOID
ControlEvent_HandleControlEvent
(
MSIPACKAGE
*
package
,
LPCWSTR
event
,
LPCWSTR
argument
,
msi_dialog
*
dialog
)
{
int
i
=
0
;
TRACE
(
"Handling Control Event %s
\n
"
,
debugstr_w
(
event
));
if
(
!
event
)
return
;
while
(
Events
[
i
].
event
!=
NULL
)
{
LPWSTR
wevent
=
strdupAtoW
(
Events
[
i
].
event
);
if
(
lstrcmpW
(
wevent
,
event
)
==
0
)
{
HeapFree
(
GetProcessHeap
(),
0
,
wevent
);
Events
[
i
].
handler
(
package
,
argument
,
dialog
);
return
;
}
HeapFree
(
GetProcessHeap
(),
0
,
wevent
);
i
++
;
}
FIXME
(
"unhandled control event %s arg(%s)
\n
"
,
debugstr_w
(
event
),
debugstr_w
(
argument
));
}
dlls/msi/msipriv.h
View file @
d757bfee
...
...
@@ -226,6 +226,7 @@ typedef struct tagMSIPACKAGE
LPWSTR
next_dialog
;
BOOL
ExecuteSequenceRun
;
struct
_subscriptions
*
EventSubscriptions
;
}
MSIPACKAGE
;
typedef
struct
tagMSIPREVIEW
...
...
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