-
-
Notifications
You must be signed in to change notification settings - Fork 100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Multiple instances of Autocad #520
Comments
I now found the following: https://stackoverflow.com/questions/63562678/how-to-reference-the-com-objects-of-all-the-running-excel-application-instances |
Upon examining the C# code, moniker seems to be relevant. Here are the relevant code snippets:
However, as I am not well-versed in C#, I hope that those who proficient in both Python and C# provide further insights. |
Unfortunately, I have no ideas what I'm trying now to rewrite the following code from here from pywin32 to comtypes: from pythoncom import (
CreateBindCtx as create_bind_context_com_interface,
IID_IDispatch as dispatch_com_interface_iid,
GetRunningObjectTable as get_running_object_table_com_interface,
)
from win32com.client import (
Dispatch as dispatch,
)
def get_excel_instances():
'''
Returns a list of the running Microsoft Excel application
instances as component object model (COM) objects.
'''
running_object_table_com_interface = get_running_object_table_com_interface()
bind_context_com_interface = create_bind_context_com_interface()
excel_application_class_clsid = '{00024500-0000-0000-C000-000000000046}'
excel_application_clsid = '{000208D5-0000-0000-C000-000000000046}'
excel_instance_com_objects = []
for moniker_com_interface in running_object_table_com_interface:
display_name = moniker_com_interface.GetDisplayName(bind_context_com_interface, None)
if excel_application_class_clsid not in display_name:
continue
unknown_com_interface = running_object_table_com_interface.GetObject(moniker_com_interface)
dispatch_com_interface = unknown_com_interface.QueryInterface(dispatch_com_interface_iid)
dispatch_clsid = str(object=dispatch_com_interface.GetTypeInfo().GetTypeAttr().iid)
if dispatch_clsid != excel_application_clsid:
continue
excel_instance_com_object = dispatch(dispatch=dispatch_com_interface)
excel_instance_com_objects.append(excel_instance_com_object)
return excel_instance_com_objects
excel_instances = get_excel_instances()
input() My code: import ctypes
get_running_object_table = ctypes.oledll.ole32.GetRunningObjectTable Now I need to pass 2 parameters to |
The By referring to this, it should be possible to define a subclass that inherits from Moreover, when searching GitHub with |
Is there an update on this issue? |
Sorry, your last answer was still difficult for me. A few days ago I found this article how to use ctypes to work with Win32 API. After this excellent article, I have a much better understanding of your answer. Now I decided to learn a basics of C programming language, because I still have a poor C knowledge to use ctypes and comtypes efficiently. I steel not sure how to model As for now using this answer from StackOverflow is the best way to solve this problem, so we can close this issue. Alternatively, you could create a function in comtypes that finds all instances. Anyway, it's interesting topic how to solve this using ctypes/comtypes and I hope I'll be able to do this in the future. |
Your attempt is wonderful. I'm not familiar with C language either, and these are unknown territories for me. If you could write a description of the usecase and tests, I can make resources to review your PR. For sharing difficulties and technical consultations, I think we should keep this issue open. |
Recently, I had the opportunity to read the Japanese translations of "Inside COM" by Dale Rogerson, "Essential COM" by Don Box, and "Inside OLE" by Kraig Brockschmidt, which are available in public libraries in Japan. These books provided overviews and usage instructions for I also realized that the wrapper module generated by By combining these interfaces with helper functions from from ctypes import byref, oledll, POINTER
from typing import Iterator, Sequence, Type, TypeVar
from comtypes import GUID
from comtypes.automation import IDispatch
from comtypes.client import GetModule
GetModule("msvidctl.dll")
from comtypes.gen.MSVidCtlLib import IBindCtx, IMoniker, IRunningObjectTable
def GetRunningObjectTable() -> IRunningObjectTable:
"""Returns a pointer to the IRunningObjectTable interface on the local
running object table (ROT).
https://learn.microsoft.com/en-us/windows/win32/api/objbase/nf-objbase-getrunningobjecttable
"""
rot = POINTER(IRunningObjectTable)()
# The first parameter is reserved and must be 0.
oledll.ole32.GetRunningObjectTable(0, byref(rot))
return rot # type: ignore
def CreateBindCtx() -> IBindCtx:
"""Returns a pointer to an implementation of IBindCtx (a bind context object).
This object stores information about a particular moniker-binding operation.
https://learn.microsoft.com/en-us/windows/win32/api/objbase/nf-objbase-createbindctx
"""
bctx = POINTER(IBindCtx)()
# The first parameter is reserved and must be 0.
oledll.ole32.CreateBindCtx(0, byref(bctx))
return bctx # type: ignore
def _iterate_moniker(rot: IRunningObjectTable) -> Iterator[IMoniker]:
enum_running = rot.EnumRunning()
while True:
item, fetched = enum_running.RemoteNext(1)
if fetched:
yield item
else:
break
_T_IDispatch = TypeVar("_T_IDispatch", bound=IDispatch)
def get_running_objects(
reg_clsid: GUID, interface: Type[_T_IDispatch]
) -> Sequence[_T_IDispatch]:
objs = []
rot = GetRunningObjectTable()
bctx = CreateBindCtx()
for moniker in _iterate_moniker(rot):
name = moniker.GetDisplayName(bctx, None)
if str(reg_clsid) not in name:
continue
disp: IDispatch = rot.GetObject(moniker).QueryInterface(IDispatch)
if interface._iid_ != disp.GetTypeInfo(0).GetTypeAttr().guid:
continue
objs.append(disp.QueryInterface(interface))
return objs With a test like the one below, we can verify that the running Excel application can be retrieved. import unittest
from comtypes.client import GetModule
GetModule(("{00020813-0000-0000-C000-000000000046}",)) # Excel libUUID
from comtypes.gen import Excel
class Test(unittest.TestCase):
def test(self):
coclass = Excel.Application
interface = Excel._Application
objs = get_running_objects(coclass._reg_clsid_, interface)
self.assertTrue(bool(objs))
self.assertTrue(all(isinstance(o, interface) for o in objs)) |
@sindzicat from pathlib import Path
import unittest
from comtypes.client import GetModule
zwcad_tlib_path: Path = Path('C:/Program Files/Common Files/ZWSoft Shared/zwcad21.tlb')
GetModule(str(zwcad_tlib_path)) # Generate the module or ensure its existence.
from comtypes.gen import ZWCAD # importing statically to analyze static typing
class Test(unittest.TestCase):
def test(self):
coclass = ZWCAD.ZcadApplication
interface = ZWCAD.IZcadApplication
objs = get_running_objects(coclass._reg_clsid_, interface)
self.assertTrue(bool(objs))
self.assertTrue(all(isinstance(o, interface) for o in objs)) |
Hello!
I know, that if Autocad is already running, we can use
comtypes.client.GetActiveObject
:But what to do, if multiple instances of Autocad is running?
I found the code to solve this issue, but it's in C#:
I know it's possible to translate the C# code above to Python, but I don't know C# to do so. Anybody know it to translate, please?
The text was updated successfully, but these errors were encountered: