2

我想从 python 脚本运行我的 WPF 应用程序,但是遇到了困难。为此,我将 WPF 应用程序转换为 COM 库,如下所示:

namespace MyWpfApp
{

[Guid("F75D3377-D677-41BF-B3D5-C677C442228F")]
public interface IMyWpfAppInterface
{
    void ShowCOMDialog();
    void ClickButton1();
    void ClickButton2();
}

[ClassInterface(ClassInterfaceType.None)]
[Guid("D936A84B-8B1C-4D62-B090-C06E3EB5EEE9")]
public class MyWpfClass : IMyWpfAppInterface
{
    private static Thread m_runDlgThread;
    private static MainWindow m_mainWindow = null;
    private static Application m_app = null;

    public MyWpfClass() { }

    public void ShowCOMDialog()
    {
        m_msgHelper = new MessageHelper();
        m_runDlgThread = new Thread(runDlg);
        m_runDlgThread.SetApartmentState(ApartmentState.STA);
        m_runDlgThread.Start();
    }

    public void ClickButton1(){// to do}
    public void ClickButton2(){// to do}

    private void runDlg()
    {
        Application m_app = new Application();
        m_mainWindow = new MainWindow();
        m_app.Run(m_mainWindow);
    }
}
}

我已将我的程序集安装到全局程序集缓存并注册 dll,如下所示

gacutil.exe" /i MyWpfApp.dll 
REGASM MyWpfApp.dll /tlb:com.MyWpfApp.tlb

我已经测试过我可以成功导入 Typelib 并从 win32 控制台应用程序运行我的 WPF 应用程序。

#include "stdafx.h"
#import "..\MyWpfApp\bin\Debug\com.MyWpfApp.tlb" named_guids raw_interfaces_only

int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL);   //Initialize all COM Components

// <namespace>::<InterfaceName>
MyWpfApp::IMyWpfAppInterfacePtr pDotNetCOMPtr;

// CreateInstance parameters
// e.g. CreateInstance (<namespace::CLSID_<ClassName>)
HRESULT hRes = 
    pDotNetCOMPtr.CreateInstance(MyWpfApp::CLSID_MyWpfClass);
if (hRes == S_OK)
{
    const DWORD cTimeout_ms = 500;
    HANDLE hEvent = CreateEvent(0, TRUE, FALSE, 0);
    BSTR str;
    pDotNetCOMPtr->ShowCOMDialog ();
    bool toggle = true;
    while(true)
    {
        DWORD dwWait = WaitForSingleObject(hEvent,cTimeout_ms);
        if(toggle)
        {
            pDotNetCOMPtr->ClickButton1();
            toggle = false;
        }
        else
        {
            pDotNetCOMPtr->ClickButton2();
            toggle = true;
        }

    }
    //call .NET COM exported function ShowDialog ()
}

CoUninitialize ();   //DeInitialize all COM Components
return 0;
}

当我尝试从 Python 访问 COM 组件时

import win32com.client
from win32com.client import constants as c
myWpf = win32com.client.Dispatch("MyWpfApp.MyWpfClass")

这失败了,报告

File "C:\Python27\lib\site-packages\win32com\client\dynamic.py", line 114, in _GetGoodDispatchAndUserName
return (_GetGoodDispatch(IDispatch, clsctx), userName)
File "C:\Python27\lib\site-packages\win32com\client\dynamic.py", line 91, in _GetGoodDispatch
IDispatch = pythoncom.CoCreateInstance(IDispatch, None, clsctx, pythoncom.IID_IDispatch)
com_error: (-2147221164, 'Class not registered', None, None)

我可以在注册表中看到类“MyWpfApp.MyWpfClass”,也可以从 OLE 查看器中看到。我已经为基于 C++ 的应用程序做过很多次这种事情,没有任何问题。然而,这适用于 ATL 项目或 MFC 应用程序,并启用了自动化。在这种情况下,我已将 WPF 应用程序转换为 dll 并手动转换为 COM。有人可以建议我还需要做什么才能从 python 运行应用程序吗?

提前致谢。

进一步编辑:我可以在 python 中加载 typelib,但仍然无法访问我运行的 com 类

import win32com.client
import pythoncom


myApp = pythoncom.LoadTypeLib("D:\\MyWorkSpace\\testProgs\\ATL_COM\\WPF\MyWpfApp\\MyWpfApp\\bin\\Debug\\com.MyWpfApp.tlb")
downloads_stat = None

for index in xrange(0, myApp.GetTypeInfoCount()):
    type_name = myApp.GetDocumentation(index)[0]
    type_iid = myApp.GetTypeInfo(index).GetTypeAttr().iid
    print type_iid
    print type_name
    if type_name == 'MyWpfClass':
        downloads_stat = win32com.client.Dispatch(type_iid)

这确认类已加载,但我无法访问它们,因为它们被报告为未注册。

>>> 
{B5E3A6C6-09A0-315C-BF3A-CB943389F610}
MessageHelper
{FBE23BB0-3EDC-3A65-90EB-DF84F7545D70}
COPYDATASTRUCT
{8BEE824F-F708-3052-BC21-A9EC4E1BB002}
MainWindow
{8C0044EF-91A9-3CB3-9945-1ACA076F3D7E}
NextPrimeDelegate
{F75D3377-D677-41BF-B3D5-C677C442228F}
IMyWpfAppInterface
{D936A84B-8B1C-4D62-B090-C06E3EB5EEE9}
MyWpfClass

Traceback (most recent call last):
  File "D:\MyWorkSpace\testProgs\ATL_COM\WPF\MyWpfApp\MyWin32App\Python\MyPythonClient.py", line 15, in <module>
    downloads_stat = win32com.client.Dispatch(type_iid)
  File "C:\Python27\lib\site-packages\win32com\client\__init__.py", line 95, in Dispatch
    dispatch, userName = dynamic._GetGoodDispatchAndUserName(dispatch,userName,clsctx)
  File "C:\Python27\lib\site-packages\win32com\client\dynamic.py", line 114, in _GetGoodDispatchAndUserName
    return (_GetGoodDispatch(IDispatch, clsctx), userName)
  File "C:\Python27\lib\site-packages\win32com\client\dynamic.py", line 91, in _GetGoodDispatch
    IDispatch = pythoncom.CoCreateInstance(IDispatch, None, clsctx, pythoncom.IID_IDispatch)
com_error: (-2147221164, 'Class not registered', None, None)
>>> 

我还可以确认注册表中有一个条目“MyWpfApp.MyWpfClass”,其类 ID 为 {D936A84B-8B1C-4D62-B090-C06E3EB5EEE9}。

进一步编辑:

我尝试为 .Net 安装 Python 并运行以下命令

import clr;
import sys
sys.path.append('D:\\MyWorkSpace\\testProgs\\ATL_COM\\WPF\\MyWpfApp\\MyWpfApp\\bin\\Debug')
clr.AddReference("MyWpfApp.dll")

但是,这产生了以下错误

FileNotFoundException: Unable to find assembly 'MyWpfApp.dll'.
   at Python.Runtime.CLRModule.AddReference(String name) in C:\Users\Barton\Documents\Visual Studio 2008\Projects\PySharp\trunk\pythonnet\src\runtime\moduleobject.cs:line 375

我对 COM、程序集和类型库的了解非常有限,因此如果有人能帮助我了解从 python 访问 DLL 需要做什么,我将不胜感激。

当我查看 OLE/COM 对象查看器中的条目时,它指向 tlb 文件,而不是 dll,即

Win32=D:\MyWorkSpace\testProgs\ATL_COM\WPF\MyWpfApp\MyWpfApp\bin\Debug\com.MyWpfApp.tlb

因此,注册的只是 tlb 文件,而不是类。当我运行 LoadTypeLib 类时,我从硬盘驱动器上的路径加载它。当我尝试调度时,我需要注册 dll。否则,如果我可以直接从固定路径访问它,这也很好,但我不知道该怎么做。

再次感谢您的帮助。

4

0 回答 0