From schapman1974 at gmail.com Tue Feb 7 11:09:18 2017 From: schapman1974 at gmail.com (Stephen Chapman) Date: Tue, 7 Feb 2017 11:09:18 -0500 Subject: [python-win32] Python win32Com Server DLL Message-ID: Hello, I am having a speed issue while running dll functions. I have a minimal com server example and a minimal com client example below. I have added cProfile to the example. All source files and the profile are attached. So when I run this example I get between 1.4 seconds to 1.7 seconds. I am running a loop of 10,000 doing 2 methods in the loop. So the here are a couple lines from the profile. ncalls tottime percall cumtime percall filename:lineno(function) 1 0.050 0.050 1.740 1.740 cpminimaltest.py:6(testcalltime) 20001 0.103 0.000 1.689 0.000 dynamic.py:41(__call__) 20004 0.698 0.000 1.247 0.000 automation.py:702(Invoke) 80001 0.276 0.000 0.313 0.000 automation.py:197(_set_value) It seems like the Invoke is taking an inordinate amount of time. When I create a minimal example in C# and run the same test. I get .009 seconds. Is there something I am not doing right. Would having a tlb file attached help?... from win32com.server import register import sys import pstats import cProfile class dataObject(object): _public_methods_ = ["method1","method2","startProfile","printStats"] _public_attrs_ = [] _reg_progid_ = "testcall.dataobject" _reg_desc_ = "simple test project" _reg_clsid_ = "{97dbc38f-44ce-11e2-a5e5-001018107395}" def __init__(self): self.profile = cProfile.Profile() def method1(self,*args): return 0 def method2(self,*args): return 0 def startProfile(self): self.profile.enable() def printStats(self,filename=""): self.profile.disable() f = open(filename, 'w') sortby = 'cumulative' try: pstats.Stats(self.profile, stream=f).strip_dirs().sort_stats(sortby).print_stats() except: f.write("Nothing was profiled\n") f.close() if __name__=='__main__': if len(sys.argv)>1: register.UnregisterServer(dataObject) else: register.UseCommandLine(dataObject) from comtypes.client import CreateObject import time do = CreateObject("testcall.dataobject") def testcalltime(): c4 = 0 a=time.time() for d in range (0,10000): d=do.method1(c4,1) e=do.method2(c4,1) b=time.time() print b-a do.startProfile() testcalltime() do.printStats("c:\profile.txt") -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- 742147 function calls (742109 primitive calls) in 1.810 seconds Ordered by: cumulative time ncalls tottime percall cumtime percall filename:lineno(function) 1 0.050 0.050 1.740 1.740 cpminimaltest.py:6(testcalltime) 20001 0.103 0.000 1.689 0.000 dynamic.py:41(__call__) 20004 0.698 0.000 1.247 0.000 automation.py:702(Invoke) 80001 0.276 0.000 0.313 0.000 automation.py:197(_set_value) 20004 0.156 0.000 0.285 0.000 automation.py:632(__del__) 20004 0.043 0.000 0.147 0.000 policy.py:266(_Invoke_) 20004 0.029 0.000 0.104 0.000 policy.py:279(_invoke_) 100005 0.096 0.000 0.096 0.000 automation.py:169(__del__) 20004 0.057 0.000 0.075 0.000 policy.py:568(_invokeex_) 20004 0.046 0.000 0.072 0.000 automation.py:525(from_param) 1 0.001 0.001 0.069 0.069 __init__.py:9() 140059 0.057 0.000 0.057 0.000 {isinstance} 1 0.010 0.010 0.054 0.054 gencache.py:22() 1 0.000 0.000 0.043 0.043 gencache.py:53(__init__) 20001 0.043 0.000 0.043 0.000 automation.py:338(_get_value) 1 0.000 0.000 0.043 0.043 gencache.py:73(_LoadDicts) 2 0.043 0.021 0.043 0.021 {built-in method load} 20011 0.020 0.000 0.020 0.000 {range} 80016 0.019 0.000 0.019 0.000 {_ctypes.byref} 1 0.001 0.001 0.014 0.014 dynamic.py:17() 1 0.009 0.009 0.013 0.013 build.py:11() 20001 0.011 0.000 0.011 0.000 {getattr} 40011 0.009 0.000 0.009 0.000 {method 'pop' of 'dict' objects} 40735/40732 0.008 0.000 0.008 0.000 {len} 20004 0.006 0.000 0.006 0.000 {_ctypes.POINTER} 20004 0.006 0.000 0.006 0.000 automation.py:165(__init__) 1 0.000 0.000 0.004 0.004 string.py:20() 2 0.000 0.000 0.003 0.002 re.py:188(compile) 2 0.000 0.000 0.003 0.002 re.py:226(_compile) 2 0.000 0.000 0.003 0.002 sre_compile.py:493(compile) 1 0.000 0.000 0.003 0.003 string.py:112(__init__) 10000 0.003 0.000 0.003 0.000 cpminimal.py:16(method1) 10000 0.003 0.000 0.003 0.000 cpminimal.py:19(method2) 2 0.000 0.000 0.002 0.001 sre_parse.py:677(parse) 7/2 0.000 0.000 0.002 0.001 sre_parse.py:301(_parse_sub) 10/2 0.001 0.000 0.002 0.001 sre_parse.py:379(_parse) 3 0.000 0.000 0.001 0.000 dynamic.py:103(__getattr__) 2 0.000 0.000 0.001 0.001 sre_compile.py:478(_code) 288 0.000 0.000 0.001 0.000 sre_parse.py:201(get) 13/2 0.000 0.000 0.001 0.000 sre_compile.py:32(_compile) 6 0.000 0.000 0.001 0.000 sre_compile.py:178(_compile_charset) 6 0.000 0.000 0.001 0.000 sre_compile.py:207(_optimize_charset) 318 0.001 0.000 0.001 0.000 sre_parse.py:182(__next) 1 0.000 0.000 0.000 0.000 glob.py:1() 4 0.000 0.000 0.000 0.000 sre_compile.py:258(_mk_bitmap) 2 0.000 0.000 0.000 0.000 sre_compile.py:359(_compile_info) 1 0.000 0.000 0.000 0.000 {map} 3 0.000 0.000 0.000 0.000 automation.py:672(GetIDsOfNames) 3 0.000 0.000 0.000 0.000 exception.py:32(__init__) 15/4 0.000 0.000 0.000 0.000 sre_parse.py:140(getwidth) 57 0.000 0.000 0.000 0.000 sre_parse.py:195(match) 36 0.000 0.000 0.000 0.000 sre_parse.py:130(__getitem__) 192 0.000 0.000 0.000 0.000 {method 'append' of 'list' objects} 3 0.000 0.000 0.000 0.000 {pythoncom.GetScodeString} 1 0.000 0.000 0.000 0.000 {open} 4 0.000 0.000 0.000 0.000 sre_parse.py:216(isname) 3 0.000 0.000 0.000 0.000 policy.py:285(_GetIDsOfNames_) 15 0.000 0.000 0.000 0.000 sre_parse.py:138(append) 3 0.000 0.000 0.000 0.000 policy.py:294(_getidsofnames_) 22 0.000 0.000 0.000 0.000 sre_compile.py:51(fixup) 1 0.000 0.000 0.000 0.000 {method 'close' of 'file' objects} 1 0.000 0.000 0.000 0.000 ntpath.py:62(join) 2 0.000 0.000 0.000 0.000 sre_parse.py:178(__init__) 3 0.000 0.000 0.000 0.000 policy.py:305(_getdispid_) 3 0.000 0.000 0.000 0.000 :12(__init__) 1 0.000 0.000 0.000 0.000 re.py:204(escape) 1 0.000 0.000 0.000 0.000 dynamic.py:171(CDispatch) 4 0.000 0.000 0.000 0.000 sre_parse.py:72(opengroup) 2 0.000 0.000 0.000 0.000 ntpath.py:95(splitdrive) 13 0.000 0.000 0.000 0.000 sre_parse.py:90(__init__) 30 0.000 0.000 0.000 0.000 {min} 2 0.000 0.000 0.000 0.000 sre_parse.py:257(_escape) 13 0.000 0.000 0.000 0.000 {method 'get' of 'dict' objects} 4 0.000 0.000 0.000 0.000 sre_parse.py:83(closegroup) 2 0.000 0.000 0.000 0.000 sre_compile.py:354(_simple) 2 0.000 0.000 0.000 0.000 {_sre.compile} 25 0.000 0.000 0.000 0.000 sre_parse.py:210(isident) 4 0.000 0.000 0.000 0.000 sre_compile.py:472(isstring) 26 0.000 0.000 0.000 0.000 {_sre.getlower} 1 0.000 0.000 0.000 0.000 {cPickle.Unpickler} 11 0.000 0.000 0.000 0.000 sre_parse.py:126(__len__) 1 0.000 0.000 0.000 0.000 __init__.py:523(VARIANT) 2 0.000 0.000 0.000 0.000 {method 'join' of 'str' objects} 1 0.000 0.000 0.000 0.000 build.py:102(DispatchItem) 3 0.000 0.000 0.000 0.000 {method 'startswith' of 'str' objects} 2 0.000 0.000 0.000 0.000 {time.time} 23 0.000 0.000 0.000 0.000 {ord} 4 0.000 0.000 0.000 0.000 {method 'remove' of 'list' objects} 1 0.000 0.000 0.000 0.000 cpminimal.py:25(printStats) 1 0.000 0.000 0.000 0.000 string.py:543(Formatter) 3 0.000 0.000 0.000 0.000 {method 'lower' of 'unicode' objects} 2 0.000 0.000 0.000 0.000 sre_parse.py:67(__init__) 4 0.000 0.000 0.000 0.000 {method 'extend' of 'list' objects} 1 0.000 0.000 0.000 0.000 __init__.py:420(DispatchBaseClass) 1 0.000 0.000 0.000 0.000 string.py:102(_TemplateMetaclass) 1 0.000 0.000 0.000 0.000 {hasattr} 1 0.000 0.000 0.000 0.000 string.py:124(Template) 3 0.000 0.000 0.000 0.000 dynamic.py:37(__init__) 2 0.000 0.000 0.000 0.000 {method 'replace' of 'str' objects} 1 0.000 0.000 0.000 0.000 string.py:85(_multimap) 1 0.000 0.000 0.000 0.000 build.py:56(MapEntry) 1 0.000 0.000 0.000 0.000 CLSIDToClass.py:18() 1 0.000 0.000 0.000 0.000 __init__.py:164(__init__) 2 0.000 0.000 0.000 0.000 sre_parse.py:134(__setitem__) 4 0.000 0.000 0.000 0.000 {max} 1 0.000 0.000 0.000 0.000 __init__.py:496(CoClassBaseClass) 1 0.000 0.000 0.000 0.000 __init__.py:116(CDispatch) 1 0.000 0.000 0.000 0.000 build.py:87(OleItem) 1 0.000 0.000 0.000 0.000 __init__.py:161(Constants) 6 0.000 0.000 0.000 0.000 sre_compile.py:24(_identityfunction) 1 0.000 0.000 0.000 0.000 __init__.py:190(EventsProxy) 1 0.000 0.000 0.000 0.000 sre_parse.py:207(seek) 2 0.000 0.000 0.000 0.000 {method 'items' of 'dict' objects} 1 0.000 0.000 0.000 0.000 build.py:391(VTableItem) 1 0.000 0.000 0.000 0.000 build.py:37(NotSupportedException) 1 0.000 0.000 0.000 0.000 build.py:408(LazyDispatchItem) 1 0.000 0.000 0.000 0.000 {method 'clear' of 'dict' objects} 1 0.000 0.000 0.000 0.000 sre_parse.py:205(tell) 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} -------------- next part -------------- A non-text attachment was scrubbed... Name: cpminimaltest.py Type: application/octet-stream Size: 344 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: cpminimal.py Type: application/octet-stream Size: 1124 bytes Desc: not available URL: From pywin32 at derketo.com Mon Feb 13 06:31:03 2017 From: pywin32 at derketo.com (pywin32 at derketo.com) Date: Mon, 13 Feb 2017 11:31:03 +0000 Subject: [python-win32] AMD64 build 220 for python 3.6 - installer looking for registry entry 3.6-32 which is probably incorrect for the x64 installer Message-ID: On Win 7 Enterprise 64-bit, with 64-bit python 3.6 I downloaded and ran as administrator the following AMD64 build of 220 for python 3.6: pywin32-220.win-amd64-py3.6.exe The installer gets stuck after looking for registry entry "3.6-32", which is probably incorrect for the x64 installer Also, when it does not find the (wrong) entry in the registry (correct "3.6" one is there under both HKLM and HKCU) the text box where the path appears on the installer is not manually editable so you cannot override the (failed) lookup with the correct directory. 64-bit Python 3.6 is installed in C:\Python36, version: Python 3.6.0 (v3.6.0:41df79263a11, Dec 23 2016, 08:06:12) [MSC v.1900 64 bit (AMD64)] Setting the registry entry incorrecty to 3.6-32 instead of 3.6 allowed the installer to run and report success, but I can't import win32con or win32api in python, so I assume that the version mismatch was fatal in some way. I was expecting that to result in: a) a fatal crash if the architecture is incorrect, or b) complete success if it is just the installer which is looking for 32 bit instead of 64 bit registry entries and the version within the installer is built for x64 as advertised I don't seem to have either of those. I am returning to python after a bit of a gap and was trying to get up to speed and to grips with django etc. under 3.6 with a SQLServer backend and that appears to want pywin32 (which I have also used in the past) so I am now slightly stuck. Any suggestions appreciated. Thanks Rick From waldemar.osuch at gmail.com Mon Feb 13 10:19:38 2017 From: waldemar.osuch at gmail.com (Waldemar Osuch) Date: Mon, 13 Feb 2017 15:19:38 +0000 Subject: [python-win32] AMD64 build 220 for python 3.6 - installer looking for registry entry 3.6-32 which is probably incorrect for the x64 installer In-Reply-To: References: Message-ID: Not a solution per say but a workaround if you are interested is: 1) Download the pywin32 in the wheel format from Christoph Gohlke's, "thanks god it exists" site http://www.lfd.uci.edu/~gohlke/pythonlibs/#pywin32 2) Get the one appropriate for your Python version ( pywin32?220.1?cp36?cp36m?win_amd64.whl) 3) use "pip install .whl to install it. 4) Run `python.exe Scripts\pywin32_postinstall.py -install` from an elevated command prompt. As the site mentions. The key is "elevated command prompt". w/o -------------- next part -------------- An HTML attachment was scrubbed... URL: From pywin32 at derketo.com Mon Feb 13 10:35:56 2017 From: pywin32 at derketo.com (pywin32 at derketo.com) Date: Mon, 13 Feb 2017 15:35:56 +0000 Subject: [python-win32] AMD64 build 220 for python 3.6 - installer looking for registry entry 3.6-32 which is probably incorrect for the x64 installer In-Reply-To: References: Message-ID: Vielen dank Waldemar. I echo your sentiments about Christoph's wonderful site - it has been a life saver for me on several occasions, and I had not thought to look there yet. I have also poked around a bit between conf calls this morning and have just discovered that I had a pythonpath problem in terms of loading it at all, so I can now load it and the sqlsever module I am using seems happy with it - no weird crashes as yet from architectural incompatibilities. It is slightly premature in terms of testing but at first blush I think that the problem may therefore be that the sourceforge x64 installer has x64 code in it but is just looking for the wrong registry entry. Lack of ability to put the path in yourself once it has failed to find it in the registry exacerbates the problem. I ran it elevated and even though it reported success it did not put the toolkit onto my pythonnpath so there may also be another loose end there. I will try your suggestion about explicitly running the post install script, Waldemar, but it is also very possible this is normally an exercise for the reader anyway. Thanks again. regards Rick On 13/02/2017 15:19, Waldemar Osuch wrote: > Not a solution per say but a workaround if you are interested is: > 1) Download the pywin32 in the wheel format from Christoph Gohlke's, > "thanks god it exists" site > http://www.lfd.uci.edu/~gohlke/pythonlibs/#pywin32 > > > 2) Get the one appropriate for your Python version ( > pywin32?220.1?cp36?cp36m?win_amd64.whl) > > 3) use "pip install .whl to install it. > > 4) Run > `python.exe Scripts\pywin32_postinstall.py -install` from an elevated > command prompt. > As the site mentions. The key is "elevated command prompt". > > w/o From schapman1974 at gmail.com Thu Feb 16 10:02:37 2017 From: schapman1974 at gmail.com (Stephen Chapman) Date: Thu, 16 Feb 2017 10:02:37 -0500 Subject: [python-win32] Python win32Com Server DLL In-Reply-To: References: Message-ID: So after much research on the library . It certainly looks like the invoke method is taking all the time. Is this because of the conversion from Variant??? On Tue, Feb 7, 2017 at 11:09 AM, Stephen Chapman wrote: > Hello, > I am having a speed issue while running dll functions. I have a > minimal com server example and a minimal com client example below. I have > added cProfile to the example. All source files and the profile are > attached. > > So when I run this example I get between 1.4 seconds to 1.7 seconds. I > am running a loop of 10,000 doing 2 methods in the loop. So the here are a > couple lines from the profile. > > ncalls tottime percall cumtime percall filename:lineno(function) > 1 0.050 0.050 1.740 1.740 cpminimaltest.py:6( > testcalltime) > 20001 0.103 0.000 1.689 0.000 dynamic.py:41(__call__) > 20004 0.698 0.000 1.247 0.000 automation.py:702(Invoke) > 80001 0.276 0.000 0.313 0.000 automation.py:197(_set_value) > > It seems like the Invoke is taking an inordinate amount of time. When I > create a minimal example in C# and run the same test. I get .009 > seconds. Is there something I am not doing right. Would having a tlb > file attached help?... > > > > from win32com.server import register > import sys > import pstats > import cProfile > > class dataObject(object): > _public_methods_ = ["method1","method2","startProfile","printStats"] > _public_attrs_ = [] > _reg_progid_ = "testcall.dataobject" > _reg_desc_ = "simple test project" > _reg_clsid_ = "{97dbc38f-44ce-11e2-a5e5-001018107395}" > > def __init__(self): > self.profile = cProfile.Profile() > > def method1(self,*args): > return 0 > > def method2(self,*args): > return 0 > > def startProfile(self): > self.profile.enable() > > def printStats(self,filename=""): > self.profile.disable() > f = open(filename, 'w') > sortby = 'cumulative' > try: > pstats.Stats(self.profile, stream=f).strip_dirs().sort_ > stats(sortby).print_stats() > except: > f.write("Nothing was profiled\n") > f.close() > > if __name__=='__main__': > if len(sys.argv)>1: > register.UnregisterServer(dataObject) > else: > register.UseCommandLine(dataObject) > > > > from comtypes.client import CreateObject > import time > > do = CreateObject("testcall.dataobject") > > def testcalltime(): > c4 = 0 > a=time.time() > for d in range (0,10000): > d=do.method1(c4,1) > e=do.method2(c4,1) > b=time.time() > print b-a > > do.startProfile() > testcalltime() > do.printStats("c:\profile.txt") > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From timr at probo.com Thu Feb 16 19:48:56 2017 From: timr at probo.com (Tim Roberts) Date: Thu, 16 Feb 2017 16:48:56 -0800 Subject: [python-win32] Python win32Com Server DLL In-Reply-To: References: Message-ID: Stephen Chapman wrote: > So after much research on the library . It certainly looks like the > invoke method is taking all the time. Is this because of the > conversion from Variant??? > > On Tue, Feb 7, 2017 at 11:09 AM, Stephen Chapman > > wrote: > > Hello, > I am having a speed issue while running dll functions. I have > a minimal com server example and a minimal com client example > below. I have added cProfile to the example. All source files > and the profile are attached. > > So when I run this example I get between 1.4 seconds to 1.7 > seconds. I am running a loop of 10,000 doing 2 methods in the > loop. So the here are a couple lines from the profile. > > ncalls tottime percall cumtime percall > filename:lineno(function) > 1 0.050 0.050 1.740 1.740 > cpminimaltest.py:6(testcalltime) > 20001 0.103 0.000 1.689 0.000 dynamic.py:41(__call__) > 20004 0.698 0.000 1.247 0.000 > automation.py:702(Invoke) > 80001 0.276 0.000 0.313 0.000 > automation.py:197(_set_value) > A late-bound COM call is not an efficient operation, and having it be out-of-process adds even more time. 20,000 calls in 0.7 seconds is 35 microseconds per call, which is pretty ding-danged fast. In my view, you have unrealistic expectations. > > It seems like the Invoke is taking an inordinate amount of time. > When I create a minimal example in C# and run the same test. I > get .009 seconds. Is there something I am not doing right. > Do you mean 0.009 seconds for 20,000 calls? I don't believe that. How are you doing the timing? Are you measuring wall-clock time or CPU time? Since it's out-of-process, time spent in the server isn't going to be counted. Are you sure the calls weren't optimized away? I suppose it is possible that C# did the dynamic COM lookup once and cached the result, but even so, I can't believe 500 nanoseconds per call with a context switch involved. In your minimal example, are BOTH ends in C#? -- Tim Roberts, timr at probo.com Providenza & Boekelheide, Inc. From schapman1974 at gmail.com Thu Feb 16 21:16:17 2017 From: schapman1974 at gmail.com (Stephen Chapman) Date: Thu, 16 Feb 2017 21:16:17 -0500 Subject: [python-win32] Python win32Com Server DLL In-Reply-To: References: Message-ID: Tim, Since it was a simple example I was only passing a single int for a parameter and returning 0. As far as I know COM servers don't cache responses I have never seen that happen anyway. As well I'm running on an i7 3.2ghz machine so my results could be faster than most. However the question was really why in the order of magnitude is python so much slower for the same exact call. I have slightly changed my example to bump the number by one to show that it is not caching. And pass I am passing 4 parameters now so as to show how much longer python takes as you add more arguments. So here are the results. I have just done a simple timer in this example. *Example code:* from comtypes.client import CreateObject import time do = CreateObject("testcall.dataobject1") do2 = CreateObject("testcall.dataobject2") def testcalltime(testname,theObj): first=theObj.method1(1,2,3,4) second=theObj.method2(1,2,3,4) print "Start "+testname,first,second a=time.time() for d in range (0,9999): first=theObj.method1(1,2,3,4) second=theObj.method2(1,2,3,4) print "End ",testname,first,second, b=time.time() print b-a testcalltime("Python Test",do) testcalltime("C# Test ",do2) *Result output is as follows:* Start Python Test 1 1 End Python Test 10000 10000 0.422999858856 Start C# Test 1 1 End C# Test 10000 10000 0.0369999408722 So the function now bumps by one and has 4 parameters passing... So as you can see the Python code took 11 times longer to do this simple process If i add 5 more paramters C# only slightly goes up and Python more than doubles. Also it may help to know that I'm not trying to do this to point out deficiencies in python. My goal is to use python for a replacement DLL I'm building for an application that already exists. The program makes many calls to the DLL which is causing a bottleneck when I use python to recreate the function calls. The original DLL does not seem to suffer from this either. See both COM server examples below *Example C# COM server: ("Register for COM Interop" Checked in build configuration)* using System; using System.Runtime.InteropServices; using testlibrary; namespace testlibrary { [ComVisible(true)] [Guid("DBE0E8C4-1C61-41F3-B6A4-4E2F353D3D06")] [InterfaceType(ComInterfaceType.InterfaceIsDual)] public interface dataobject { int method1(int test, int test2, int test3, int test4); int method2(int test, int test2, int test3, int test4); } } [ComVisible(true)] [Guid("DBE0E8C4-1C61-41F3-B6A4-4E2F353D3D07")] [ProgId("testcall.dataobject2")] [ClassInterface(ClassInterfaceType.None)] public class testcall : dataobject { private int testcount1 = 0; private int testcount2 = 0; public int method1(int test, int test2, int test3, int test4) { testcount1 += 1; return testcount1; } public int method2(int test, int test2, int test3, int test4) { testcount2 += 1; return testcount2; } } *Example Python COM server:* from win32com.server import register import sys class dataObject(object): _public_methods_ = ["method1","method2","startProfile","printStats"] _reg_progid_ = "testcall.dataobject1" _reg_desc_ = "simple test project" _reg_clsid_ = "{97dbc38f-44ce-11e2-a5e5-001018107395}" def __init__(self): self.atest1=0 self.atest2=0 def method1(self,*args): self.atest1+=1 return self.atest1 def method2(self,*args): self.atest2+=1 return self.atest2 if __name__=='__main__': if len(sys.argv)>1: register.UnregisterServer(dataObject) else: register.UseCommandLine(dataObject) On Thu, Feb 16, 2017 at 7:48 PM, Tim Roberts wrote: > Stephen Chapman wrote: > > So after much research on the library . It certainly looks like the > > invoke method is taking all the time. Is this because of the > > conversion from Variant??? > > > > On Tue, Feb 7, 2017 at 11:09 AM, Stephen Chapman > > > wrote: > > > > Hello, > > I am having a speed issue while running dll functions. I have > > a minimal com server example and a minimal com client example > > below. I have added cProfile to the example. All source files > > and the profile are attached. > > > > So when I run this example I get between 1.4 seconds to 1.7 > > seconds. I am running a loop of 10,000 doing 2 methods in the > > loop. So the here are a couple lines from the profile. > > > > ncalls tottime percall cumtime percall > > filename:lineno(function) > > 1 0.050 0.050 1.740 1.740 > > cpminimaltest.py:6(testcalltime) > > 20001 0.103 0.000 1.689 0.000 dynamic.py:41(__call__) > > 20004 0.698 0.000 1.247 0.000 > > automation.py:702(Invoke) > > 80001 0.276 0.000 0.313 0.000 > > automation.py:197(_set_value) > > > > A late-bound COM call is not an efficient operation, and having it be > out-of-process adds even more time. 20,000 calls in 0.7 seconds is 35 > microseconds per call, which is pretty ding-danged fast. In my view, > you have unrealistic expectations. > > > > > > It seems like the Invoke is taking an inordinate amount of time. > > When I create a minimal example in C# and run the same test. I > > get .009 seconds. Is there something I am not doing right. > > > > Do you mean 0.009 seconds for 20,000 calls? I don't believe that. How > are you doing the timing? Are you measuring wall-clock time or CPU > time? Since it's out-of-process, time spent in the server isn't going > to be counted. Are you sure the calls weren't optimized away? I > suppose it is possible that C# did the dynamic COM lookup once and > cached the result, but even so, I can't believe 500 nanoseconds per call > with a context switch involved. > > In your minimal example, are BOTH ends in C#? > > -- > Tim Roberts, timr at probo.com > Providenza & Boekelheide, Inc. > > _______________________________________________ > python-win32 mailing list > python-win32 at python.org > https://mail.python.org/mailman/listinfo/python-win32 > -------------- next part -------------- An HTML attachment was scrubbed... URL: From denis.akhiyarov at gmail.com Thu Feb 16 21:52:59 2017 From: denis.akhiyarov at gmail.com (Denis Akhiyarov) Date: Fri, 17 Feb 2017 02:52:59 +0000 Subject: [python-win32] Python win32Com Server DLL In-Reply-To: References: Message-ID: I would be curious to see your c# code, I support Tim on unrealistic timing. This kind of questions are good for Stackoverflow. On Thu, Feb 16, 2017, 6:50 PM Tim Roberts wrote: > Stephen Chapman wrote: > > So after much research on the library . It certainly looks like the > > invoke method is taking all the time. Is this because of the > > conversion from Variant??? > > > > On Tue, Feb 7, 2017 at 11:09 AM, Stephen Chapman > > > wrote: > > > > Hello, > > I am having a speed issue while running dll functions. I have > > a minimal com server example and a minimal com client example > > below. I have added cProfile to the example. All source files > > and the profile are attached. > > > > So when I run this example I get between 1.4 seconds to 1.7 > > seconds. I am running a loop of 10,000 doing 2 methods in the > > loop. So the here are a couple lines from the profile. > > > > ncalls tottime percall cumtime percall > > filename:lineno(function) > > 1 0.050 0.050 1.740 1.740 > > cpminimaltest.py:6(testcalltime) > > 20001 0.103 0.000 1.689 0.000 dynamic.py:41(__call__) > > 20004 0.698 0.000 1.247 0.000 > > automation.py:702(Invoke) > > 80001 0.276 0.000 0.313 0.000 > > automation.py:197(_set_value) > > > > A late-bound COM call is not an efficient operation, and having it be > out-of-process adds even more time. 20,000 calls in 0.7 seconds is 35 > microseconds per call, which is pretty ding-danged fast. In my view, > you have unrealistic expectations. > > > > > > It seems like the Invoke is taking an inordinate amount of time. > > When I create a minimal example in C# and run the same test. I > > get .009 seconds. Is there something I am not doing right. > > > > Do you mean 0.009 seconds for 20,000 calls? I don't believe that. How > are you doing the timing? Are you measuring wall-clock time or CPU > time? Since it's out-of-process, time spent in the server isn't going > to be counted. Are you sure the calls weren't optimized away? I > suppose it is possible that C# did the dynamic COM lookup once and > cached the result, but even so, I can't believe 500 nanoseconds per call > with a context switch involved. > > In your minimal example, are BOTH ends in C#? > > -- > Tim Roberts, timr at probo.com > Providenza & Boekelheide, Inc. > > _______________________________________________ > python-win32 mailing list > python-win32 at python.org > https://mail.python.org/mailman/listinfo/python-win32 > -------------- next part -------------- An HTML attachment was scrubbed... URL: From puirippo at gmail.com Thu Feb 16 22:50:02 2017 From: puirippo at gmail.com (Filippo Scotti) Date: Thu, 16 Feb 2017 22:50:02 -0500 Subject: [python-win32] 2D array from win32com Message-ID: Hello, I am expecting a 720x480 array (safearray, 1 byte/pixel) from the method below from a camera SDK but win32com is returning a byte buffer of size 720. Extracting the data from the buffer I can get pixel values of only 1 row of pixels and not the entire 2D array. How can I get the 2D array? I've seen posts on relatively similar topics but couldn't solve the problem. Thank you for any help that you can provide. Regards, Filippo Python 2.7.6, pywin32 (220) >>> import win32com.client >>> import struct >>> cam=win32com.client.Dispatch(AA) >>> a=cam.GetRawData() >>> a >>> len(a) 720 >>> a[0] '\x12' >>> struct.unpack('b', a[0]) (18,) -------------- next part -------------- An HTML attachment was scrubbed... URL: From timr at probo.com Fri Feb 17 16:53:11 2017 From: timr at probo.com (Tim Roberts) Date: Fri, 17 Feb 2017 13:53:11 -0800 Subject: [python-win32] Python win32Com Server DLL In-Reply-To: References: Message-ID: Stephen Chapman wrote: > > Since it was a simple example I was only passing a single int for a > parameter and returning 0. As far as I know COM servers don't cache > responses I have never seen that happen anyway. That's not what I said. There are two parts to a late-dispatch COM call: finding the address of the routine to call, and calling the routine. Finding the address is a relatively expensive operation, because you don't just have a pile of function pointers. You have to go enumerate the list of methods and properties until you find the one you want by comparing the names as strings, then go ask what the function's signature is, then fake up a function call with that signature. It's possible that C# caches that information so it can just make the call. However, I was assuming that both the client and server were in C#. Now I see that it's only the server that's in C#, so my comment does not apply. > However the question was really why in the order of magnitude is > python so much slower for the same exact call. I have slightly > changed my example to bump the number by one to show that it is not > caching. And pass I am passing 4 parameters now so as to show how > much longer python takes as you add more arguments. So here are the > results. I have just done a simple timer in this example. > ... > So the function now bumps by one and has 4 parameters passing... So > as you can see the Python code took 11 times longer to do this simple > process > If i add 5 more paramters C# only slightly goes up and Python more > than doubles. Really, that's just the way it is. Interpreted Python code is always going to be slower than the just-in-time compiled machine code from C#. COM interfaces are optimized for C++, so the Python interface is always going to have something of an impedance mismatch. 20 microseconds per call is pretty fantastic, in my view, but if your application is one where performance over millions of calls is absolutely critical, then you should not move to Python. -- Tim Roberts, timr at probo.com Providenza & Boekelheide, Inc. From timr at probo.com Fri Feb 17 16:55:39 2017 From: timr at probo.com (Tim Roberts) Date: Fri, 17 Feb 2017 13:55:39 -0800 Subject: [python-win32] 2D array from win32com In-Reply-To: References: Message-ID: <61f63573-555b-6d3f-d7b6-b6a8c4f7dea6@probo.com> Filippo Scotti wrote: > > I am expecting a 720x480 array (safearray, 1 byte/pixel) from the > method below from a camera SDK but win32com is returning a byte buffer > of size 720. Extracting the data from the buffer I can get pixel > values of only 1 row of pixels and not the entire 2D array. How can I > get the 2D array? Which camera SDK is this? Do you know exactly what this API is returning? Is it a SAFEARRAY of SAFEARRAYs, or have they cheated by returning something else? Two dimensional arrays are not trivial in COM. I write USB camera drivers, and the APIs I've done return the frames as one large vector. -- Tim Roberts, timr at probo.com Providenza & Boekelheide, Inc. From schapman1974 at gmail.com Fri Feb 17 17:23:11 2017 From: schapman1974 at gmail.com (Stephen Chapman) Date: Fri, 17 Feb 2017 17:23:11 -0500 Subject: [python-win32] Python win32Com Server DLL In-Reply-To: References: Message-ID: I thought that might be the answer. Thank you On Feb 17, 2017 4:53 PM, "Tim Roberts" wrote: > Stephen Chapman wrote: > > > > Since it was a simple example I was only passing a single int for a > > parameter and returning 0. As far as I know COM servers don't cache > > responses I have never seen that happen anyway. > > That's not what I said. There are two parts to a late-dispatch COM > call: finding the address of the routine to call, and calling the > routine. Finding the address is a relatively expensive operation, > because you don't just have a pile of function pointers. You have to go > enumerate the list of methods and properties until you find the one you > want by comparing the names as strings, then go ask what the function's > signature is, then fake up a function call with that signature. It's > possible that C# caches that information so it can just make the call. > > However, I was assuming that both the client and server were in C#. Now > I see that it's only the server that's in C#, so my comment does not apply. > > > > However the question was really why in the order of magnitude is > > python so much slower for the same exact call. I have slightly > > changed my example to bump the number by one to show that it is not > > caching. And pass I am passing 4 parameters now so as to show how > > much longer python takes as you add more arguments. So here are the > > results. I have just done a simple timer in this example. > > ... > > So the function now bumps by one and has 4 parameters passing... So > > as you can see the Python code took 11 times longer to do this simple > > process > > If i add 5 more paramters C# only slightly goes up and Python more > > than doubles. > > Really, that's just the way it is. Interpreted Python code is always > going to be slower than the just-in-time compiled machine code from C#. > COM interfaces are optimized for C++, so the Python interface is always > going to have something of an impedance mismatch. 20 microseconds per > call is pretty fantastic, in my view, but if your application is one > where performance over millions of calls is absolutely critical, then > you should not move to Python. > > -- > Tim Roberts, timr at probo.com > Providenza & Boekelheide, Inc. > > _______________________________________________ > python-win32 mailing list > python-win32 at python.org > https://mail.python.org/mailman/listinfo/python-win32 > -------------- next part -------------- An HTML attachment was scrubbed... URL: From peter.enenkel+python at gmail.com Fri Feb 17 17:29:11 2017 From: peter.enenkel+python at gmail.com (Peter Enenkel) Date: Fri, 17 Feb 2017 23:29:11 +0100 Subject: [python-win32] passing array by reference (3) Message-ID: Hello All, I'm trying to read some data from CATIA v5 (which is an older CAD application) via its COM server. Overall it works rather well, even if I'm fairly new to COM communication. Nevertheless I have run into a problem: One specific function *GetComponents * is supposed to return its results via an array passed by reference. As far as I can tell it is exactly the same problem as in (1) https://mail.python.org/pipermail/python-win32/2002-November/000562.html and (2) https://mail.python.org/pipermail/python-win32/2014-July/013234.html unfortunately there doesn't appear to be a solution as of yet. The python call looks something like this a = list(range(0,12)) b = catapp.ActiveProduct.Position.GetComponents(a) print(a) # outputs (0,1,2,3,4,5,6,7,8,9,10,11) instead of the actual values The equivalent VBScript code is Dim a(11) As Float CATIA.ActiveProduct.Position.GetComponents(a) MsgBox a(0) & ", " & a(1) & ... The VBScript works as intended, the python one just passes the array back out unmodified. As both other threads state: The Position object above has two methods *GetComponents *and *SetComponents *that each take a *CATSafeArrayVariant *as an argument. This *CATSafeArrayVariant *should in this case be a one-dimensional array of real values. CATSafeArrayVariant is a typedef for a *CATVariant *which itself is *typedef any CATVariant*. Any help would be appreciated. As stated above I haven't done much with COM, but otherwise I'm reasonably computer savvy and know my way around python. Obviously Catia is a commercial application but I have access to the .tlb file if that helps. best regards Peter Enenkel -------------- next part -------------- An HTML attachment was scrubbed... URL: From puirippo at gmail.com Sat Feb 18 11:22:45 2017 From: puirippo at gmail.com (Filippo Scotti) Date: Sat, 18 Feb 2017 11:22:45 -0500 Subject: [python-win32] 2D array from win32com Message-ID: Hello Tim, thank you for your response. This is the ActiveGige SDK by A&B. The method description only says it returns the 2D array of image buffer values with a return value type Variant (SAFEARRAY). Thanks, Filippo -------------- next part -------------- An HTML attachment was scrubbed... URL: From puirippo at gmail.com Sun Feb 19 03:48:43 2017 From: puirippo at gmail.com (Filippo Scotti) Date: Sun, 19 Feb 2017 03:48:43 -0500 Subject: [python-win32] 2D array from win32com (Tim Roberts) Message-ID: Hello Tim, thank you for your response. This is the ActiveGige SDK by A&B. The method description only says it returns the 2D array of image buffer values with a return value type Variant (SAFEARRAY). Thanks, Filippo > Date: Fri, 17 Feb 2017 13:55:39 -0800 > From: Tim Roberts > To: "python-win32 at python.org" > Subject: Re: [python-win32] 2D array from win32com > Message-ID: <61f63573-555b-6d3f-d7b6-b6a8c4f7dea6 at probo.com> > Content-Type: text/plain; charset="utf-8" > > Filippo Scotti wrote: > > > > I am expecting a 720x480 array (safearray, 1 byte/pixel) from the > > method below from a camera SDK but win32com is returning a byte buffer > > of size 720. Extracting the data from the buffer I can get pixel > > values of only 1 row of pixels and not the entire 2D array. How can I > > get the 2D array? > > Which camera SDK is this? Do you know exactly what this API is > returning? Is it a SAFEARRAY of SAFEARRAYs, or have they cheated by > returning something else? Two dimensional arrays are not trivial in > COM. I write USB camera drivers, and the APIs I've done return the > frames as one large vector. > > -- > Tim Roberts, timr at probo.com > Providenza & Boekelheide, Inc. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From A.Holtz at gmx.net Sun Feb 19 10:23:25 2017 From: A.Holtz at gmx.net (Andreas Holtz) Date: Sun, 19 Feb 2017 16:23:25 +0100 Subject: [python-win32] passing array by reference (3) In-Reply-To: References: Message-ID: <33514573-fffd-5fe9-3e29-3a90194cbece@gmx.net> Hi Peter, >From Python call Catia.SystemService.Evaluate() and hand over a VB script that does what you need but returns an Array. This works for all CATIA methods that use an Array as Input/Output-parameter. Regards Andreas Peter Enenkel schrieb am 17.02.2017 um 23:29: > Hello All, > > > I'm trying to read some data from CATIA v5 (which is an older CAD application) via its COM server. > Overall it works rather well, even if I'm fairly new to COM communication. > > Nevertheless I have run into a problem: One specific function *GetComponents * is supposed to return > its results via an array passed by reference. As far as I can tell it is exactly the same problem as > in (1)https://mail.python.org/pipermail/python-win32/2002-November/000562.html > and > (2)https://mail.python.org/pipermail/python-win32/2014-July/013234.html > unfortunately there doesn't > appear to be a solution as of yet. > > The python call looks something like this > a = list(range(0,12)) > b = catapp.ActiveProduct.Position.GetComponents(a) > print(a) # outputs (0,1,2,3,4,5,6,7,8,9,10,11) instead of the actual values > The equivalent VBScript code is > Dim a(11) As Float > CATIA.ActiveProduct.Position.GetComponents(a) > MsgBox a(0) & ", " & a(1) & ... > The VBScript works as intended, the python one just passes the array back out unmodified. > > As both other threads state: The Position object above has two methods *GetComponents *and > *SetComponents *that each take a *CATSafeArrayVariant *as an argument. This *CATSafeArrayVariant > *should in this case be a one-dimensional array of real values. CATSafeArrayVariant is a typedef for > a *CATVariant *which itself is *typedef any CATVariant*. > > Any help would be appreciated. As stated above I haven't done much with COM, but otherwise I'm > reasonably computer savvy and know my way around python. Obviously Catia is a commercial application > but I have access to the .tlb file if that helps. > > > best regards > Peter Enenkel > > > _______________________________________________ > python-win32 mailing list > python-win32 at python.org > https://mail.python.org/mailman/listinfo/python-win32 > From A.Holtz at gmx.net Sun Feb 19 14:48:49 2017 From: A.Holtz at gmx.net (Andreas Holtz) Date: Sun, 19 Feb 2017 20:48:49 +0100 Subject: [python-win32] passing array by reference (3) In-Reply-To: References: <33514573-fffd-5fe9-3e29-3a90194cbece@gmx.net> Message-ID: <99dc7b87-675b-db1b-6bdb-ee68b0f82048@gmx.net> Hi Peter, yes, this works fine. We used to walk through a tree of Products collecting all position matrizes, on the Measurable-object to get the points of a line and other stuff. And yes, you pass the object (product, measurable, etc.) to the Evaluate function. Although it would be much better to be able to use Arrays as Input/Output-parameters. Regards Andreas Peter Enenkel schrieb am 19.02.2017 um 20:38: > Hello Andreas, > > thanks for this workaround suggestion. Do you know if this will work if I want to evaluate something > context sensitive? I.E. Instead of evaluating something in the global context like the previously > mentioned /CATIA.ActiveProduct.Position.//GetComponents(components)/ which would refer to the > toplevel element, I want to use Python to navigate to some other /Product /and then pass that to the > VBScript to call /someproduct.//Position.GetComponents(components). /Can I simply pass a Python COM > Object to /CATIA.SystemService.Evaluate/ as a parameter? > > I will definitely try this on Monday. > > An other idea I came up over the weekend is using the VARIANT type, like it is described here > do you > think that is a viable option, or am I misunderstanding the purpose of this construct? > > best regards > Peter Enenkel > > 2017-02-19 16:23 GMT+01:00 Andreas Holtz >: > > Hi Peter, > > >From Python call Catia.SystemService.Evaluate() and hand over a VB script that does what you need > but returns an Array. > > This works for all CATIA methods that use an Array as Input/Output-parameter. > > Regards > > Andreas > > > Peter Enenkel schrieb am 17.02.2017 um 23:29: > > Hello All, > > > > > > I'm trying to read some data from CATIA v5 (which is an older CAD application) via its COM server. > > Overall it works rather well, even if I'm fairly new to COM communication. > > > > Nevertheless I have run into a problem: One specific function *GetComponents * is supposed to > return > > its results via an array passed by reference. As far as I can tell it is exactly the same problem as > > in (1)https://mail.python.org/pipermail/python-win32/2002-November/000562.html > > > > and > > (2)https://mail.python.org/pipermail/python-win32/2014-July/013234.html > > > > unfortunately there doesn't > > appear to be a solution as of yet. > > > > The python call looks something like this > > a = list(range(0,12)) > > b = catapp.ActiveProduct.Position.GetComponents(a) > > print(a) # outputs (0,1,2,3,4,5,6,7,8,9,10,11) instead of the actual values > > The equivalent VBScript code is > > Dim a(11) As Float > > CATIA.ActiveProduct.Position.GetComponents(a) > > MsgBox a(0) & ", " & a(1) & ... > > The VBScript works as intended, the python one just passes the array back out unmodified. > > > > As both other threads state: The Position object above has two methods *GetComponents *and > > *SetComponents *that each take a *CATSafeArrayVariant *as an argument. This *CATSafeArrayVariant > > *should in this case be a one-dimensional array of real values. CATSafeArrayVariant is a > typedef for > > a *CATVariant *which itself is *typedef any CATVariant*. > > > > Any help would be appreciated. As stated above I haven't done much with COM, but otherwise I'm > > reasonably computer savvy and know my way around python. Obviously Catia is a commercial application > > but I have access to the .tlb file if that helps. > > > > > > best regards > > Peter Enenkel > > > > > > _______________________________________________ > > python-win32 mailing list > > python-win32 at python.org > > https://mail.python.org/mailman/listinfo/python-win32 > > > > _______________________________________________ > python-win32 mailing list > python-win32 at python.org > https://mail.python.org/mailman/listinfo/python-win32 > > > From A.Holtz at gmx.net Sun Feb 19 14:57:28 2017 From: A.Holtz at gmx.net (Andreas Holtz) Date: Sun, 19 Feb 2017 20:57:28 +0100 Subject: [python-win32] passing array by reference (3) In-Reply-To: References: <33514573-fffd-5fe9-3e29-3a90194cbece@gmx.net> Message-ID: I missed your second questions: I have no experience with this. But it looks like one could wrap a Python-array in such a VARIANT object and hand this to CATIA, like: v = VARIANT(pythoncom.VT_BYREF | pythoncom.VT_ARRAY | pythoncom.VT_R4, 12*[1.]) Worth a try. Peter Enenkel schrieb am 19.02.2017 um 20:38: > An other idea I came up over the weekend is using the VARIANT type, like it is described here > do you > think that is a viable option, or am I misunderstanding the purpose of this construct? From denis.akhiyarov at gmail.com Sun Feb 19 11:33:58 2017 From: denis.akhiyarov at gmail.com (Denis Akhiyarov) Date: Sun, 19 Feb 2017 16:33:58 +0000 Subject: [python-win32] Python win32Com Server DLL In-Reply-To: References: Message-ID: .NET uses RCW to cache calls into COM. I once used pythonnet to call into COM from Python using .NET COM interop. But this is not ready for general use due to the amount of boilerplate code necessary to make the calls. See this issue for more details. https://github.com/pythonnet/pythonnet/issues/260 On Sun, Feb 19, 2017, 6:04 AM Stephen Chapman wrote: > I thought that might be the answer. Thank you > > On Feb 17, 2017 4:53 PM, "Tim Roberts" wrote: > > Stephen Chapman wrote: > > > > Since it was a simple example I was only passing a single int for a > > parameter and returning 0. As far as I know COM servers don't cache > > responses I have never seen that happen anyway. > > That's not what I said. There are two parts to a late-dispatch COM > call: finding the address of the routine to call, and calling the > routine. Finding the address is a relatively expensive operation, > because you don't just have a pile of function pointers. You have to go > enumerate the list of methods and properties until you find the one you > want by comparing the names as strings, then go ask what the function's > signature is, then fake up a function call with that signature. It's > possible that C# caches that information so it can just make the call. > > However, I was assuming that both the client and server were in C#. Now > I see that it's only the server that's in C#, so my comment does not apply. > > > > However the question was really why in the order of magnitude is > > python so much slower for the same exact call. I have slightly > > changed my example to bump the number by one to show that it is not > > caching. And pass I am passing 4 parameters now so as to show how > > much longer python takes as you add more arguments. So here are the > > results. I have just done a simple timer in this example. > > ... > > So the function now bumps by one and has 4 parameters passing... So > > as you can see the Python code took 11 times longer to do this simple > > process > > If i add 5 more paramters C# only slightly goes up and Python more > > than doubles. > > Really, that's just the way it is. Interpreted Python code is always > going to be slower than the just-in-time compiled machine code from C#. > COM interfaces are optimized for C++, so the Python interface is always > going to have something of an impedance mismatch. 20 microseconds per > call is pretty fantastic, in my view, but if your application is one > where performance over millions of calls is absolutely critical, then > you should not move to Python. > > -- > Tim Roberts, timr at probo.com > Providenza & Boekelheide, Inc. > > _______________________________________________ > python-win32 mailing list > python-win32 at python.org > https://mail.python.org/mailman/listinfo/python-win32 > > _______________________________________________ > python-win32 mailing list > python-win32 at python.org > https://mail.python.org/mailman/listinfo/python-win32 > -------------- next part -------------- An HTML attachment was scrubbed... URL: From peter.enenkel+python at gmail.com Sun Feb 19 14:38:17 2017 From: peter.enenkel+python at gmail.com (Peter Enenkel) Date: Sun, 19 Feb 2017 20:38:17 +0100 Subject: [python-win32] passing array by reference (3) In-Reply-To: <33514573-fffd-5fe9-3e29-3a90194cbece@gmx.net> References: <33514573-fffd-5fe9-3e29-3a90194cbece@gmx.net> Message-ID: Hello Andreas, thanks for this workaround suggestion. Do you know if this will work if I want to evaluate something context sensitive? I.E. Instead of evaluating something in the global context like the previously mentioned *CATIA.ActiveProduct.Position.**GetComponents(components)* which would refer to the toplevel element, I want to use Python to navigate to some other *Product *and then pass that to the VBScript to call *someproduct.**Position.GetComponents(components). *Can I simply pass a Python COM Object to *CATIA.SystemService.Evaluate* as a parameter? I will definitely try this on Monday. An other idea I came up over the weekend is using the VARIANT type, like it is described here do you think that is a viable option, or am I misunderstanding the purpose of this construct? best regards Peter Enenkel 2017-02-19 16:23 GMT+01:00 Andreas Holtz : > Hi Peter, > > From Python call Catia.SystemService.Evaluate() and hand over a VB script > that does what you need > but returns an Array. > > This works for all CATIA methods that use an Array as > Input/Output-parameter. > > Regards > > Andreas > > > Peter Enenkel schrieb am 17.02.2017 um 23:29: > > Hello All, > > > > > > I'm trying to read some data from CATIA v5 (which is an older CAD > application) via its COM server. > > Overall it works rather well, even if I'm fairly new to COM > communication. > > > > Nevertheless I have run into a problem: One specific function > *GetComponents * is supposed to return > > its results via an array passed by reference. As far as I can tell it is > exactly the same problem as > > in (1)https://mail.python.org/pipermail/python-win32/2002- > November/000562.html > > November/000562.html> and > > (2)https://mail.python.org/pipermail/python-win32/2014-July/013234.html > > > unfortunately there doesn't > > appear to be a solution as of yet. > > > > The python call looks something like this > > a = list(range(0,12)) > > b = catapp.ActiveProduct.Position.GetComponents(a) > > print(a) # outputs (0,1,2,3,4,5,6,7,8,9,10,11) instead of the actual > values > > The equivalent VBScript code is > > Dim a(11) As Float > > CATIA.ActiveProduct.Position.GetComponents(a) > > MsgBox a(0) & ", " & a(1) & ... > > The VBScript works as intended, the python one just passes the array > back out unmodified. > > > > As both other threads state: The Position object above has two methods > *GetComponents *and > > *SetComponents *that each take a *CATSafeArrayVariant *as an argument. > This *CATSafeArrayVariant > > *should in this case be a one-dimensional array of real values. > CATSafeArrayVariant is a typedef for > > a *CATVariant *which itself is *typedef any CATVariant*. > > > > Any help would be appreciated. As stated above I haven't done much with > COM, but otherwise I'm > > reasonably computer savvy and know my way around python. Obviously Catia > is a commercial application > > but I have access to the .tlb file if that helps. > > > > > > best regards > > Peter Enenkel > > > > > > _______________________________________________ > > python-win32 mailing list > > python-win32 at python.org > > https://mail.python.org/mailman/listinfo/python-win32 > > > _______________________________________________ > python-win32 mailing list > python-win32 at python.org > https://mail.python.org/mailman/listinfo/python-win32 > -------------- next part -------------- An HTML attachment was scrubbed... URL: From timr at probo.com Mon Feb 20 13:07:43 2017 From: timr at probo.com (Tim Roberts) Date: Mon, 20 Feb 2017 10:07:43 -0800 Subject: [python-win32] passing array by reference (3) In-Reply-To: References: Message-ID: Peter Enenkel wrote: > > I'm trying to read some data from CATIA v5 (which is an older CAD > application) via its COM server. Overall it works rather well, even if > I'm fairly new to COM communication. > > Nevertheless I have run into a problem: One specific function > *GetComponents * is supposed to return its results via an array passed > by reference. As far as I can tell it is exactly the same problem as > in > (1)https://mail.python.org/pipermail/python-win32/2002-November/000562.html > and > (2)https://mail.python.org/pipermail/python-win32/2014-July/013234.html > unfortunately there doesn't appear to be a solution as of yet. > > The python call looks something like this > a = list(range(0,12)) > b = catapp.ActiveProduct.Position.GetComponents(a) > print(a) # outputs (0,1,2,3,4,5,6,7,8,9,10,11) instead of the actual > values Usually, in this kind of situation, the array would be an output parameter: b, a = catapp.ActiveProduct.Position.GetComponents() Remember that Python doesn't actually do pass-by-reference in the way you are used to. In your code above, you aren't really passing "a". What you're passing is the list that "a" is bound to. The Python COM code converts that into whatever type the function wants. If that array gets changed, it doesn't change the list. It can't, because that parameter might actually have been a tuple, which can't be modified, and there is no way for the function to change the binding of "a". That's why the COM stuff usually returns the changed parameter, so you can change your binding. Do you have the actual function signature in C++ or IDL form? If they haven't declared it properly, PythonCOM might not be able to determine that this is an output parameter. -- Tim Roberts, timr at probo.com Providenza & Boekelheide, Inc. From peter.enenkel+python at gmail.com Mon Feb 20 14:46:18 2017 From: peter.enenkel+python at gmail.com (Peter Enenkel) Date: Mon, 20 Feb 2017 20:46:18 +0100 Subject: [python-win32] passing array by reference (3) In-Reply-To: References: Message-ID: Hello Tim, I concur that the array SHOULD be a return value (at the very least in Python). Unfortunately it isn't. Definitely not with late binding and I think not with early binding. The function does expect a parameter of the described type and does not return anything. In my opinion it would theoretically be possible to process an argument by reference in Python, of cause it would have to be a mutable object. Which, as you mentioned, tuples are not, so it would have to be restricted to lists or some specialized transport object. Admittedly, any such solution would not be particularly pythonic. I thought that the pythoncom.VARIANT class is such a transport object. But I could not get it to work. I suspect that you are correct that the interface might not be declared properly on the serverside. On the other hand similar problems with passing arrays by reference seem to have cropped up with other COM servers also. I have access to the official Catia V5 automation IDL documentation (which is reasonably complete) as well as the .tlb files. But I do not know what I could do with the later. Unfortunately Catia has deemed it necessary to split the COM server into several (more that two dozen) files which doesn't exactly help with early binding and identifying the required interfaces. That is probably one of the reasons I could not get it to work with early binding. An other difficulty with that is, that (interface) inheritance is used, i.e. both PartDocument and ProductDocument both inherit from Document but each has additional attributes. Functions always seem to return the base type which then would require some kind of cast. I have managed to implement a workaround in the manner that Andreas Holtz suggested. That is, using win32com to instruct Catia to execute a VBScript function which calls GetComponents with an ByRef argument and then returns it as a return value, which in turn is passed back to python. Not a particularly elegant solution, but it works! So the pressure to find a "native" solution isn't quite as high as before. Nevertheless I'm still interested in a way to do it "right". If you have any ideas in that direction I'd appreciate hearing them. best regards Peter 2017-02-20 19:07 GMT+01:00 Tim Roberts : > Peter Enenkel wrote: > > > > I'm trying to read some data from CATIA v5 (which is an older CAD > > application) via its COM server. Overall it works rather well, even if > > I'm fairly new to COM communication. > > > > Nevertheless I have run into a problem: One specific function > > *GetComponents * is supposed to return its results via an array passed > > by reference. As far as I can tell it is exactly the same problem as > > in > > (1)https://mail.python.org/pipermail/python-win32/2002- > November/000562.html > > and > > (2)https://mail.python.org/pipermail/python-win32/2014-July/013234.html > > unfortunately there doesn't appear to be a solution as of yet. > > > > The python call looks something like this > > a = list(range(0,12)) > > b = catapp.ActiveProduct.Position.GetComponents(a) > > print(a) # outputs (0,1,2,3,4,5,6,7,8,9,10,11) instead of the actual > > values > > Usually, in this kind of situation, the array would be an output parameter: > > b, a = catapp.ActiveProduct.Position.GetComponents() > > Remember that Python doesn't actually do pass-by-reference in the way > you are used to. In your code above, you aren't really passing "a". > What you're passing is the list that "a" is bound to. The Python COM > code converts that into whatever type the function wants. If that array > gets changed, it doesn't change the list. It can't, because that > parameter might actually have been a tuple, which can't be modified, and > there is no way for the function to change the binding of "a". That's > why the COM stuff usually returns the changed parameter, so you can > change your binding. > > Do you have the actual function signature in C++ or IDL form? If they > haven't declared it properly, PythonCOM might not be able to determine > that this is an output parameter. > > -- > Tim Roberts, timr at probo.com > Providenza & Boekelheide, Inc. > > _______________________________________________ > python-win32 mailing list > python-win32 at python.org > https://mail.python.org/mailman/listinfo/python-win32 > -------------- next part -------------- An HTML attachment was scrubbed... URL: From peter.enenkel+python at gmail.com Mon Feb 20 14:50:07 2017 From: peter.enenkel+python at gmail.com (Peter Enenkel) Date: Mon, 20 Feb 2017 20:50:07 +0100 Subject: [python-win32] passing array by reference (3) In-Reply-To: References: <33514573-fffd-5fe9-3e29-3a90194cbece@gmx.net> Message-ID: Hello Andreas, I have managed to cobble together a solution following your initial suggestion. Not really elegant, but it works quite well. Many thanks. best regards Peter 2017-02-19 20:57 GMT+01:00 Andreas Holtz : > I missed your second questions: > I have no experience with this. But it looks like one could wrap a > Python-array in such a VARIANT > object and hand this to CATIA, like: > > v = VARIANT(pythoncom.VT_BYREF | pythoncom.VT_ARRAY | pythoncom.VT_R4, > 12*[1.]) > > Worth a try. > > Peter Enenkel schrieb am 19.02.2017 um 20:38: > > An other idea I came up over the weekend is using the VARIANT type, like > it is described here > > com/win32com/HTML/variant.html> do you > > think that is a viable option, or am I misunderstanding the purpose of > this construct? > -------------- next part -------------- An HTML attachment was scrubbed... URL: From Andrew.MacIntyre at acma.gov.au Mon Feb 20 18:33:53 2017 From: Andrew.MacIntyre at acma.gov.au (Andrew MacIntyre) Date: Mon, 20 Feb 2017 23:33:53 +0000 Subject: [python-win32] passing array by reference (3) [SEC=UNCLASSIFIED] Message-ID: <62c13b6460ef42cda99c00656f23ea2a@cbrexc1301pp.internal.govt> If you?re prepared to consider another approach, comtypes (https://pypi.python.org/pypi/comtypes) can generate module definitions from TLB files. Comtypes supports passing by reference via the underlying ctypes FFI. Andrew. -------------------------> "These thoughts are mine alone!" <--------- Andrew MacIntyre Operations, Services and Technologies Branch tel: +61 2 6219 5356 Communications Infrastructure Division Australian Communications & Media Authority email: andrew.macintyre at acma.gov.au http://www.acma.gov.au/ From: python-win32 [mailto:python-win32-bounces+andrew.macintyre=acma.gov.au at python.org] On Behalf Of Peter Enenkel Sent: Tuesday, 21 February 2017 6:46 AM To: Tim Roberts Cc: python-win32 at python.org Subject: Re: [python-win32] passing array by reference (3) Hello Tim, I concur that the array SHOULD be a return value (at the very least in Python). Unfortunately it isn't. Definitely not with late binding and I think not with early binding. The function does expect a parameter of the described type and does not return anything. In my opinion it would theoretically be possible to process an argument by reference in Python, of cause it would have to be a mutable object. Which, as you mentioned, tuples are not, so it would have to be restricted to lists or some specialized transport object. Admittedly, any such solution would not be particularly pythonic. I thought that the pythoncom.VARIANT class is such a transport object. But I could not get it to work. I suspect that you are correct that the interface might not be declared properly on the serverside. On the other hand similar problems with passing arrays by reference seem to have cropped up with other COM servers also. I have access to the official Catia V5 automation IDL documentation (which is reasonably complete) as well as the .tlb files. But I do not know what I could do with the later. Unfortunately Catia has deemed it necessary to split the COM server into several (more that two dozen) files which doesn't exactly help with early binding and identifying the required interfaces. That is probably one of the reasons I could not get it to work with early binding. An other difficulty with that is, that (interface) inheritance is used, i.e. both PartDocument and ProductDocument both inherit from Document but each has additional attributes. Functions always seem to return the base type which then would require some kind of cast. I have managed to implement a workaround in the manner that Andreas Holtz suggested. That is, using win32com to instruct Catia to execute a VBScript function which calls GetComponents with an ByRef argument and then returns it as a return value, which in turn is passed back to python. Not a particularly elegant solution, but it works! So the pressure to find a "native" solution isn't quite as high as before. Nevertheless I'm still interested in a way to do it "right". If you have any ideas in that direction I'd appreciate hearing them. best regards Peter 2017-02-20 19:07 GMT+01:00 Tim Roberts >: Peter Enenkel wrote: > > I'm trying to read some data from CATIA v5 (which is an older CAD > application) via its COM server. Overall it works rather well, even if > I'm fairly new to COM communication. > > Nevertheless I have run into a problem: One specific function > *GetComponents * is supposed to return its results via an array passed > by reference. As far as I can tell it is exactly the same problem as > in > (1)https://mail.python.org/pipermail/python-win32/2002-November/000562.html > and > (2)https://mail.python.org/pipermail/python-win32/2014-July/013234.html > unfortunately there doesn't appear to be a solution as of yet. > > The python call looks something like this > a = list(range(0,12)) > b = catapp.ActiveProduct.Position.GetComponents(a) > print(a) # outputs (0,1,2,3,4,5,6,7,8,9,10,11) instead of the actual > values Usually, in this kind of situation, the array would be an output parameter: b, a = catapp.ActiveProduct.Position.GetComponents() Remember that Python doesn't actually do pass-by-reference in the way you are used to. In your code above, you aren't really passing "a". What you're passing is the list that "a" is bound to. The Python COM code converts that into whatever type the function wants. If that array gets changed, it doesn't change the list. It can't, because that parameter might actually have been a tuple, which can't be modified, and there is no way for the function to change the binding of "a". That's why the COM stuff usually returns the changed parameter, so you can change your binding. Do you have the actual function signature in C++ or IDL form? If they haven't declared it properly, PythonCOM might not be able to determine that this is an output parameter. -- Tim Roberts, timr at probo.com Providenza & Boekelheide, Inc. _______________________________________________ python-win32 mailing list python-win32 at python.org https://mail.python.org/mailman/listinfo/python-win32 NOTICE: This email message is for the sole use of the intended recipient(s) and may contain confidential and privileged information. Any unauthorized review, use, disclosure or distribution is prohibited. If you are not the intended recipient, please contact the sender by reply email and destroy all copies of the original message. -------------- next part -------------- An HTML attachment was scrubbed... URL: