Archive: windows vista -> nsis using game explorer


windows vista -> nsis using game explorer
  hi, could someone help using the igameexplorer interface from windows vista with nsis' system.dll?

i already have my executable modified with the gdf (game definition file) data as described in the ms directx sdk. now, the next step to take is registering the executable via an api call.

here is what the directx sdk readme states

Once the GDF and related files have been added to a binary resource, it is then possible to integrate the game with Game Explorer. It is strongly advised that games integrate with Game Explorer during the installation process. The outline to the integration process is as follows:[list=1][*]Install ALL files to the user's hard drive. The next step activates parental controls and could potentially lock the user out of the installation directory. [*]Create an instance to the IGameExplorer interface. [*]Call the VerifyAccess method, of the IGameExplorer interface and pass it the path to the GDF. [*]Call the AddGame method, of the IGameExplorer interface and pass it the path to the GDF, the path to the root installation directory, and a unique GUID called the game instance ID. [*]Create shortcuts, which are Game Explorer tasks, by using the game instance ID. Game Explorer tasks are explained in the next section.[/list=1]
game explorer: http://windowssdk.msdn.microsoft.com.../ms687212.aspx
interface reference: http://windowssdk.msdn.microsoft.com.../ms687221.aspx

Completely untested.

!include WinVer.nsh

!define GDF $INSTDIR\game.exe

!define GIS_NOT_INSTALLED 0 # might be wrong value
!define GIS_CURRENT_USER 1 # might be wrong value
!define GIS_ALL_USERS 2 # might be wrong value

${If} ${AtLeastWinVista}
SetOutPath $PLUGINSDIR
File GameuxInstallHelper.dll # from dxsdk
System::Call "GameuxInstallHelper::GenerateGUID(*g .r0)"
System::Call "GameuxInstallHelper::AddToGameExplorer(t '${GDF}', t d, i ${GIS_ALL_USERS}, *g r0)"
System::Call "GameuxInstallHelper::CreateTask(i ${GIS_ALL_USERS}, *g r0, i 0, i 0, t 'Play', t '${GDF}', t '')"
System::Call "GameuxInstallHelper::CreateTask(i ${GIS_ALL_USERS}, *g r0, i 0, i 1, t 'Network Play', t '${GDF}', t '-network')"
System::Call "GameuxInstallHelper::CreateTask(i ${GIS_ALL_USERS}, *g r0, i 0, i 2, t 'Safe Mode', t '${GDF}', t '-safe')"
System::Call "GameuxInstallHelper::CreateTask(i ${GIS_ALL_USERS}, *g r0, i 1, i 0, t 'Supprt', t 'http://nsis.sf.net/', t '')"
System::Call "GameuxInstallHelper::SetupRichSavedGames(t '.ExampleSaveGame', t '${GDF}', t '%1')"
SetOutPath $INSTDIR
${EndIf}
# uninstall
${If} ${AtLeastWinVista}
System::Call "GameuxInstallHelper::RetrieveGUIDForApplication(t '${GDF}', *g .r0)"
System::Call "GameuxInstallHelper::RemoveFromGameExplorer(*g .r0)"
System::Call "GameuxInstallHelper::RemoveTasks(*g .r0)"
System::Call "GameuxInstallHelper::RemoveRichSaveGames(t '.ExampleSaveGame')"
${EndIf}

Great. From what I can tell there, Microsoft is now using something even more cryptic than the Registry. Now there's a "games database"?

<sarcastic>*sighs* don't you just love it when Microsoft's APIs insist on doing everything for you?</sarcastic>

-dandaman32


thanks for your help kichik!

works quite well, except one thing. in my case the guid is generated before - in the game definition file editor.
i tried both, with the sample binary with gdf information and my own binary and both the last parameter of addline could be left empty or even should left empty. i am not much into the gdf thing yet, so i don't know why this last parameter is there anyway as in the vista registry the guid of the is taken anyway.
the line

  System::Call "GameuxInstallHelper::GenerateGUID(*g .r0)"

crashes the installer. as i seem not to require it anyway i left it out, everything else seems to run smooth yet though i didn't try the uninstaller yet but looking at the lines you wrote that could be more a problem than addline cause of the guid thing i do not totally understand ;)

DOCa Cola

edit: @dandaman32
and yes, quite complicated for a simple link with menu :P

GenerateGUID might need an allocated buffer like CoCreateGuid. In which case, its usage should be:

System::Alloc 16
System::Call "GameuxInstallHelper::GenerateGUID(i sr0)"
or even:
System::Call "GameuxInstallHelper::GenerateGUID(g .r0)"
I'd need the DLL to verify. Could you attach it? Though you're probably correct that it just generates a new GUID. It doesn't take any parameters relating to the game.

here you go. :)

thanks for your time


As I thought, it just calls CoCreateGuid. The last usage example I wrote should work. It'd probably have the same effect if you generate the GUID in advance on your computer, but I can't be sure of that. According to MSDN, it's the InstanceID, so it's probably per-computer after all.

MSDN also says:

Callers should store the instanceID returned by this call as it is necessary to call RemoveGame or UpdateGame, and to create tasks for the game within the Game Explorer.

If the call is made to upgrade a legacy title to a supported title the ID returned in pguidInstanceID will be the same as the legacy entry.
It seems AddGame would return a different GUID then the one passed, if the game is already installed. All `*g r0` instances in the script above should therefore be changed to `gr0` and the first instance, in the call to AddToGameExplorer should be changed to `gr0r0` so that AddToGameExplorer would be able to change the GUID.

great, installing works now without any problems. the uninstaller is the next step.

thanks for your help kichik!


Mind creating a page on the Wiki with examples and functions/macros for adding games to the Game Explorer?


yea, as soon as i got this 100% running.
today i played with the uninstaller and couldn't get it working. i forgot to copy the gameuxinstallhelper.dll in the first place but i added it later so the uninstaller part does now look like that

${If} ${AtLeastWinVista}
SetOutPath $PLUGINSDIR
File GameuxInstallHelper.dll # from dxsdk
System::Call "GameuxInstallHelper::RetrieveGUIDForApplication(t '${GDF}', *g .r0)"
System::Call "GameuxInstallHelper::RemoveFromGameExplorer(*g .r0)"
System::Call "GameuxInstallHelper::RemoveTasks(*g .r0)"
System::Call "GameuxInstallHelper::RemoveRichSaveGames(t '.ExampleSaveGame')"
SetOutPath $INSTDIR
${EndIf}


i tested it and the path to ${GDF} is also correct set to the gdf binary.
Another problem i am experiencing are random crashes sometimes the installer calls the dll functions - both with the installer and uninstaller
http://img170.imageshack.us/my.php?i...6123647py9.png

You need to convert `*g .r0` to `g .r0` for the first call and to `g r0` for the others, just like with the installer code.


damn, i already tried changing the first call but forgot about the others ;) thx i will try it


still no success with

${If} ${AtLeastWinVista}
SetOutPath $PLUGINSDIR
File GameuxInstallHelper.dll # from dxsdk
System::Call "GameuxInstallHelper::RetrieveGUIDForApplication(t '${GDF}', g .r0)"
System::Call "GameuxInstallHelper::RemoveFromGameExplorer(*g r0)"
System::Call "GameuxInstallHelper::RemoveTasks(*g r0)"
System::Call "GameuxInstallHelper::RemoveRichSaveGames(t '.ExampleSaveGame')"
SetOutPath $INSTDIR
${EndIf}


the uninstaller seems to run fine but the game doesn't seem to be removed from the game browser...

You still have an asterisk before `g`. It should be `gr0` for the last two calls.


including .dlls in Setup package.
  How can I pack the GameuxInstallHelper.dll into the AppNameSetup.exe?

Is is necessary for our users to only download one file and I need to have the .dll accessible so the calls to the Game Explorer work correctly.

Any help would be appreciated,

Thanks,

Keith


Okay, I know I'm asking dumb questions, but has anyone made a tutorial on this subject? :D


does the dll not exist on every vista system?

if it does exist on every vista system, you should not include it in your setup but rather check, whether the user has the dll already and then call the functions or don't, if he has no windows vista (because then they're all useless).

if it is not installed on vista by default you should indeed include the dll into your installer.

this is quite simple:


SetOutPath $PLUGINSDIR
File GameuxInstallHelper.dll

you may need to modify your dll calls to:

system::call '$PLUGINSDIR\GameuxInstallHelper.dll::blabla()'

I've recently written an installer integrating with Game Explorer, thanks for the help kichik and Doca!

I've put up a wiki page with the code at:

http://nsis.sourceforge.net/Game_explorer

One thing of interest I discovered is that if you try and create a game explorer link for the current user it fails unless you are an administrator as it tries to write to HKLM - this is in conflict with what the documentation says but there's very little other information about Game Explorer at the moment.

--
Marc Sutton
www.codev.co.uk


I've been reading through these forums and I have been able to get my game to install in game explorer. My problem is that I can not uninstall the game from Game Explorer now. This is the GameEx code that I am using:


!define GDF gdf_wheel.dll

!define GIS_NOT_INSTALLED 0 # might be wrong value
!define GIS_CURRENT_USER 1 # might be wrong value
!define GIS_ALL_USERS 2 # might be wrong value

..Other code omitted

Install Code

${If} ${AtLeastWinVista}
SetOutPath $PLUGINSDIR
File GameuxInstallHelper.dll # from dxsdk
System::Call "GameuxInstallHelper::GenerateGUID(*g .r0)"
System::Call "GameuxInstallHelper::AddToGameExplorer(t '${GDF}', t d, i ${GIS_ALL_USERS}, *g r0)"
System::Call "GameuxInstallHelper::CreateTask(i ${GIS_ALL_USERS}, *g r0, i 0, i 0, t 'Play', t '${GDF}', t '')"
SetOutPath $INSTDIR
${EndIf}


Uninstall Code

${If} ${AtLeastWinVista}
System::Call "GameuxInstallHelper::RetrieveGUIDForApplication(t '${GDF}', *g .r0)"
System::Call "GameuxInstallHelper::RemoveFromGameExplorer(*g .r0)"
System::Call "GameuxInstallHelper::RemoveTasks(*g .r0)"
${EndIf}



I'm not sure where to go from here I've read the NSIS wiki on game explorer and I still can not get my game removed from game explorer. So my first step is to actually get the game removed then figure out how to set up the installer/uninstaller correctly.

Hi Third,

You need to use code more like that in the wiki. For a start the defines at the top of your code are incorrect. Also you need to RequestUserLevel admin at the top (it seems that applies even if you are trying to install for a current user).

Also you need to generate a GUID and store it in the registry when you install, then use that value to uninstall. Copying the code from the wiki entry at:

http://nsis.sourceforge.net/Game_explorer

should make it work. Hope that helps,

--
Marc Sutton
http://www.codev.co.uk


I tried the code from the wiki, but I think my problem is that I can't get the old game to uninstall from gameEx so the code from the wiki doesn't work. Also I have a gid inside my GDF file do I need to generate one the way you said or should I be able to pull it from the GDF?

Thanks


Okay some how i managed to get the old game removed from GameEx I am now using the code from the wiki, but it is not installing GameEx. I have the GameuxInstallHelper.dll and my gdf.dll in the directory with the installer. My script compiles fine it just doesn't seem to be running the GameEx functions.


!define GDF "gdf_wheel.dll"



!define PRODUCT "MyGame"
!define FILES "files"
!define STUDIO "MyStudio"

;Directory selection page
InstallDir "$PROGRAMFILES\${STUDIO}\${PRODUCT}"



Function GameExplorer
Pop $0

; Check if we have Vista or later
ClearErrors
ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion
IfErrors finished
StrCpy $0 $0 1
IntCmp $0 6 0 finished

; Register with Game Explorer if so
;SetOutPath $PLUGINSDIR
File "GameuxInstallHelper.dll"

; Remove first to avoid duplication
ReadRegStr $0 HKCU "Software\${PRODUCT}" "GameExplorer"
StrCmp $0 '' skipUninstall
System::Call "GameuxInstallHelper::RemoveFromGameExplorer(g r0)"
System::Call "GameuxInstallHelper::RemoveTasks(g r0)"
skipUninstall:

; Now add to GE
System::Call "GameuxInstallHelper::GenerateGUID(g .r0)"
WriteRegStr HKCU "Software\${PRODUCT}" "GameExplorer" $0
System::Call "GameuxInstallHelper::AddToGameExplorer(t ${GDF}, t '$INSTDIR\${PRODUCT}.exe', i ${GIS_ALL_USERS}, g r0 r0)"
System::Call "GameuxInstallHelper::CreateTask(i ${GIS_ALL_USERS}, g r0, i 0, i 0, t 'Play', t '$INSTDIR\${PRODUCT}.exe', t '')"
System::Call "GameuxInstallHelper::CreateTask(i ${GIS_ALL_USERS}, g r0, i 1, i 0, t 'Support', t 'http://www.MySite.com/', t '')"

finished:
Pop $0
FunctionEnd

Function un.GameExplorer
Push $0

; Check if we have Vista or later
ClearErrors
ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion
IfErrors finished
StrCpy $0 $0 1
IntCmp $0 6 0 finished

; Remove from game explorer
;SetOutPath $Temp
File "GameuxInstallHelper.dll"
ReadRegStr $0 HKCU "Software\${PRODUCT}" "GameExplorer"
StrCmp $0 '' finished
System::Call "GameuxInstallHelper::RemoveFromGameExplorer(g r0)"
System::Call "GameuxInstallHelper::RemoveTasks(g r0)"
finished:

Pop $0
FunctionEnd


Sorry for all of the code just wasn't sure if i was missing something. Like I said, I have the dll's in the same directory as the install script and I also copied them into the directory of the app just to make sure they were found but still no luck.

Thanks

Umm.. Does anyone have any ideas why I might be getting empty GUIDs from the System::Call "GameuxInstallHelper::GenerateGUID(g .r0)" line? I'm not getting "", but "{00000000-0000-0000-000000000000}" as a GUID...?

Owen.


GenerateGUID does not take a GUID as argument, but the POINTER TO AN GUID.

try GenerateGUID(i .r0)


GenerateGUID(i .r0) returns simply 0 instead of an empty GUID

Also, this was taken from above and the wiki, so it seems to have worked for others...

Owen.


you may try GenerateGUID(g r0)


untested:

System::Call "*(g 0) i .r0" # allocate memory for the GUID

>System::Call "GameuxInstallHelper::GenerateGUID (i .r0)" # pass the pointer to the allocated memory to the function
>System::Call "*$0(g .r1)" # read the new data from the pointer
>System::Free $0 # free the allocated memory
>DetailPrint "$1" # ouput the data

Your code with GenerateGUID (i r0) (no period), gives me a blank GUID again... (not "", "{00000000-0000-0000-000000000000}") This was the same as simply doing the GenerateGUID(g .r0) (which gave the same thing, all 0's)

I'm wondering if there's something borked on the vista box I'm using... (or flavour, or... sigh)

Owen.


Well, I found the problem. There are 2 versions of the GameuxInstallHelper. One's a 32 bit dll, one's a 64 bit dll. The 32 bit one works, but if you try to call the 64 bit one, it returns an empty GUID. So. Moral of this story. If you are getting totally weird results, double check you have the right files.

For other people's sanity:
32 bit version of GameuxInstallerHelper is around 77 k
64 bit version of GameuxInstallerHelper is around 100 k

Owen.


If anyone has an install script/s that succesfully add an entry to game explorer I would appreciate it if they would share it with me as I am currently unable to create one of my own.

I've followed the code in the wiki but for some reason my app does not get added to Game Explorer.


I was able to add an entry to game explorer using the GUID extracted from the GDF resource beforehand, and code like the following:


;--------------------------------
Function GE_AddGame
SetOutPath $PLUGINSDIR
File "GameuxInstallHelper.dll"
System::Call 'GameuxInstallHelper::AddToGameExplorerStrGUID(t "$INSTDIR\${GDF_BINARY}", t "$INSTDIR\", i 3, t "${GAME_GUID}")'
FunctionEnd

;--------------------------------
Function GE_AddTasks
SetShellVarContext all
System::Call 'GameuxInstallHelper::CreateTaskStrGUID(i 3, t "${GAME_GUID}", i 0, i 0, t "Play", t "$INSTDIR\${GAME_EXE}", t "")'
SetShellVarContext current
FunctionEnd

;--------------------------------
Function un.GE_RemoveGame
SetOutPath $PLUGINSDIR
File "GameuxInstallHelper.dll"
System::Call 'GameuxInstallHelper::RemoveFromGameExplorerStrGUID(t "${GAME_GUID}")'
System::Call 'GameuxInstallHelper::RemoveTasksStrGUID(t "${GAME_GUID}")'
FunctionEnd


Possibly the GUID passed to the functions needs to be the same as in the GDF resource, but if that's the case, what's the point of having a GenerateGUID function in GameuxInstallHelper instead of an ExtractGUID function?

Originally posted by mauvecloud
Possibly the GUID passed to the functions needs to be the same as in the GDF resource, but if that's the case, what's the point of having a GenerateGUID function in GameuxInstallHelper instead of an ExtractGUID function?
It doesn't, the GUID that you use for passing into the game explorer should be unique so that you could potentially add multiple versions/installs of the game to the explorer if you really wanted to. The GenerateGUID was failing for me because I had the 64 bit version of the dll instead of the 32 bit version on a 32 bit system.

we use:

System::Call "GameuxInstallHelper::GenerateGUID(g .r0)"
StrCmp $0 '{00000000-0000-0000-0000-000000000000}' finished

System::Call "GameuxInstallHelper::AddToGameExplorer(t 'path_to_gdf_file', t 'path_to_exe', i ${GIS_ALL_USERS}, g r0) i .r4"

System::Call "GameuxInstallHelper::CreateTask(i ${GIS_ALL_USERS}, g r0, i 1, i 0, t 'Play', t 'path_to_exe', t 'arguments') i .r4"
System::Call "GameuxInstallHelper::CreateTask(i ${GIS_ALL_USERS}, g r0, i 0, i 0, t 'Support', t 'path_to_exe', t 'arguments') i .r4"

System::Call "GameuxInstallHelper::SetupRihcSavedGames(t '.save_game_extension', t 'path_to_exe', t 'Save_game_descriptor') i .r4"

System::Call "GameuxInstallHelper::RegisterWithMediaCenter(t 'path_to_gdf_file', t 'path_to_mcl_location', i ${GIS_ALL_USERS}, t 'path_to_exe', t 'args', i 0) i .r4"
finished:


${GIS_ALL_USERS} = 3, can be 1 for current user instead (HKCU vs LM and for limited user can be 1)

Hope that helps anyone else that is trying to get this up and running.

Owen.

There's no need to use GameuxInstallHelper. There are better solutions available.

http://nsis.sourceforge.net/Game_explorer
http://nsis.sourceforge.net/Games_plug-in


I fail to see how either of those is better than GameuxInstallHelper. The "Games" plugin looks like it will only work if the GDF is embedded in the EXE, not if it's in a separate DLL, and requires MSVCR80.dll. The "GameExplorer" header doesn't handle Media Center (and also looks a little buggy - I mean, why swap the GDF path and INSTDIR depending on current or all users?), and neither currently supports rich saved games.


GameExplorer header is smaller, simpler, easier to get and just works. Just look at the length of this GameuxInstallHelper related thread to see what I mean. I've created the GameExplorer headers to help users avoid this DLL.


I'm doubtful of the "just works" part. I still don't understand the reversal of R0 and R1 depending on ${CONTEXT} in the following snippet:


!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


Anyway, I think the clarifications in this thread can be summarized as follows, and maybe added to a wiki page about GameuxInstallHelper:
1. The correct parameter type to use for the GUID (it's "g", not "i" or "*g" - the System plugin takes care of creating a GUID from the string and passing a pointer to it)
2. Use the 32-bit version of GameuxInstallHelper.dll, not the 64-bit version (unless maybe you want to only allow the game to be installed on a 64-bit system)
3. The GUID can be generated during the install, and shouldn't be the same as the gameID in the GDF resource.
Once those three things are understood, using GameuxInstallHelper is almost as easy as the GameExplorer header or Games plugin.

If you're going to create a Wiki page for GameuxInstallHelper, I suggest you put a direct link to the correct version or step by step instructions for its location.


Here you go:
http://nsis.sourceforge.net/Game_Explorer_with_Helper
(I haven't figured out yet how this forum decides which links to block, so I'm leaving it as text for now)

For comparison:
Weaknesses of old Game Explorer header:
1. No save game support
2. No media center support
3. Additional tasks have to be created manually (with long paths to remember)
4. No support for pre-Vista systems that might get upgraded

Weaknesses of Games plug-in:
1. Requires msvcr80.dll (612 KB)
2. Can't handle GDF in separate dll
3. No save game support
4. All tasks have to be created manually
5. No support for pre-Vista systems that might get upgraded

Weaknesses of Game Explorer with Helper header:
1. Requires GameuxInstallHelper.dll (95 KB)
2. Doesn't support more than one game per installer


2. Doesn't support more than one game per installer
If you change the macro for the adding the game to do a check to see if the dll is already written out, then it should work fine to add multiple games, as long as you make sure to always add them in sequence.

!ifndef GAME_EXPLORER_DLL_EXISTS
!ifdef GAME_EXPLORER_HELPER_PATH
File "/oname=GameuxInstallHelper.dll" "${GAME_EXPLORER_HELPER_PATH}"
!else
File "GameuxInstallHelper.dll"
!endif
!define GAME_EXPLORER_DLL_EXISTS
!endif


Also, another suggestion, for localization reasons, I'd pull the "Play" task out of the first macro, otherwise the French will see "Play". Or put them in as extra label options. (Same for support), or make them come from language strings $(GameExplorerPlayTask) or something.

Owen.

Supporting more than one game per installer took a little more than just checking for the dll, due to the way it had been using defines for the play task number and support task number, which wouldn't work if the task adding was done in a function declared before the one that added the game, so I switched to variables, and it should be more robust now.

As far as localization, I see your point, but I don't want to force the use of LangStrings, so I pulled the task adding out of the GameExplorer_AddGame, and GameExplorer_AddPlayTask and GameExplorer_AddSupportTask already allow the task names to be specified separately.