Jump to content


This is a ready-only archive of the InstallSite Forum. You cannot post any new content here. / Dies ist ein Archiv des InstallSite Forums. Hier können keine neuen Beiträge veröffentlicht werden.
Photo

LaunchAppAndWait never returns from batch file


8 replies to this topic

WJPOConnor

WJPOConnor
  • Full Members
  • 10 posts

Posted 28 November 2006 - 22:34

I have a strange situation. I have an InstallShield function that validates an Oracle User Name and Password. It does this by calling a batch file using LaunchAppAndWait and then reading the result back from a LOG file. The installation is going to be running on Win2K.

Here's the relevant code:

InstallScript function:
CODE
szProgram = SUPPORTDIR ^ "CheckOraclePassword.bat";
szLogFile = SUPPORTDIR ^ "CheckOraclePassword.log";
szCmdLine = tszOracleHome + " " + tszUserName + "/" + tszPassword + "@" + tszTNSName;
// If the user is testing SYS, add the AS SYSDBA function.
if tszUserName = "SYS" then
szCmdLine = szCmdLine + " AS SYSDBA";
endif;
Log("CheckOracleUser: Validating Oracle login for " + tszUserName);
// Default return value is "UNKNOWN".
szRetVal = "UNKNOWN";
if Is(FILE_EXISTS, szProgram) then
Log("Batch file exists: " + szProgram);
// Run the batch file.
iRetVal = LaunchAppAndWait(szProgram, szCmdLine, LAAW_OPTION_WAIT); // | LAAW_OPTION_HIDDEN);
Log("Returned from batch file.");
endif;

Batch file:
CODE
@@echo off
SET CONNECTION=%1

DEL CheckOraclePassword.log

%ORACLE_HOME%\BIN\SQLPLUS.EXE /nolog @CheckOraclePassword.sql %CONNECTION%

SQL Script:
CODE
spool CheckOraclePassword.log
DEFINE sys_connect = &&1
CONNECT &&sys_connect
EXIT


I currently have the LAAW_OPTION_HIDDEN commented out for debugging purposes. The Log function is a wrapper for the SprintfMsiLog InstallScript function that creates a custom log file if the system is Win2K.

What I observe is the install getting to the LaunchAppAndWait and then never leaving it. I see the DOS window open. The LOG file from the SQL script is created and contains the proper information. The DOS window closes, but the program never continues. If I kill the MSIEXEC process for the install, the script will continue (i.e. the log file is updated with the next steps in the install).

When I test it out on my WinXP development machine, it works perfectly and, in fact, this was working fine up until a day ago even on the Win2K system.

Further testing even shows that the LAAW_OPTION_WAIT parameter doesn't matter. It freezes no matter what is put in the third parameter in LaunchAppAndWait.

I'm under a looming deadline at the moment, so any assistance I can get would be very appreciated.

Stefan Krueger

Stefan Krueger

    InstallSite.org

  • Administrators
  • 13,269 posts

Posted 29 November 2006 - 14:19

Are you calling this script as a custom action? How and where do you launch that custom action? Using DoAction from a dialog button?

WJPOConnor

WJPOConnor
  • Full Members
  • 10 posts

Posted 29 November 2006 - 16:29

Yes. It's being called by a DoAction on the Next button. The way I have it set up is:

DoAction, ValidateOracleUser, 1
NewDialog, SetupType, ORACLE_CONNECT_STATUS <> "INVALID"

The ValidateOracleUser function handles the UI portion of the function. It pulls the Oracle Home, User Name, Password and SID from the property table. The CheckOracleUser accepts these values as parameters. My Validate functions are installer specific; they handle maintaining properties and taking care of the user interface. The Check functions are generic; they generally can't be called by custom actions and don't normally have any user interface (i.e. MessageBox, SprintfBox, etc.). The communication between the two functions is handled by return values or variables passed by reference.

Here are the full functions:
CODE
   export prototype ValidateOracleUser(HWND);
function ValidateOracleUser(thMsi)
STRING  svOracleUserName, svOraclePassword, svOracleHome, szOracleTNS;
STRING  szRetVal;
INT  iRetVal, iSize;
begin
/*
 Apparently, Windows 2000 doesn't allow the use of SprintfMsiLog in
 custom actions called from Dialog "DoAction" events.
*/
MsiGetProperty(thMsi, "ORACLE_USER", svOracleUserName, iSize);
MsiGetProperty(thMsi, "ORACLE_PASSWORD", svOraclePassword, iSize);
MsiGetProperty(thMsi, "ORACLE_HOME", svOracleHome, iSize);
szOracleTNS = "LDB";

Log("Validating Oracle User Name: " + svOracleUserName);
if svOracleUserName != "" && svOraclePassword != "" then
 //szRetVal = CheckOracleUser(svOracleHome, svOracleUserName, svOraclePassword, szOracleTNS);
 szRetVal = "CONNECTED";
 Log("Validating Oracle User Name: CheckOracleUser Return Value: " + szRetVal);
 if szRetVal = "CONNECTED" then
  MsiSetProperty(thMsi, "ORACLE_CONNECT_STATUS", "VALID");
 elseif szRetVal = "ORA-01017" then
  MsiSetProperty(thMsi, "ORACLE_CONNECT_STATUS", "INVALID");
  MessageBox("Invalid User Id or Password."
   + "\nPlease Try Again!", INFORMATION);
 elseif szRetVal = "ORA-28000" then
  MsiSetProperty(thMsi, "ORACLE_CONNECT_STATUS", "INVALID");
  MessageBox("That account is locked."
   + "\nPlease try again with a different user.", INFORMATION);
 elseif szRetVal = "ORA-28001" | szRetVal = "ORA-28049" then
  MsiSetProperty(thMsi, "ORACLE_CONNECT_STATUS", "INVALID");
  MessageBox("The password for that account has expired."
   + "\nPlease try again with a different user.", INFORMATION);
 elseif szRetVal = "ORA-28002" then
  MsiSetProperty(thMsi, "ORACLE_CONNECT_STATUS", "VALID");
  // This password will expire soon, but still works, which is good enough.
 elseif szRetVal = "UNKNOWN" then
  MsiSetProperty(thMsi, "ORACLE_CONNECT_STATUS", "INVALID");
  MessageBox("An unknown error occurred while validating the Oracle User Name and Password."
   + "\nPlease check your Oracle service and try again later!", SEVERE);
 else
  MsiSetProperty(thMsi, "ORACLE_CONNECT_STATUS", "INVALID");
  MessageBox("An unknown error occurred while validating the Oracle User Name and Password(2)."
   + "\nPlease check your Oracle service and try again later!", SEVERE);
 endif;
 
 //SprintfMsiLog("Validation of Oracle User Id %s received %s", svOracleUserName, szRetVal);
else
 MsiSetProperty(thMsi, "ORACLE_CONNECT_STATUS", "INVALID");
 MessageBox("You must enter an Oracle User Name and Password to continue.", WARNING);
endif;
end;

CODE
/*
CheckOracleUser accepts four parameters and returns one string.
 1) The location of the Oracle Home directory.
 2) The Oracle User Name to be validated.
 3) The Oracle Password to be validated.
 4) The Oracl TNS Name to the instance.
The function returns either "CONNECTED", "UNKNOWN" or the Oracle error code.
It attempts no user interface. All that must be handled by the calling function.
It requires two files to be in SUPPORTDIR:
 CheckOraclePassword.bat
 CheckOraclePassword.sql
If these files aren't there, the function will return UNKNOWN.

CheckOraclePassword.sql:

 spool CheckOraclePassword.log
 DEFINE sys_connect = &&1
 CONNECT &&sys_connect
 EXIT

CheckOraclePassword.bat:

 @@echo off
 SET ORACLE_HOME=%1
 SET CONNECTION=%2
 
 %ORACLE_HOME%\BIN\SQLPLUS.EXE /nolog @CheckOraclePassword.sql %CONNECTION%
*/
export prototype STRING CheckOracleUser(STRING, STRING, STRING, STRING);

function STRING CheckOracleUser(tszOracleHome, tszUserName, tszPassword, tszTNSName)
STRING  szProgram, szCmdLine, szRetVal, szLogFile, szMsg, szBatch, szDir;
INT  iRetVal, iIndex;
STRING svLogLine;
LIST listFile;
HWND hProcess;
begin
iIndex = 0;
// Convert passed strings to upper case.
StrToUpper(tszUserName, tszUserName);
StrToUpper(tszPassword, tszPassword);
StrToUpper(tszTNSName, tszTNSName);
// Initialize the variables to be sent to the LAAW function.
// CheckOraclePassword.bat and CheckOraclePassword.sql must be in the
// Support Files/Language Independent section of the project.
szProgram = SUPPORTDIR ^ "CheckOraclePassword.bat";
szLogFile = SUPPORTDIR ^ "CheckOraclePassword.log";
LongPathToShortPath(szProgram);
LongPathToShortPath(tszOracleHome);
szCmdLine = tszOracleHome + " " + tszUserName + "/" + tszPassword + "@" + tszTNSName;
// If the user is testing SYS, add the AS SYSDBA function.
if tszUserName = "SYS" then
 szCmdLine = szCmdLine + " AS SYSDBA";
endif;
Log("CheckOracleUser: Validating Oracle login for " + tszUserName);
// Default return value is "UNKNOWN".
szRetVal = "UNKNOWN";
if Is(FILE_EXISTS, szProgram) then
 Log("Batch file exists: " + szProgram);
 // Run the batch file.
 /*_LaunchAppEx(
  szProgram,
  szCmdLine,
  WAIT,
  TRUE,
  10000,
  SUPPORTDIR,
  iRetVal);*/
 iRetVal = LaunchAppAndWait(szProgram, szCmdLine, LAAW_OPTION_NOWAIT); // | LAAW_OPTION_HIDDEN);
 Log("Returned from batch file.");
 Sprintf(szMsg, "Return Value: %d, Process Id: %d", iRetVal, LAAW_PROCESS_INFORMATION.dwProcessId);
 Log(szMsg);
 hProcess = LAAW_PROCESS_INFORMATION.hProcess;
 WaitForSingleObject(hProcess, -1);
 
 if Is(FILE_EXISTS, szLogFile) then
  // A log file was created. Read it into memory.
  listFile = ListCreate(STRINGLIST);
  ListReadFromFile(listFile, SUPPORTDIR ^ "CheckOraclePassword.log");
  // Get the first line.
  iRetVal = ListGetFirstString(listFile, svLogLine);
  if iRetVal = 0 then
   // If the first line says there's an error...
   if svLogLine = "ERROR:" then
    // Get the error from the second line.
    iRetVal = ListGetNextString(listFile, svLogLine);
    Log("Error received: " + svLogLine);
    StrSub(szRetVal, svLogLine, 0, 9);
    Log("Returning value: " + szRetVal);
    //MessageBox("Error Received: " + szRetVal, INFORMATION);
   else
    // The log file was created and the first line doesn't
    // say ERROR:. Therefore, we assume that the connection
    // succeeded.
    szRetVal = "CONNECTED";
    Log("Connected to Oracle using " + tszUserName);
   endif;
  endif;
  ListDestroy(listFile);
 else
  Log("Could not find LOG file.");
 endif;
else
 iRetVal = SprintfBox(MB_ICONQUESTION + MB_YESNO, "Check Oracle User", "Unable to find a file used in checking the Oracle User Name and Password.\nContinue the installation with the unverified password?");
 if iRetVal = IDYES then
  szRetVal = "CONNECTED";
 else
  abort;
 endif;
endif;
return szRetVal;
end;


Stefan Krueger

Stefan Krueger

    InstallSite.org

  • Administrators
  • 13,269 posts

Posted 29 November 2006 - 17:22

You could try without the SprintfMsiLog. I guess it calls MsiProcessMessage internally which is documented to fail from a DoAction control event.

Also there's a known problem which might be related. Search for "Setup Hangs During MSI API Call" at http://installsite.o...bugs_isd800.htm

WJPOConnor

WJPOConnor
  • Full Members
  • 10 posts

Posted 29 November 2006 - 17:52

Well, I had noticed that MsiSprintfLog didn't work in a DoAction and, in Win2K, was causing the install to hang, so my Log function checks the system version and uses the File Open/Create/Write functions to create a separate log file. I'm commenting them out entirely so I can see if I inadvertantly left one in there.

WJPOConnor

WJPOConnor
  • Full Members
  • 10 posts

Posted 29 November 2006 - 18:02

Same result. The most frustrating part of this is that it was working perfectly just last week. I've even gone to the extent of ghosting the system to a previous image, just to ensure that I hadn't made any changes to the system that would account for this.

Is it possible that my ISD is corrupt in some way? Should I remove and reinstall it?

WJPOConnor

WJPOConnor
  • Full Members
  • 10 posts

Posted 29 November 2006 - 19:51

I downloaded the _LaunchAppEx from InstallSite and modified it to work with IS11. Since this uses the CreateProcessA directly, I thought it might work where LaunchAppAndWait failed. Unfortunately, it gets the same result.

WJPOConnor

WJPOConnor
  • Full Members
  • 10 posts

Posted 30 November 2006 - 20:48

I finally figured out what was going on. The program and command line entries ended up being too long for Windows 2000, but not Windows XP. From what I could tell, whatever method the Windows API was using to track the status of the process was getting stuck due to the extremely long strings being passed to it. I copy the BAT and SQL file to a short temporary directory right off the root of the windows volume and the problem goes away.
The issue apparently started when I added the Oracle home directory to the command line. This must have put it over some limit that was increased in Windows XP. So, when I tested it on my development system, it worked fine. When I moved it to my Win2K test environment, it failed.

Thanks for the help, Stefan!

Stefan Krueger

Stefan Krueger

    InstallSite.org

  • Administrators
  • 13,269 posts

Posted 30 November 2006 - 22:51

If you have a copy of the old (working) setup you could try a MSI diff.

Edit: I just noticed that you were able to solve the problem.