【问题标题】:How to determine if win32api.ShellExecute was successful using hinstance?如何使用 hinstance 确定 win32api.ShellExecute 是否成功?
【发布时间】:2013-08-02 20:49:12
【问题描述】:

我一直在寻找原始问题的答案。我如何(以编程方式)确定我的 win32api.ShellExecute 语句是否成功执行,如果成功执行,则执行 os.remove() 语句。

研究我发现 ShellExecute() 调用返回 HINSTANCE。进一步挖掘我发现 ShellExecute() 如果成功,将返回 HINSTANCE > 32。我现在的问题/问题是,我如何使用它来控制程序的其余部分?我尝试使用if HINSTANCE> 32: 语句来控制下一部分,但我收到了NameError: name 'hinstance' is not defined 消息。通常这不会让我感到困惑,因为这意味着我需要在引用它之前定义变量“hinstance”;但是,因为我认为 ShellExecute 应该返回 HINSTANCE,所以我认为它可以使用?

这是我尝试实现此功能的完整代码。请注意,在我的 print_file() def 中,我将 hinstance 分配给完整的 win32api.ShellExecute() 命令,以尝试捕获 hinstance 并在函数末尾显式返回它。这也不起作用。

import win32print
import win32api
from os.path import isfile, join
import glob
import os
import time

source_path = "c:\\temp\\source\\"

def main():
    printer_name = win32print.GetDefaultPrinter()
    while True:
        file_queue = [f for f in glob.glob("%s\\*.txt" % source_path) if isfile(f)]
        if len(file_queue) > 0:
            for i in file_queue:
                print_file(i, printer_name)
                if hinstance > 32:
                    time.sleep(.25)
                    delete_file(i)
                print "Filename: %r has printed" % i
                print
                time.sleep(.25)
                print                
        else:
            print "No files to print. Will retry in 15 seconds"
        time.sleep(15)


def print_file(pfile, printer):
    hinstance = win32api.ShellExecute(
        0,
        "print",
        '%s' % pfile,
        '/d:"%s"' % printer,
        ".",
        0
        )
    return hinstance


def delete_file(f):
    os.remove(f)
    print f, "was deleted!"

def alert(email):
    pass

main()

【问题讨论】:

  • ShellExecute 返回一个HINSTANCE 类型的值,与任何变量名无关。你还需要hinstance = print_file(...)
  • 啊哈!这是有道理的。现在看来,这对我来说是一个愚蠢的疏忽。谢谢你。我调整了代码,使 print_file 只运行 win32api.ShellExecute(...) 而没有任何 hinstance 位,并将 main() 中的部分更改为就像您引用 hinstance = print_file(...) 但现在 print_file() 返回 None 而不是像以前那样的 42L。有什么想法吗?
  • 只有在print_file返回的情况下,调用者才能得到值
  • 好的,我明白我做错了什么。我调整了我的 print_file() 函数以返回 hinstance。所以现在 for 循环看起来像:pastebin.com/yTX461JT 你觉得怎么样?
  • 那个 pastebin 是 Drew 在他的评论中建议的,也是我在回答中写的。我觉得没有什么要补充的了,

标签: python winapi python-2.7 pywin32 shellexecute


【解决方案1】:

使用ShellExecute,您永远不会知道打印何时完成,这取决于文件的大小以及打印机驱动程序是否缓冲内容(打印机可能正在等待您填满纸盘,例如)。

根据this SO answer,看起来subprocess.call()是一个更好的解决方案,因为它等待命令完成,只有在这种情况下你需要读取注册表来获取与文件关联的exe。

ShellExecuteEx 可从pywin32 获得,您可以执行以下操作:

import win32com.shell.shell as shell
param = '/d:"%s"' % printer
shell.ShellExecuteEx(fmask = win32com.shell.shellcon.SEE_MASK_NOASYNC, lpVerb='print', lpFile=pfile, lpParameters=param)

编辑:等待 ShellExecuteEx() 句柄的代码

import win32com.shell.shell as shell
import win32event
#fMask = SEE_MASK_NOASYNC(0x00000100) = 256 + SEE_MASK_NOCLOSEPROCESS(0x00000040) = 64
dict = shell.ShellExecuteEx(fMask = 256 + 64, lpFile='Notepad.exe', lpParameters='Notes.txt')
hh = dict['hProcess']
print hh
ret = win32event.WaitForSingleObject(hh, -1)
print ret

【讨论】:

  • subprocess.call 不会处理 shell 动词打印。 ShellExecuteEx 将返回一个您可以等待的进程句柄。无需等到打印机完成。直到应用程序将打印作业排入队列。
  • @DavidHeffernan:我确实提到了subprocess.call,您需要从注册表中获取 exe 名称——回复ShellExecuteEx,您是对的,您需要调用WaitForSingleObject返回 dict 值的句柄 (ref SO answer)
  • @Cyber​​Samurai 确实如此。请注意,您可能不一定会获得进程句柄。并非所有关联/动词组合都会产生您可以等待的进程句柄。如果记事本正在打印,那么我认为您将获得一个进程句柄。但是,如果它是您要打印的图像,并且与默认系统图像预览器关联,则不要期望进程句柄。
  • @EdwardClements 我在玩你的 ShellExecuteEx 代码 sn-p,我遇到了 win32com.shell.shellcon.SEE_MASK_NOASYNC 位的问题。它不喜欢 SEE_MASK_NOASYNC 部分。我尝试过导入 win32com、win32com.shell、win32com.shell.shellcon 甚至 from win32com.shell.shellcon import *,但每次尝试使用该位时都会得到 AttributeError: 'module' object has no attribute 'SEE_MASK_NOASYNC'。看着MSDN,我可能只需要输入fmask = 'SEE_MASK_NOASYNC'。对不起,如果这是一个完全的菜鸟错误,只是不知道如何亲
  • 我发现ShellExecuteEx 需要一个额外的掩码值SEE_MASK_NOCLOSEPROCESS (0x00000040) 来返回句柄,我添加了对我有用的代码(上面)——你可能不想无限地等待进程完成(以防挂起)但放置一个合理的值等待并提示是否继续......
【解决方案2】:

ShellExecute的返回值是你需要测试的。您从print_file 返回它,但随后您忽略它。您需要捕获它并检查它。

hinstance = print_file(i, printer_name)
if hinstance > 32:
    ....

但是,像HINSTANCE 这样的print_file 函数泄漏实现细节似乎很糟糕。我认为您最好在使用时直接检查ShellExecute 的返回值。因此,请尝试将> 32 检查移至print_file

请注意,ShellExecute 的错误报告非常弱。如果您想要正确的错误报告,那么您应该改用ShellExecuteEx

您的删除/睡眠循环确实非常脆弱。我不太确定我可以推荐更好的东西,因为我不确定你想要达到什么目标。但是,您的程序的这一部分可能会遇到麻烦。

【讨论】:

  • 感谢 cmets。我在网上看到了一些使用 ShellExecuteEx 的建议,但我在 Python 世界中没有看到类似的建议。我正在使用 pywin32 访问 win32 API,它只有 ShellExecute。因此,您建议将 if hinstance > 32 移动到 print_file() 内?我的目的是在移动到delete_file() 之前验证文件打印成功。我拥有time.sleep 的唯一原因是避免在 ShellExecute() 完成之前删除文件。在添加延迟之前,我收到了 notepad.exe 错误。目标:打印文件然后删除它们
猜你喜欢
  • 2017-01-26
  • 1970-01-01
  • 2015-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-28
  • 2014-08-14
  • 2014-11-11
相关资源
最近更新 更多