Example #1
0
def execute_elevated(*args):
    # FIXME: support **kwargs
    from win32com.shell.shell import ShellExecuteEx
    from win32com.shell import shellcon
    import win32process, win32event
    import winxpgui
    import win32api
    import win32con
    try:
        hwnd = winxpgui.GetConsoleWindow()
    except winxpgui.error:
        hwnd = 0
    parameters = ""
    if not hasattr(sys, "frozen"):
        # Not running under py2exe exe
        parameters += "\"" + sys.argv[0] + "\" "
    parameters += " ".join(map(lambda x: "\"" + str(x) + "\"", args))
    print "Executing elevated with parameters " + parameters
    # TODO: capture output (maybe via named pipe)
    rc = ShellExecuteEx(hwnd=hwnd,
                        fMask=shellcon.SEE_MASK_NOCLOSEPROCESS,
                        lpVerb="runas",
                        lpFile=sys.executable,
                        lpParameters=parameters,
                        nShow=win32con.SW_SHOW)
    hproc = rc['hProcess']
    win32event.WaitForSingleObject(hproc, win32event.INFINITE)
    exit_code = win32process.GetExitCodeProcess(hproc)
    if exit_code:
        raise Exception("Error: subprocess failed (exit code %s)." % exit_code)
Example #2
0
def UseCommandLine(*classes, **flags):
    unregisterInfo = '--unregister_info' in sys.argv
    unregister = '--unregister' in sys.argv
    flags['quiet'] = flags.get('quiet', 0) or '--quiet' in sys.argv
    flags['debug'] = flags.get('debug', 0) or '--debug' in sys.argv
    flags['unattended'] = flags.get('unattended',
                                    0) or '--unattended' in sys.argv
    if unregisterInfo:
        return UnregisterInfoClasses(*classes, **flags)
    try:
        if unregister:
            UnregisterClasses(*classes, **flags)
        else:
            RegisterClasses(*classes, **flags)
    except win32api.error, exc:
        # If we are on xp+ and have "access denied", retry using
        # ShellExecuteEx with 'runas' verb to force elevation (vista) and/or
        # admin login dialog (vista/xp)
        if flags['unattended'] or exc[0] != winerror.ERROR_ACCESS_DENIED \
           or sys.getwindowsversion()[0] < 5:
            raise
        from win32com.shell.shell import ShellExecuteEx
        from win32com.shell import shellcon
        import win32process, win32event
        import winxpgui  # we've already checked we are running XP above

        if not flags['quiet']:
            print "Requesting elevation and retrying..."
        new_params = " ".join(['"' + a + '"' for a in sys.argv])
        # specifying the parent means the dialog is centered over our window,
        # which is a good usability clue.
        # hwnd is unlikely on the command-line, but flags may come from elsewhere
        hwnd = flags.get('hwnd', None)
        if hwnd is None:
            try:
                hwnd = winxpgui.GetConsoleWindow()
            except winxpgui.error:
                hwnd = 0
        rc = ShellExecuteEx(hwnd=hwnd,
                            fMask=shellcon.SEE_MASK_NOCLOSEPROCESS,
                            lpVerb="runas",
                            lpFile=win32api.GetShortPathName(sys.executable),
                            lpParameters=new_params,
                            lpDirectory=os.getcwd(),
                            nShow=win32con.SW_SHOW)
        # Output is lost to the new console which opens, so the
        # best we can do is get the exit code of the process.
        hproc = rc['hProcess']
        win32event.WaitForSingleObject(hproc, win32event.INFINITE)
        exit_code = win32process.GetExitCodeProcess(hproc)
        if exit_code:
            # Even if quiet you get to see this error.
            print "Error: registration failed (exit code %s)." % exit_code
            print "Please re-execute this command from an elevated command-prompt"
            print "to see details about the error."
        else:
            if not flags['quiet']:
                print "Elevated process succeeded."
Example #3
0
def ReExecuteElevated(flags):
  from win32com.shell.shell import ShellExecuteEx
  from win32com.shell import shellcon
  import win32process, win32event
  import winxpgui # we've already checked we are running XP above
  import tempfile

  if not flags['quiet']:
    print("Requesting elevation and retrying...")
  new_params = " ".join(['"' + a + '"' for a in sys.argv])
  # If we aren't already in unattended mode, we want our sub-process to
  # be.
  if not flags['unattended']:
    new_params += " --unattended"
  # specifying the parent means the dialog is centered over our window,
  # which is a good usability clue.
  # hwnd is unlikely on the command-line, but flags may come from elsewhere
  hwnd = flags.get('hwnd', None)
  if hwnd is None:
    try:
      hwnd = winxpgui.GetConsoleWindow()
    except winxpgui.error:
      hwnd = 0
  # Redirect output so we give the user some clue what went wrong.  This
  # also means we need to use COMSPEC.  However, the "current directory"
  # appears to end up ignored - so we execute things via a temp batch file.
  tempbase = tempfile.mktemp("pycomserverreg")
  outfile = tempbase + ".out"
  batfile = tempbase + ".bat"
  try:
    batf = open(batfile, "w")
    try:
      cwd = os.getcwd()
      print("@echo off", file=batf)
      # nothing is 'inherited' by the elevated process, including the
      # environment.  I wonder if we need to set more?
      print("set PYTHONPATH=%s" % os.environ.get('PYTHONPATH', ''), file=batf)
      # may be on a different drive - select that before attempting to CD.
      print(os.path.splitdrive(cwd)[0], file=batf)
      print('cd "%s"' % os.getcwd(), file=batf)
      print('%s %s > "%s" 2>&1' % (win32api.GetShortPathName(sys.executable), new_params, outfile), file=batf)
    finally:
      batf.close()
    executable = os.environ.get('COMSPEC', 'cmd.exe')
    rc = ShellExecuteEx(hwnd=hwnd,
                        fMask=shellcon.SEE_MASK_NOCLOSEPROCESS,
                        lpVerb="runas",
                        lpFile=executable,
                        lpParameters='/C "%s"' % batfile,
                        nShow=win32con.SW_SHOW)
    hproc = rc['hProcess']
    win32event.WaitForSingleObject(hproc, win32event.INFINITE)
    exit_code = win32process.GetExitCodeProcess(hproc)
    outf = open(outfile)
    try:
      output = outf.read()
    finally:
      outf.close()

    if exit_code:
      # Even if quiet you get to see this message.
      print("Error: registration failed (exit code %s)." % exit_code)
    # if we are quiet then the output if likely to already be nearly
    # empty, so always print it.
    print(output, end=' ')
  finally:
    for f in (outfile, batfile):
      try:
        os.unlink(f)
      except os.error as exc:
        print("Failed to remove tempfile '%s': %s" % (f, exc))