Is is possible in Dolphin 4 to open an already running instance of Excel?
|
I believe if you wrap the Excel COM objects, you can do this. You'll have
to review MS's docs to be sure. jlo "ar" <[hidden email]> wrote in message news:[hidden email]... > Is is possible in Dolphin 4 to open an already running instance of Excel? |
In reply to this post by ar-2
"ar" <[hidden email]> wrote in message
news:[hidden email]... > Is is possible in Dolphin 4 to open an already running instance of Excel? Yes. Using CoGetObject() is simplest. Regards Blair ---------------------- | package | package := Package name: 'GetObject'. package paxVersion: 0; basicComment: 'For example: obj := IDispatch newPointer. OLELibrary default coGetObject: ''Book1'' asUnicodeString pBindOptions: nil riid: IDispatch iid ppv: obj. obj typeInfo.'. package basicPackageVersion: ''. "Add the package scripts" "Add the class names, loose method names, global names, resource names" package classNames add: #BIND_OPTS; yourself. package methodNames add: #OLELibrary -> #coGetObject:pBindOptions:riid:ppv:; yourself. package globalNames yourself. package resourceNames yourself. "Binary Global Names" package binaryGlobalNames: (Set new yourself). "Resource Names" package allResourceNames: (Set new yourself). "Add the prerequisite names" package setPrerequisites: (IdentitySet new add: 'Dolphin'; add: 'OLE COM'; yourself). package! "Class Definitions"! OLEStructure subclass: #BIND_OPTS instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' classInstanceVariableNames: ''! "Loose Methods"! !OLELibrary methodsFor! coGetObject: wszName pBindOptions: aBIND_OPTS riid: anIID ppv: anIUnknown <stdcall: sdword CoGetObject lpwstr BIND_OPTS* IID* void**> ^self invalidCall! ! !OLELibrary categoriesFor: #coGetObject:pBindOptions:riid:ppv:!*-primitives!OLE Functions-COM!public! ! "End of package definition"! BIND_OPTS comment: 'BIND_OPTS is an external structure class to represent the OLE moniker structure of the same name. BIND_OPTS is used to specify options to be taken account of when a moniker is being bound. These options are set into the bind context with IBindCtx:::SetBindOptions, and retrived with IBindCtx::GetBindOptions. BIND_OPTS has been superceded by BIND_OPTS2 with the advent of DCOM.'! BIND_OPTS guid: (GUID fromString: '{87B4C5B3-026E-11D3-9FD7-00A0CC3E4A32}')! !BIND_OPTS categoriesForClass!External-Data-Structured-COM! ! !BIND_OPTS methodsFor! dwSize: anObject "Set the receiver's dwSize field to the value of anObject. This method has been automatically generated from the class' structure template. Any modifications you make will be lost the next time it is so generated." bytes dwordAtOffset: 0 put: anObject! dwTickCountDeadline "Answer the receiver's dwTickCountDeadline field as a Smalltalk object. This method has been automatically generated from the class' structure template. Any modifications you make will be lost the next time it is so generated." ^(bytes dwordAtOffset: 12)! dwTickCountDeadline: anObject "Set the receiver's dwTickCountDeadline field to the value of anObject. This method has been automatically generated from the class' structure template. Any modifications you make will be lost the next time it is so generated." bytes dwordAtOffset: 12 put: anObject! grfFlags "Answer the receiver's grfFlags field as a Smalltalk object. This method has been automatically generated from the class' structure template. Any modifications you make will be lost the next time it is so generated." ^(bytes dwordAtOffset: 4)! grfFlags: anObject "Set the receiver's grfFlags field to the value of anObject. This method has been automatically generated from the class' structure template. Any modifications you make will be lost the next time it is so generated." bytes dwordAtOffset: 4 put: anObject! grfMode "Answer the receiver's grfMode field as a Smalltalk object. This method has been automatically generated from the class' structure template. Any modifications you make will be lost the next time it is so generated." ^(bytes dwordAtOffset: 8)! grfMode: anObject "Set the receiver's grfMode field to the value of anObject. This method has been automatically generated from the class' structure template. Any modifications you make will be lost the next time it is so generated." bytes dwordAtOffset: 8 put: anObject! ! !BIND_OPTS categoriesFor: #dwSize:!**compiled accessors**!public! ! !BIND_OPTS categoriesFor: #dwTickCountDeadline!**compiled accessors**!public! ! !BIND_OPTS categoriesFor: #dwTickCountDeadline:!**compiled accessors**!public! ! !BIND_OPTS categoriesFor: #grfFlags!**compiled accessors**!public! ! !BIND_OPTS categoriesFor: #grfFlags:!**compiled accessors**!public! ! !BIND_OPTS categoriesFor: #grfMode!**compiled accessors**!public! ! !BIND_OPTS categoriesFor: #grfMode:!**compiled accessors**!public! ! !BIND_OPTS class methodsFor! defineFields "Define the fields of the BIND_OPTS structure. BIND_OPTS compileDefinition. struct BIND_OPTS { DWORD cbStruct; DWORD grfFlags; DWORD grfMode; DWORD dwTickCountDeadline; }; " self "Use standard name for structure size member" defineField: #dwSize type: DWORDField writeOnly beOverride; defineField: #grfFlags type: DWORDField new; defineField: #grfMode type: DWORDField new; defineField: #dwTickCountDeadline type: DWORDField new! ! !BIND_OPTS class categoriesFor: #defineFields!initializing!public! ! "Binary Globals"! "Resources"! |
Blair,
Works great, thanks for making this available. regards alan r On Tue, 5 Feb 2002 01:30:44 -0000, "Blair McGlashan" <[hidden email]> wrote: >"ar" <[hidden email]> wrote in message >news:[hidden email]... >> Is is possible in Dolphin 4 to open an already running instance of Excel? > >Yes. Using CoGetObject() is simplest. |
In reply to this post by Blair McGlashan
On Tue, 5 Feb 2002 01:30:44 -0000, "Blair McGlashan" <[hidden email]>
wrote: >"ar" <[hidden email]> wrote in message >news:[hidden email]... >> Is is possible in Dolphin 4 to open an already running instance of Excel? > >Yes. Using CoGetObject() is simplest. > >Regards > >Blair >---------------------- > >| package | >package := Package name: 'GetObject'. >package paxVersion: 0; > basicComment: 'For example: > >obj := IDispatch newPointer. >OLELibrary default coGetObject: ''Book1'' asUnicodeString pBindOptions: nil >riid: IDispatch iid ppv: obj. >obj typeInfo.'. I'd like to use getObject to find the first instance of Excel.Application, as opposed to looking for a particular workbook. I tried obj := IDispatch newPointer. OLELibrary default coGetObject: nil " or '' " pBindOptions: nil riid: 'Excel.Application' "or Excel.Application.9" ppv: obj. Should this work? I getting return value -2147024809 and obj = an IDispatch(an ExternalAddress(NULL)). In Excel itself, GetObject(,"Excel.Application.9") works (but only with the .9, it should also work without it I think). thanks for any help -alan r side note, I went way down the road (extending DeskTopView) of looping through all the top level windows to find the Excel window caption 'Microsoft Excel - Bookname' and trying getObject with Bookname. The problems are that while it works for things like 'Book1', for some reason it fails with an existing workbook loaded eg mybook.xls (qualified or not). Also I want to be able to find the Application even if no book has been loaded yet. |
"ar" <[hidden email]> wrote in message
news:[hidden email]... > On Tue, 5 Feb 2002 01:30:44 -0000, "Blair McGlashan" <[hidden email]> > wrote: > > >"ar" <[hidden email]> wrote in message > >news:[hidden email]... > >> Is is possible in Dolphin 4 to open an already running instance of Excel? > > > >Yes. Using CoGetObject() is simplest. > > > >Regards > > > >Blair > >---------------------- > > > >| package | > >package := Package name: 'GetObject'. > >package paxVersion: 0; > > basicComment: 'For example: > > > >obj := IDispatch newPointer. > >OLELibrary default coGetObject: ''Book1'' asUnicodeString pBindOptions: > >riid: IDispatch iid ppv: obj. > >obj typeInfo.'. > > I'd like to use getObject to find the first instance of Excel.Application, as > opposed to looking for a particular workbook. > > I tried > > obj := IDispatch newPointer. > OLELibrary default > coGetObject: nil " or '' " > pBindOptions: nil > riid: 'Excel.Application' "or Excel.Application.9" > ppv: obj. > > Should this work? No. You can't pass a string to parameter that expects an IID (i.e. a GUID that uniquely identifies an interface). What you need to do is to pass a "moniker" as the first argument that identifies the loaded document. Monikers are a very powerful concept, and I would suggest doing a bit or reading up on the subject at msdn.microsoft.com. Also locate and download Microsoft's ROTViewer tool (part of VisualStudio, and also the Platform SDK), and run it up with an Excel doc. open. This will help you determine the form of moniker to use. Don Box's writings on the subject are also well worth searching out. The VB(A) GetObject() call is a thin layer on top of CoGetObject(), but I would guess that it is mapping the progid 'Excel.Application' to a CLSID moniker. Regards Blair |
On Tue, 19 Mar 2002 22:56:48 -0000, "Blair McGlashan" <[hidden email]>
wrote: >The VB(A) GetObject() call is a thin layer on top of CoGetObject(), but I >would guess that it is mapping the progid 'Excel.Application' to a CLSID >moniker. Thanks for all the references. I have much to learn but what I have gleaned so far is that in VB if GetObject() is called with the 1st parameter omitted, then it becomes a call to getActiveObject() passing it the clsid from the getObject eg Excel.Application.9. So I think that getActiveObject is the method I need here. If you're inclined to add it to dolphin at some point when the pressure is off with D5, I'd appreciate it. Meanwhile I'll hack away at it. |
On Wed, 20 Mar 2002 01:23:34 GMT, ar <[hidden email]> wrote:
> Meanwhile I'll hack away at it. !OLEAutLibrary methodsFor! GetActiveObject: clsid pvReserved: ignore ppv: anIUnknown <stdcall: sdword GetActiveObject CLSID* lppvoid void**> ^self invalidCall " obj := IDispatch newPointer. OLEAutLibrary default GetActiveObject: XL_Application clsid pvReserved: nil ppv: obj. obj. app := obj queryInterface: XL_Application. " ! ! !OLEAutLibrary categoriesFor: #GetActiveObject:pvReserved:ppv:!OLE Functions-COM!public! ! When I started testing this, I was getting back a 0 return code but any operations on the object gave 'rpc server unavailable' messages. This went away on a reboot, so I guess there must have been zombies. So that is a potential reliability problem in using GetActiveObject(). alan r |
In reply to this post by ar-2
correction (declare return as hresult)
!OLEAutLibrary methodsFor! GetActiveObject: clsid pvReserved: ignore ppv: anIUnknown <stdcall: hresult GetActiveObject CLSID* lppvoid void**> ^self invalidCall " obj := IDispatch newPointer. OLEAutLibrary default GetActiveObject: XL_Application clsid pvReserved: nil ppv: obj. obj. app := obj queryInterface: XL_Application. " ! ! !OLEAutLibrary categoriesFor: #GetActiveObject:pvReserved:ppv:!OLE Functions-COM!public! ! |
In reply to this post by ar-2
"ar" <[hidden email]> wrote in message
news:[hidden email]... > On Wed, 20 Mar 2002 01:23:34 GMT, ar <[hidden email]> wrote: > ... > When I started testing this, I was getting back a 0 return code but any > operations on the object gave 'rpc server unavailable' messages. This went > away on a reboot, so I guess there must have been zombies. So that is a > potential reliability problem in using GetActiveObject(). There is a general problem of this sort with the Running Object Table (ROT) - it is possible for a server that shuts down incorrectly to leave stale entries in the ROT which will then be handed out. This is especially problematic on Win9X where the only solution if often to reboot (but then Win9X users are used to that :-)). There is an "undocumented" technique for working around this which is used by the regclean tool, however it involves getting a bit closer to the metal. I've attached some C++ code that implements GetObject for file monikers (open office docs are registered in the ROT as file monikers I think). It would be easy enough to translate into Smalltalk. I'm not sure how one would do something similar for GetActiveObject(). Regards Blair -------------------------- HRESULT GetObject(BSTR bstrID, IDispatch **ppiDisp) { // Note that rather than relying on IMoniker::BindToObject, we make our own // attempt at looking up the object in the ROT. This is in order to provide // robust handling of stale ROT entries. CComPtr<IRunningObjectTable> piROT; HRESULT hr = ::GetRunningObjectTable(0, &piROT); if (FAILED(hr)) return hr; CComPtr<IMoniker> piMk; hr = ::CreateFileMoniker(bstrID, &piMk); if (FAILED(hr)) return hr; if (piROT->IsRunning(piMk) == S_OK) { // It is apparently running, but is it live? Let's call GetObject to find out... CComPtr<IUnknown> punkExisting; hr = piROT->GetObject(piMk, &punkExisting); if (SUCCEEDED(hr) && punkExisting != NULL) { // It's live, so we can return it. return punkExisting->QueryInterface(IID_IDispatch, reinterpret_cast<void**>(ppiDisp)); } // else drop through and try the more traditional means } CComPtr<IBindCtx> pbc; hr = ::CreateBindCtx(0, &pbc); if (FAILED(hr)) // Nothing we can do to recover return hr; return piMk->BindToObject(pbc, NULL, IID_IDispatch, (void**)ppiDisp); } |
Free forum by Nabble | Edit this page |