Доступ к моей библиотеке WPF COM из Python

Я хотел бы запустить свое приложение WPF из скрипта Python, однако у меня возникли трудности. Для этого я преобразовал приложение 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 и запустить мое приложение WPF из консольного приложения win32.

#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;
}

Когда я пытаюсь получить доступ к компоненту COM из Python

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 Viewer. Я много раз делал подобные вещи для приложений на C++ без каких-либо проблем. Однако это было либо с проектом ATL, либо с приложением MFC с включенной автоматизацией. В этом случае я преобразовал приложение WPF в dll и вручную преобразовал в COM. Может кто-нибудь посоветовать, что еще мне нужно сделать, чтобы запустить приложение из python?

Заранее спасибо.

Дальнейшее редактирование: я могу загрузить typelib в python, но все еще не могу получить доступ к 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" с идентификатором класса {D936A84B-8B1C-4D62-B090-C06E3EB5EEE9}.

Дальнейшее редактирование:

Я попытался установить Python для.Net и выполнил следующую команду

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, сборок и библиотек типов весьма ограничены, поэтому я был бы признателен, если бы кто-нибудь помог мне понять, что мне нужно сделать, чтобы получить доступ к DLL из python.

Когда я смотрю на запись в OLE/COM Object viewer, она указывает на файл tlb, а не на dll, т.е.

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

Таким образом, регистрируется только файл tlb, а не класс. Когда я запускаю класс LoadTypeLib, я загружаю его из пути на моем жестком диске. Мне нужно, чтобы DLL была зарегистрирована, когда я пытаюсь отправить. В противном случае, если бы я мог получить доступ к этому напрямую с фиксированного пути, это также было бы хорошо, но я не знаю, как это сделать.

Еще раз спасибо за вашу помощь.

0 ответов

Другие вопросы по тегам