Game explorer: Difference between revisions
(+ msdn link) |
(macro arguments, working removal and no more GameuxInstallHelper) |
||
Line 2: | Line 2: | ||
== Description == | == Description == | ||
Microsoft Windows Vista ships with a feature called Game Explorer that allows a developer to list games in a central explorer location. | Microsoft Windows Vista ships with a feature called Game Explorer that allows a developer to list games in a central explorer location. This page contains code that allows a NSIS installer to add and remove a game from the Game Explorer. | ||
Before using this code, a game with an implemented GDF must already be prepared. GDF stands for Game Definition File and is actually a XML embedded as a resource in the game executable. The resource type should be named DATA and the resource itself should be named __GDF_XML. For more information, see MSDN. | |||
== | == Code == | ||
<highlight-nsis> | <highlight-nsis># user interface | ||
!define GameExplorer_AddGame '!insertmacro GameExplorer_AddGame' | |||
!define GameExplorer_UpdateGame '!insertmacro GameExplorer_UpdateGame' | |||
!define GameExplorer_RemoveGame '!insertmacro GameExplorer_RemoveGame' | |||
# internal stuff | |||
!define CLSCTX_INPROC_SERVER 1 | |||
!define IID_IGameExplorer {E7B2FB72-D728-49B3-A5F2-18EBF5F1349E} | |||
!define CLSID_GameExplorer {9A5EA990-3034-4D6F-9128-01F3C61022BC} | |||
!define GIS_CURRENT_USER 2 | |||
!define GIS_ALL_USERS 3 | |||
!define IGameExplorer_QueryInterface 0 | |||
!define IGameExplorer_AddRef 1 | |||
!define IGameExplorer_Release 2 | |||
!define IGameExplorer_AddGame 3 | |||
!define IGameExplorer_RemoveGame 4 | |||
!define IGameExplorer_UpdateGame 5 | |||
!define IGameExplorer_VerifyAccess 6 | |||
# includes | |||
!include LogicLib.nsh | |||
# the actual code | |||
!macro GameExplorer_GenerateGUID | |||
System::Call 'ole32::CoCreateGuid(g .s)' | |||
!macroend | |||
!macro GameExplorer_AddGame CONTEXT GDF INSTDIR EXE GUID | |||
!define __GAME_EXPLORER_UNIQUE "${__LINE__}${__FILE__}" | |||
Push $0 | Push $0 | ||
Push $1 | |||
Push $R0 | |||
Push $R1 | |||
Push $R2 | |||
Push "${GUID}" | |||
Push "${INSTDIR}" | |||
Push "${GDF}" | |||
Pop $R0 # == ${GDF} | |||
Pop $R1 # == ${INSTDIR} | |||
Pop $R2 # == ${GUID} | |||
ClearErrors | ClearErrors | ||
System::Call "ole32::CoCreateInstance( \ | |||
g '${CLSID_GameExplorer}', i 0, \ | |||
i ${CLSCTX_INPROC_SERVER}, \ | |||
g '${IID_IGameExplorer}', *i .r1) i .r0" | |||
${If} $0 != 0 # S_OK | |||
SetErrors | |||
Goto "done_${__GAME_EXPLORER_UNIQUE}" | |||
${EndIf} | |||
!if ${CONTEXT} == all | |||
System::Call "$1->${IGameExplorer_AddGame}(w R0, w R1, i ${GIS_ALL_USERS}, g R2) i .r0" | |||
!else if ${CONTEXT} == user | |||
System::Call "$1->${IGameExplorer_AddGame}(w R1, w R0, i ${GIS_CURRENT_USER}, g R2) i .r0" | |||
!else | |||
!error "Invalid CONTEXT passed to GameExplorer_AddGame! Must be `user` or `all`." | |||
!endif | |||
${If} $0 != 0 # S_OK | |||
SetErrors | |||
${Else} | |||
# Create play task | |||
!if ${CONTEXT} == all | |||
SetShellVarContext all | |||
!else if if ${CONTEXT} == user | |||
SetShellVarContext user | |||
!endif | |||
CreateDirectory $APPDATA\Microsoft\Windows\GameExplorer\$R2\PlayTasks\0 | |||
CreateShortcut $APPDATA\Microsoft\Windows\GameExplorer\$R2\PlayTasks\0\Play.lnk "${EXE}" | |||
${EndIf} | |||
System::Call "$1->${IGameExplorer_Release}()" | |||
"done_${__GAME_EXPLORER_UNIQUE}:" | |||
Pop $R2 | |||
Pop $R1 | |||
Pop $R0 | |||
Pop $1 | |||
Pop $0 | |||
!undef __GAME_EXPLORER_UNIQUE | |||
!macroend | |||
!macro _GameExplorer_GUID_Function Function GUID | |||
!define __GAME_EXPLORER_UNIQUE "${__LINE__}${__FILE__}" | |||
Push $0 | Push $0 | ||
Push $1 | |||
Push $2 | |||
Push $3 | |||
Push $4 | |||
Push $5 | |||
Push $R0 | |||
Push "${GUID}" | |||
Pop $R0 # == ${GUID} | |||
System::Alloc 16 | |||
Exch $R0 | |||
System::Call "ole32::CLSIDFromString(w s, i R0)" | |||
System::Call "*$R0(i .r2, i .r3, i .r4, i .r5)" | |||
System::Free $R0 | |||
ClearErrors | ClearErrors | ||
System::Call "ole32::CoCreateInstance( \ | |||
g '${CLSID_GameExplorer}', i 0, \ | |||
i ${CLSCTX_INPROC_SERVER}, \ | |||
g '${IID_IGameExplorer}', *i .r1) i .r0" | |||
${If} $0 != 0 # S_OK | |||
SetErrors | |||
Goto "done_${__GAME_EXPLORER_UNIQUE}" | |||
System::Call " | |||
${EndIf} | |||
System::Call "$1->${Function}(i r2, i r3, i r4, i r5) i .r0" | |||
${If} $0 != 0 # S_OK | |||
</highlight-nsis> | |||
SetErrors | |||
${EndIf} | |||
System::Call "$1->${IGameExplorer_Release}()" | |||
"done_${__GAME_EXPLORER_UNIQUE}:" | |||
Pop $R0 | |||
Pop $5 | |||
Pop $4 | |||
Pop $3 | |||
Pop $2 | |||
Pop $1 | |||
Pop $0 | |||
!undef __GAME_EXPLORER_UNIQUE | |||
!macroend | |||
!macro GameExplorer_UpdateGame GUID | |||
!insertmacro _GameExplorer_GUID_Function ${IGameExplorer_UpdateGame} "${GUID}" | |||
!macroend | |||
!macro GameExplorer_RemoveGame GUID | |||
!insertmacro _GameExplorer_GUID_Function ${IGameExplorer_RemoveGame} "${GUID}" | |||
!macroend</highlight-nsis> | |||
== Usage == | == Usage == | ||
=== Adding Games === | |||
First, an instance GUID for the game installation must be created with '''GameExplorer_GenerateGUID''' or any other GUID generation method. The generated instance GUID must be saved for later usage as it's required for the removal and updating of the game. | |||
<highlight-nsis>${GameExplorer_GenerateGUID} | |||
Pop $0 # instance GUID saved to $0</highlight-nsis> | |||
Next, simply call '''GameExplorer_AddGame''' with all the details. | |||
<highlight-nsis>${GameExplorer_AddGame} all $INSTDIR\GDF.dll $INSTDIR $INSTDIR\Game.exe $0 | |||
# `all` means installation for all users | |||
# `$INSTDIR\GDF.dll` is the path to the executable containing the GDF | |||
# `$INSTDIR` is the installation directory | |||
# `$INSTDIR\Game.exe` is the path to the main game executable | |||
# `$0` is the instance GUID</highlight-nsis> | |||
The error flag is set in case of an error. | |||
=== Additional Tasks === | |||
'''GameExplorer_AddGame''' creates only one task by default - the ''Play'' task. To create more, a shortcut must be created in a numbered directory under ''$APPDATA\Microsoft\Windows\GameExplorer\<instance GUID>\PlayTasks\<task number>'' or ''$APPDATA\Microsoft\Windows\GameExplorer\<instance GUID>\SupportTasks\<task number>''. The ''Play'' task is numbered 0 under PlayTasks, so the next play task should be numbered 1, while the next support task should be numbered 0. | |||
<highlight-nsis># restore instance GUID to $0 somehow | |||
CreateDirectory $APPDATA\Microsoft\Windows\GameExplorer\$0\PlayTasks\1 | |||
CreateShortcut "$APPDATA\Microsoft\Windows\GameExplorer\$0\PlayTasks\1\Network Play.lnk" \ | |||
"$INSTDIR\Game.exe" "-network" | |||
CreateDirectory $APPDATA\Microsoft\Windows\GameExplorer\$0\SupportTasks\0 | |||
CreateShortcut "$APPDATA\Microsoft\Windows\GameExplorer\$0\SupportTasks\0\Network Play.lnk" \ | |||
"$INSTDIR\Support.exe"</highlight-nsis> | |||
=== Updating Games === | |||
Restore the instance GUID and pass it to ''GameExplorer_UpdateGame''. | |||
<highlight-nsis># restore instance GUID to $0 somehow | |||
${GameExplorer_UpdateGame} $0</highlight-nsis> | |||
The error flag is set in case of an error. | |||
=== Removing Games === | |||
Restore the instance GUID and pass it to ''GameExplorer_RemoveGame''. | |||
<highlight-nsis># restore instance GUID to $0 somehow | |||
${GameExplorer_RemoveGame} $0</highlight-nsis> | |||
The error flag is set in case of an error. | |||
== Related MSDN Pages == | |||
*[http://msdn2.microsoft.com/en-us/library/bb206359.aspx#Integrating_into_an_Installer Integrating Windows Game Explorer into an Installer] | |||
[http://msdn2.microsoft.com/en-us/library/bb206359.aspx#Integrating_into_an_Installer Integrating Windows Game Explorer into an Installer] | *[http://msdn2.microsoft.com/en-us/library/bb173435.aspx Game Definition File Editor] | ||
[[Category:Code Examples]] | [[Category:Code Examples]] |
Revision as of 15:43, 13 April 2007
Author: codev (talk, contrib) |
Description
Microsoft Windows Vista ships with a feature called Game Explorer that allows a developer to list games in a central explorer location. This page contains code that allows a NSIS installer to add and remove a game from the Game Explorer.
Before using this code, a game with an implemented GDF must already be prepared. GDF stands for Game Definition File and is actually a XML embedded as a resource in the game executable. The resource type should be named DATA and the resource itself should be named __GDF_XML. For more information, see MSDN.
Code
# user interface !define GameExplorer_AddGame '!insertmacro GameExplorer_AddGame' !define GameExplorer_UpdateGame '!insertmacro GameExplorer_UpdateGame' !define GameExplorer_RemoveGame '!insertmacro GameExplorer_RemoveGame' # internal stuff !define CLSCTX_INPROC_SERVER 1 !define IID_IGameExplorer {E7B2FB72-D728-49B3-A5F2-18EBF5F1349E} !define CLSID_GameExplorer {9A5EA990-3034-4D6F-9128-01F3C61022BC} !define GIS_CURRENT_USER 2 !define GIS_ALL_USERS 3 !define IGameExplorer_QueryInterface 0 !define IGameExplorer_AddRef 1 !define IGameExplorer_Release 2 !define IGameExplorer_AddGame 3 !define IGameExplorer_RemoveGame 4 !define IGameExplorer_UpdateGame 5 !define IGameExplorer_VerifyAccess 6 # includes !include LogicLib.nsh # the actual code !macro GameExplorer_GenerateGUID System::Call 'ole32::CoCreateGuid(g .s)' !macroend !macro GameExplorer_AddGame CONTEXT GDF INSTDIR EXE GUID !define __GAME_EXPLORER_UNIQUE "${__LINE__}${__FILE__}" Push $0 Push $1 Push $R0 Push $R1 Push $R2 Push "${GUID}" Push "${INSTDIR}" Push "${GDF}" Pop $R0 # == ${GDF} Pop $R1 # == ${INSTDIR} Pop $R2 # == ${GUID} ClearErrors System::Call "ole32::CoCreateInstance( \ g '${CLSID_GameExplorer}', i 0, \ i ${CLSCTX_INPROC_SERVER}, \ g '${IID_IGameExplorer}', *i .r1) i .r0" ${If} $0 != 0 # S_OK SetErrors Goto "done_${__GAME_EXPLORER_UNIQUE}" ${EndIf} !if ${CONTEXT} == all System::Call "$1->${IGameExplorer_AddGame}(w R0, w R1, i ${GIS_ALL_USERS}, g R2) i .r0" !else if ${CONTEXT} == user System::Call "$1->${IGameExplorer_AddGame}(w R1, w R0, i ${GIS_CURRENT_USER}, g R2) i .r0" !else !error "Invalid CONTEXT passed to GameExplorer_AddGame! Must be `user` or `all`." !endif ${If} $0 != 0 # S_OK SetErrors ${Else} # Create play task !if ${CONTEXT} == all SetShellVarContext all !else if if ${CONTEXT} == user SetShellVarContext user !endif CreateDirectory $APPDATA\Microsoft\Windows\GameExplorer\$R2\PlayTasks\0 CreateShortcut $APPDATA\Microsoft\Windows\GameExplorer\$R2\PlayTasks\0\Play.lnk "${EXE}" ${EndIf} System::Call "$1->${IGameExplorer_Release}()" "done_${__GAME_EXPLORER_UNIQUE}:" Pop $R2 Pop $R1 Pop $R0 Pop $1 Pop $0 !undef __GAME_EXPLORER_UNIQUE !macroend !macro _GameExplorer_GUID_Function Function GUID !define __GAME_EXPLORER_UNIQUE "${__LINE__}${__FILE__}" Push $0 Push $1 Push $2 Push $3 Push $4 Push $5 Push $R0 Push "${GUID}" Pop $R0 # == ${GUID} System::Alloc 16 Exch $R0 System::Call "ole32::CLSIDFromString(w s, i R0)" System::Call "*$R0(i .r2, i .r3, i .r4, i .r5)" System::Free $R0 ClearErrors System::Call "ole32::CoCreateInstance( \ g '${CLSID_GameExplorer}', i 0, \ i ${CLSCTX_INPROC_SERVER}, \ g '${IID_IGameExplorer}', *i .r1) i .r0" ${If} $0 != 0 # S_OK SetErrors Goto "done_${__GAME_EXPLORER_UNIQUE}" ${EndIf} System::Call "$1->${Function}(i r2, i r3, i r4, i r5) i .r0" ${If} $0 != 0 # S_OK SetErrors ${EndIf} System::Call "$1->${IGameExplorer_Release}()" "done_${__GAME_EXPLORER_UNIQUE}:" Pop $R0 Pop $5 Pop $4 Pop $3 Pop $2 Pop $1 Pop $0 !undef __GAME_EXPLORER_UNIQUE !macroend !macro GameExplorer_UpdateGame GUID !insertmacro _GameExplorer_GUID_Function ${IGameExplorer_UpdateGame} "${GUID}" !macroend !macro GameExplorer_RemoveGame GUID !insertmacro _GameExplorer_GUID_Function ${IGameExplorer_RemoveGame} "${GUID}" !macroend
Usage
Adding Games
First, an instance GUID for the game installation must be created with GameExplorer_GenerateGUID or any other GUID generation method. The generated instance GUID must be saved for later usage as it's required for the removal and updating of the game.
${GameExplorer_GenerateGUID} Pop $0 # instance GUID saved to $0
Next, simply call GameExplorer_AddGame with all the details.
${GameExplorer_AddGame} all $INSTDIR\GDF.dll $INSTDIR $INSTDIR\Game.exe $0 # `all` means installation for all users # `$INSTDIR\GDF.dll` is the path to the executable containing the GDF # `$INSTDIR` is the installation directory # `$INSTDIR\Game.exe` is the path to the main game executable # `$0` is the instance GUID
The error flag is set in case of an error.
Additional Tasks
GameExplorer_AddGame creates only one task by default - the Play task. To create more, a shortcut must be created in a numbered directory under $APPDATA\Microsoft\Windows\GameExplorer\<instance GUID>\PlayTasks\<task number> or $APPDATA\Microsoft\Windows\GameExplorer\<instance GUID>\SupportTasks\<task number>. The Play task is numbered 0 under PlayTasks, so the next play task should be numbered 1, while the next support task should be numbered 0.
# restore instance GUID to $0 somehow CreateDirectory $APPDATA\Microsoft\Windows\GameExplorer\$0\PlayTasks\1 CreateShortcut "$APPDATA\Microsoft\Windows\GameExplorer\$0\PlayTasks\1\Network Play.lnk" \ "$INSTDIR\Game.exe" "-network" CreateDirectory $APPDATA\Microsoft\Windows\GameExplorer\$0\SupportTasks\0 CreateShortcut "$APPDATA\Microsoft\Windows\GameExplorer\$0\SupportTasks\0\Network Play.lnk" \ "$INSTDIR\Support.exe"
Updating Games
Restore the instance GUID and pass it to GameExplorer_UpdateGame.
# restore instance GUID to $0 somehow ${GameExplorer_UpdateGame} $0
The error flag is set in case of an error.
Removing Games
Restore the instance GUID and pass it to GameExplorer_RemoveGame.
# restore instance GUID to $0 somehow ${GameExplorer_RemoveGame} $0
The error flag is set in case of an error.