xboxscene.org forums

Author Topic: Determine Drive Mapping  (Read 397 times)

Hyper_Eye

  • Recovered User
  • Sr. Member
  • *
  • Posts: 366
Determine Drive Mapping
« on: July 16, 2010, 07:19:00 PM »

I am looking at launching an XBE with command-line parameters. I decided the best way would be to use the PLD_DEMO structure. Using that I can fill in the szLauncherXBE field to test that my second app was called from my first app and I can use it to return to the first app when the second app completes or something. I can also fill the Reserved field with the command-line arguments. From what I can tell there is no way to do this using XLaunchNewImage() because it will not send the data in you LAUNCH_DATA structure to the app. Your app will start but the command-line parameters you have stored will be gone. Looking at "undocumented.h" by everlame, Team Evox, and Woodoo I determined that I need XWriteTitleInfoAndRebootA(). Using this function you can stick anything you want into the LAUNCH_DATA. You could even define your own structure as long as it is no bigger than MAX_LAUNCH_DATA_SIZE. Well, there is a slight problem with this but first I will point out how to use it for any future google drive-bys. The function declaration, which you could slap into your own code if you don't want to use undocumented.h, looks like this:

CODE
extern "C" INT WINAPI XWriteTitleInfoAndRebootA(LPVOID,LPVIOD,DWORD,DWORD,LPVOID);


I opened up xapilib.lib in vim and found the declaration within. This is what the parameters to the function are and what they mean:

CODE
pszLaunchPath = The path to the XBE you want to launch. (ex. "D:\\app2.xbe")
pszDDrivePath = This is what you want your D: drive to be mapped to. (ex. "\\Device\\CdRom0")
dwLaunchDataType = The launch data type field is what you use to determine which type of LAUNCH_DATA structure to parse. (ex. LDT_TITLE)
dwTitleId = The title id of the xbe you are launching. Could this be used as an override? (ex. 0x4D530004 if you were launching Halo 2)
pLaunchData = This is a reference to a launch data structure or you can just pass it a PLAUNCH_DATA.


Alright, so lets say I want to launch Halo 2 and I know that it is in the same directory as my xbe and that I am running off of an actual DVD. I could launch Halo 2 with the following code:

CODE
LAUNCH_DATA launchData = { LDT_TITLE };

// Halo 2 obviously won't parse this but my app will so lets pretend like Halo 2 will.
strcpy(((PLD_DEMO)&launchData)->szLauncherXBE, "MyXbe.xbe");
strcpy((char*)((PLD_DEMO)&launcData)->Reserved, "SomeCommandLineArgs"); // I can put anything I want in here. Using the PLD_DEMO structure we get 2932 bytes in the reserved field to work with which I hope would be plenty for any command-line arguments we may want to pass.

XWriteTitleInfoAndRebootA("D:\\Halo2.xbe", "\\Device\\CdRom0", LDT_TITLE, 0x4D530004, &launchData);


This code works great. I can pass anything I want to the xbe I am launching including up to a 2932 character command-line argument.

Now lets say that D:\ wasn't actually mapped to "\\Device\\CdRom0" but instead to "\\Device\\Harddrisk0\\Partition6\\Games\\MyApp" (which is equivalent to F:\Games\MyApp). Well now this code doesn't work because I am mapping D: to the wrong path. This leaves me choosing between two possible solutions:

1) Ask the user exactly where to find the XBE to be launched. This is inconvenient because you have to inform the user that they should only select it within the D: path if the actual location of the xbe is the DVD drive.
2) Query the actual mapping. This option ftw.

I'm not sure if the second option is possible but, if it is, I would love to know how to do it. Thanks to anyone that can provide any information.

As an added note, another function found within the undocumented.h header is:

CODE
extern "C" INT WINAPI XWriteTitleInfoNoReboot(LPVOID,LPVIOD,DWORD,DWORD,LPVOID);


The declaration is exactly the same as the other function. But, if you were to try to use this you would get a linker error due to the non-existent _XWriteTitleInfoNoReboot@20. This is because, should you look in xapilib.lib, it is actually _XwriteTitleInfoNoReboot@24. It has an extra parameter. Maybe it changed after undocumented.h was produced. Anyway, the extra parameter is after pszDDrivePath and it is DWORD fAllowDDriveMapping. It seems to specify whether or not the D drive can be mapped. I was slightly hopeful that if you sent a 0 into it the pszDDrivePath parameter would be ignored and it would use the current mapping. It seems that it does cause pszDDrivePath to be ignored but it doesn't use the current mapping. I am not absolutely sure but I believe it forces the mapping to be the DVD drive no matter what. I don't really see how that parameter is useful.

On top of that I am not sure how to make the Title launch once you are done with this function besides sending the console a warm reboot. Does anyone know anything more about this function?
Logged

ldotsfan

  • Archived User
  • Hero Member
  • *
  • Posts: 2072
Determine Drive Mapping
« Reply #1 on: July 16, 2010, 08:06:00 PM »

Can we do this differently? Force the drive mapping to be what we want.

XBMC runs from Q drive and remaps Q to whenever the XBE was launched from.
http://xbmc4xbox.svn.....pe=text/plain
CODE

// map Q to home drive of xbe to load the config file
  CUtil::GetHomePath(strExecutablePath);
  CIoSupport::GetPartition(strExecutablePath.c_str()[0], szDevicePath);
  strcat(szDevicePath, &strExecutablePath.c_str()[2]);
  CIoSupport::RemapDriveLetter('Q', szDevicePath);

This is done via IoDeleteSymbolicLink and IoCreateSymbolicLink behind the scene in
http://xbmc4xbox.svn.....pe=text/plain

It determines the actual location of where the XBE was launched via XeImageFileName
CODE

VOID CIoSupport::GetXbePath(char* szDest)
{
#ifdef _XBOX
  //Function to get the XBE Path like:
  //E:\DevKit\xbplayer\xbplayer.xbe

  char szTemp[MAX_PATH];
  char cDriveLetter = 0;

  strncpy(szTemp, XeImageFileName->Buffer + 8, XeImageFileName->Length - 8);
  szTemp[20] = 0;
  GetDrive(szTemp, &cDriveLetter);

  strncpy(szTemp, XeImageFileName->Buffer + 29, XeImageFileName->Length - 29);
  szTemp[XeImageFileName->Length - 29] = 0;

  sprintf(szDest, "%c:\\%s", cDriveLetter, szTemp);

#else
  GetCurrentDirectory(XBMC_MAX_PATH, szDest);
  strcat(szDest, "\\XBMC_PC.exe");
#endif
}


In your case, you will remap D to whenever the XBE was launched from prior to the call to XWriteTitleInfoAndRebootA.  XBMC's IOSupport.cpp has other code which deals with drive mappings. If my suggestion doesn't work, you can look at those as well.

I hope this helps.
Logged

Hyper_Eye

  • Recovered User
  • Sr. Member
  • *
  • Posts: 366
Determine Drive Mapping
« Reply #2 on: July 16, 2010, 11:00:00 PM »

Thanks ldotsfan! That had exactly what I needed in it: XeImageFileName

Another undocumented bit that is crucial to making this work. So for any who ever wants to be able to launch an xbe with command-line parameters here is the code from above modified to work.

CODE
#include

typedef struct _STRING
{
    USHORT  Length;
    USHORT  MaximumLength;
    PSTR    Buffer;
} UNICODE_STRING, *PUNICODE_STRING, ANSI_STRING, *PANSI_STRING;

extern "C" INT WINAPI XWriteTitleInfoAndRebootA(LPVOID,LPVOID,DWORD,DWORD,LPVOID);
extern "C" PANSI_STRING XeImageFileName;

void __cdecl main()
{
    LAUNCH_DATA   launchData = { LDT_TITLE };
    long          pathLen;
    char         *mntDev;
    char         *p;

    p = strrchr(XeImageFileName->Buffer, '\\') + 1;
    pathLen = (long)p - (long)XeImageFileName->Buffer;
    mntDev = (char *)malloc(pathLen + 1);
    memcpy(mntDev, XeImageFileName->Buffer, pathLen);
    mntDev[pathLen] = '\0'; // This is necessary

    // Halo 2 obviously won't parse this but my app will so lets pretend like Halo 2 will.
    strcpy(((PLD_DEMO)&launchData)->szLauncherXBE, "MyXbe.xbe");
    strcpy((char*)((PLD_DEMO)&launcData)->Reserved, "SomeCommandLineArgs"); // I can put anything I want in here. Using the PLD_DEMO structure we get 2932 bytes in the reserved field to work with which I hope would be plenty for any command-line arguments we may want to pass.

    XWriteTitleInfoAndRebootA("Halo2.xbe", mntDev, LDT_TITLE, 0x4D530004, &launchData);
}


Unlike what I said earlier, the first parameter to XWriteTitleInfoAndRebootA() needs to be the xbe name only. Do not include the drive letter on the front of it. Having passed the correct mapping for drive D this will now launch an xbe residing in the same directory as the currently running one and, having filled in LAUNCH_DATA as we wanted it, will send our command-line options (or whatever you felt like packing in there) to the launched xbe.

Now, on the other side, I take them and turn them into the equivalent of argv and argc:

CODE
#include

void __cdecl main()
{
    DWORD          launchDataType;
    LAUNCH_DATA    launchData;
    char          *xargv[100];
    int            xargc = 1;

    xargv[0] = strdup("D:\\default.xbe"); // mimic argv[0]

    if(XGetLaunchInfo(&launchDataType, &launchData) == ERROR_SUCCESS)
    {
        if(launchDataType == LDT_FROM_DEBUGGER_CMDLINE)
            xargv[xargc] = strtok(((PLD_FROM_DEBUGGER_CMDLINE)&launchData)->szCmdLine, " ");
        else if(launchDataType == LDT_TITLE)
            xargv[xargc] = strtok((char *)((PL_DEMO)&launchData)->Reserved, " ");

        while(xargv[argc] != NULL)
        {
            xargc++;
            xargv[xargc] = strtok(NULL, " ");
        }
    }

    ParseCommandLine(xargv, xargc);
}


The good thing is that it will handle both the case where you are sending command line options from the XDK debugger (in MSVC++ Project->Properties->Debugging->Command Arguments) or from your own application. You could parse them right out of szCmdLine if you wanted to but I prefer to handle them as standard arguments. If you want to be able to send a command-line larger than 2932 you could just pack the data field of LAUNCH_DATA and not typecast it at all I would be willing to bet. That would give you a reserved field of 3072 bytes. But, some of the info you can pack PLD_DEMO with is useful especially if you want to return to the original XBE when you are finished.

Thanks for the help ldotsfan. Another XBox dev problem solved.
Logged

ldotsfan

  • Archived User
  • Hero Member
  • *
  • Posts: 2072
Determine Drive Mapping
« Reply #3 on: July 17, 2010, 09:01:00 AM »

QUOTE(Hyper_Eye @ Jul 17 2010, 01:00 PM) View Post

Another XBox dev problem solved.

I see that the code has been checked into Odamex SVN. This must be intended for the exchange of data from the Launcher to Odamex. Looking forward for the release when it is ready.
Logged

Hyper_Eye

  • Recovered User
  • Sr. Member
  • *
  • Posts: 366
Determine Drive Mapping
« Reply #4 on: July 17, 2010, 03:31:00 PM »

The part that parses the parameters went in. I haven't committed any launcher code but yes things are progressing.  biggrin.gif
Logged