2

I trying to execute following bat file in c++ using win32 api.Following is code for execution.

  //#include "Shellapi.h"
    #include "Windows.h"
    int _tmain(int argc, _TCHAR* argv[])
    {
        ShellExecute(GetDesktopWindow(), "sa.bat","", NULL, NULL, SW_SHOWNORMAL);
        DWORD LastError = GetLastError();
        return 0;
    }

but it is not working.

following is content "sa.bat"

C:\windows\system32\wusa /uninstall /kb:2718695 /quiet /forcerestart

but last error returns 1155.

Aryan
  • 29
  • 1
  • 1
  • 4
  • 1
    Compare your arguments: http://msdn.microsoft.com/en-ca/library/windows/desktop/bb762153(v=vs.85).aspx – chris May 18 '13 at 07:46
  • You fumbled the arguments, "sa.bat" should be passed as the **third** argument. – Hans Passant May 18 '13 at 11:40
  • @HansPassant No its not :-(.I thing so some thing wrong with batch command.Did you thing so??Please my new question. – Aryan May 18 '13 at 11:47

4 Answers4

7

Try this:

//#include "Shellapi.h"
#include "Windows.h"
int _tmain(int argc, _TCHAR* argv[])
{
  HINSTANCE hReturnCode=ShellExecute(NULL, _T("open"), _T("cmd.exe"), _T("/C sa.bat"), NULL, SW_SHOWNORMAL);
  DWORD LastError = GetLastError();
  return 0;
}

[EDITED] This working suggestion is from Chris:

    //#include "Shellapi.h"
    #include "Windows.h"
    int _tmain(int argc, _TCHAR* argv[])
    {
      HINSTANCE hReturnCode=ShellExecute(NULL, _T("open"), _T("sa.bat"), NULL, NULL, SW_SHOWNORMAL);
      DWORD LastError = GetLastError();
      return 0;
    }
Leo Chapiro
  • 13,678
  • 8
  • 61
  • 92
  • 2
    The batch file should work as the third argument, shouldn't it? I've used them in place of executables in other places. – chris May 18 '13 at 07:47
  • Well, I just tested it, and it does run my batch file without routing through cmd. – chris May 18 '13 at 07:53
  • In this case I would post your suggestion as an answer - my upvote have you already :) – Leo Chapiro May 18 '13 at 07:55
  • 1
    It's already part of your answer. All I was hinting towards was needing "open" and moving the batch file to the next argument. Both of these ways worked when I tested them. – chris May 18 '13 at 07:56
4

.BAT files are not executable binaries, so batch file alone does not take off, instead it is started with command interpreter (CMD.EXE). On ShellExecute you either start it with CMD /C directly, or you leverage registry assotiation which starts .BAT file with an "open" verb.

See:

You apparently don't attempt to start CMD.EXE, so the association.

The error code you get is ERROR_NO_ASSOCIATION "No application is associated with the specified file for this operation." and it refers to ShellExecute API, not to the contents of your batch file.

SE_ERR_NOASSOC

There is no application associated with the given file name extension. This error will also be returned if you attempt to print a file that is not printable.

This means that ShellExecute could not figure out your arguments. The file should go third, not second, and then second argument would be "open" or NULL (verb). Applying the verb onto .BAT file would make the .BAT file "run".

Community
  • 1
  • 1
Roman R.
  • 68,205
  • 6
  • 94
  • 158
  • .bat files may not themselves be binary executables, but they are directly executable via ShellExecute/Ex() since they are associated with cmd.exe in the Registry. Both articles you link to are using cmd.exe because they utilize extra functionality that requires it. – Remy Lebeau May 19 '13 at 07:20
  • @RemyLebeau: I clarified that. – Roman R. May 19 '13 at 07:57
2

This will also work:

#include <windows.h>
#include <stdio.h>
int main()
{
   STARTUPINFO si;
   PROCESS_INFORMATION pi;

   ZeroMemory( &si, sizeof(si) );
   si.cb = sizeof(si);
   ZeroMemory( &pi, sizeof(pi) );
   if( !CreateProcess( NULL, "cmd /C  sa.bat", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)  )
   {
     printf( "CreateProcess failed (%d)\n", GetLastError() );
     return FALSE;
   }
   WaitForSingleObject( pi.hProcess, INFINITE );
   CloseHandle( pi.hProcess );
   CloseHandle( pi.hThread );
   return 0;
}
Sohail xIN3N
  • 2,951
  • 2
  • 30
  • 29
1

ShellExecute() reports errors via its own return value, not via GetLastError(). You also need to pass the filename in the lpFile parameter, not the lpOperation parameter.

Try this:

//#include "Shellapi.h"
#include "Windows.h"
int _tmain(int argc, _TCHAR* argv[])
{
    int nErrorCode = (int) ShellExecute(NULL, NULL, "sa.bat", NULL, NULL, SW_SHOWNORMAL);
    if (nErrorCode <= 32)
      // an error occurred...
    return 0;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770