Dave sent me the source via email.

The root problem is that the MFC project is not supporting the GetTypeInfo() and associated calls, and TBH I'm not sure how hard it would be to make it support that. The end result is that the makepy support for the object isn't being used as pywin32 can't associate the object with the typelib, and thus isn't specifying that additional second param. This is also the reason you can't automagically generate the typelib using, eg, win32com.client.gencache.EnsureDispatch() - you are forced to run makepy manually and specify the exact typelib.

There is actually a deficiency in pywin32 here too - it *does* know that MyApp.Application has a generated class, but it never tries that route - instead it creates the object and tries to use the typeinfo stuff to make the association. I think a bug on sourceforge for this would be good.

So after running makepy, a work-around is:

>>> klass=win32com.client.gencache.GetClassForProgID("MyApp.Application")
>>> x = klass()
>>> x.GetSettingValue("foo")
u'foo=testValue123'
>>>

If you can work out how to get the MFC app to respond to the GetTypeInfo() and associated calls, it would all "just work". ie:

>>> x=win32com.client.Dispatch("MyApp.Application")._oleobj_
>>> x
<PyIDispatch at 0x00000000023590B0 with obj at 0x00000000003C0298>
>>> x.GetTypeInfo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
pywintypes.com_error: (-2147352565, 'Invalid index.', None, None)
>>>

should work - eg, a similar example using a WMI object:

>>> x = win32com.client.Dispatch("WbemScripting.SWbemLocator")._oleobj_
>>> x
<PyIDispatch at 0x0000000002359110 with obj at 0x0000000002C513D0>
>>> x.GetTypeInfo()
<PyITypeInfo at 0x00000000023590B0 with obj at 0x00000000003EB8B8>
>>>

So it kinda sucks :(

Mark





On 18/12/2012 10:46 AM, Dave Calkins wrote:
On 12/16/2012 6:17 PM, Mark Hammond wrote:

I'm the vendor of the object :)  As I mentioned, I just created this
small test app which reproduces the issue having just those 3 simple
methods.  However, I'm not able to talk to it via Python.

Is the source to this available?


Yes, its just a Visual C++ app-wizard generated project.  In Visual C++
2010 I used new >> project, selected MFC application, chose a dialog app
with default settings but I checked the "Automation" checkbox so it
would set it up as an OLE Automation server.  Once created, in the Class
view I right-clicked the IMyApp interface and chose Add >> Method.  I
did this for each method shown earlier.  When you add a method this way,
it adds it to the IDL and then adds implementation methods in the
DlgProxy class it creates as part of the project.  Then you just fill in
the implementation methods that it created for you.

Here is the IDL.

=====
     [ uuid(E85C16AC-7936-4792-8E2A-40537D9FA02B) ]
     dispinterface IMyApp
     {
         properties:

         methods:
             [id(1)] void ShowMessage(BSTR msg);
             [id(2)] void SetSettingValue(BSTR settingName, BSTR
settingValue);
             [id(3)] void GetSettingValue(BSTR settingName, BSTR*
settingValue);
     };
=====

Here's the implementation methods it created for the above.  For the
first two I'm just showing a message box with the passed in args. For
the third, with the out param, I'm sending back a dummy value to the
caller.

=====
void CMyAppDlgAutoProxy::ShowMessage(LPCTSTR msg)
{
     AFX_MANAGE_STATE(AfxGetAppModuleState());

     // TODO: Add your dispatch handler code here
     CString s;
     s.Format(_T("ShowMessage\n\"%s\""), msg);
     AfxMessageBox(s);
}


void CMyAppDlgAutoProxy::SetSettingValue(LPCTSTR settingName, LPCTSTR
settingValue)
{
     AFX_MANAGE_STATE(AfxGetAppModuleState());

     // TODO: Add your dispatch handler code here
     CString s;
     s.Format(_T("SetSettingValue\nsettingName = \"%s\"\nsettingValue =
\"%s\""), settingName, settingValue);
     AfxMessageBox(s);
}


void CMyAppDlgAutoProxy::GetSettingValue(LPCTSTR settingName, BSTR*
settingValue)
{
     AFX_MANAGE_STATE(AfxGetAppModuleState());

     // TODO: Add your dispatch handler code here
     CString s;
     s.Format(_T("%s=testValue123"), settingName);
     *settingValue = s.AllocSysString();
}
=====

The first two methods work great, I can call those from python without
any problems.


Nope - it should all be good.  For example, check out:

http://pywin32.hg.sourceforge.net/hgweb/pywin32/pywin32/file/8b73631eeee0/com/TestSources/PyCOMTest/PyCOMTest.idl#l193


http://pywin32.hg.sourceforge.net/hgweb/pywin32/pywin32/file/8b73631eeee0/com/TestSources/PyCOMTest/PyCOMImpl.cpp#l133


and (slightly cryptic) Python code which calls it:

http://pywin32.hg.sourceforge.net/hgweb/pywin32/pywin32/file/8b73631eeee0/com/win32com/test/testPyComTest.py#l225


Which shows some "out" param tests (and while there is an inout bstr
test, there doesn't seem to be a specific test for an out bstr, so
it's still possible you have hit a pywin32 bug)

Thanks for the links.  I'll take a look at them as soon as I can.

You indicated that the out params should be converted to a return
value.  Why does the MakePy generated method signature not indicate
this?  i.e. why does it show 2 arguments?

The makepy signature really just reflects the params passed to the
interface itself - hence those params all have default values.

You said above that pywin32 *will* be passing a second param - a byref
bstr.  That suggests to me that there's some other method I need to call
which internally calls the real method from pywin32. Where is the method
I need to call then?  I don't see any method generated there with only a
single arg?

InvokeTypes is what does all the magic - it takes the VT_* values and
builds real params in C++, and also builds the tuple (if necessary)
which is returned.  The params mainly exist for when the interface is
*implemented* by Python rather than when called by Python - the same
generated classes are used in both directions.


Got it, so I shouldn't expect the actual calling convention to be bound
to whats in the MakePy code.

Hope this clarifies...

Yes, thanks for the continued help on this.  I'd love to see this work
from Python and then be able to provide that as another way to automate
this app.


_______________________________________________
python-win32 mailing list
python-win32@python.org
http://mail.python.org/mailman/listinfo/python-win32

Reply via email to