GetObject Fails while CreateObject Works [duplicate] - excel

This question already has answers here:
How to use GetObject in VBScript
(2 answers)
Closed 3 years ago.
I recently got a small CG software package from my friend his father wrote about 30 years ago. It has a window where one can create and render some solid primitives. Interestingly, it has a VBA interface and I can in Excel (let’s call it TheSoftware) use Set app = CreateObject(“TheSoftware.Application”) to create such application (after setting app.Visible to True one can get the window on the screen)! However, the GetObject(, “TheSoftware.Application”) returns the “ActiveX component can’t create object” error. More surprisingly to me, the GetObject(“”, “TheSoftware.Application”) successfully creates the application! I have its source code in C++ about 900 KB that I can share, but just to be quick, has anyone had this issue before, or have a clue what may be the issue? I am no expert in C++, and the author passed away 4 years ago. I have seen the “opposite” problem of failing to create an object but OK when getting it, but not this one. Any idea is welcome, thanks!

GetObject(FName) opens a file or connects to a file if it already opened (and if class is specified use that class to open it) OR GetObject(,"Appname") connects to a running instance of an application. You are creating a blank file.
Visual Basic Scripting Edition
GetObject Function
See Also CreateObject Function
Requirements
Version 5
Returns a reference to an Automation object from a file.
GetObject([pathname] [, class])
Arguments
pathname
Optional; String. Full path and name of the file containing the object to retrieve.
If pathname is omitted, class is required.
class
Optional; String. Class of the object.
The class argument uses the syntax appname.objectype and has these
parts:
Use the GetObject function to access an Automation object from a file
and assign the object to an object variable. Use the Set statement to
assign the object returned by GetObject to the object variable. For
example:
Dim CADObject
Set CADObject = GetObject("C:\CAD\SCHEMA.CAD")
When this code is executed, the application associated with the
specified pathname is started and the object in the specified file is
activated. If pathname is a zero-length string (""), GetObject
returns a new object instance of the specified type. If the pathname
argument is omitted, GetObject returns a currently active object of
the specified type. If no object of the specified type exists, an
error occurs.
Some applications allow you to activate part of a file. Add an
exclamation point (!) to the end of the file name and follow it with a
string that identifies the part of the file you want to activate. For
information on how to create this string, see the documentation for
the application that created the object.
For example, in a drawing application you might have multiple layers
to a drawing stored in a file. You could use the following code to
activate a layer within a drawing called SCHEMA.CAD:
Set LayerObject = GetObject("C:\CAD\SCHEMA.CAD!Layer3")
If you don't specify the object's class, Automation determines the application to start and the object to activate, based on the file
name you provide. Some files, however, may support more than one class
of object. For example, a drawing might support three different types
of objects: an Application object, a Drawing object, and a Toolbar
object, all of which are part of the same file. To specify which
object in a file you want to activate, use the optional class
argument. For example:
Dim MyObject
Set MyObject = GetObject("C:\DRAWINGS\SAMPLE.DRW", "FIGMENT.DRAWING")
In the preceding example, FIGMENT is the name of a drawing application
and DRAWING is one of the object types it supports. Once an object is
activated, you reference it in code using the object variable you
defined. In the preceding example, you access properties and methods
of the new object using the object variable MyObject. For example:
MyObject.Line 9, 90
MyObject.InsertText 9, 100, "Hello, world."
MyObject.SaveAs "C:\DRAWINGS\SAMPLE.DRW"
Note Use the GetObject function when there is a current instance
of the object or if you want to create the object with a file already
loaded. If there is no current instance, and you don't want the
object started with a file loaded, use the CreateObject function.
If an object has registered itself as a single-instance object, only
one instance of the object is created, no matter how many times
CreateObject is executed. With a single-instance object, GetObject
always returns the same instance when called with the zero-length
string ("") syntax, and it causes an error if the pathname argument is
omitted.
Requirements Version 5
See Also CreateObject Function
© 2001 Microsoft Corporation. All rights reserved.
Build: Topic Version 5.6.9309.1546
Also these are the COM API calls that each form makes. From the Automation part of the COM docs.
CreateObject (“ProgID”)
CLSIDFromProgID
CoCreateInstance
QueryInterface to get IDispatch interface.
GetObject (“filename”, “ProgID”)
CLSIDFromProgID
CoCreateInstance
QueryInterface for IPersistFile interface.
Load on IPersistFile interface.
QueryInterface to get IDispatch interface.
GetObject (“filename”)
CreateBindCtx creates the bind context for the subsequent functions.
MkParseDisplayName returns a moniker handle for BindMoniker.
BindMoniker returns a pointer to the IDispatch interface.
Release on moniker handle.
Release on context.
GetObject (“ProgID”)
CLSIDFromProgID
GetActiveObject on class ID.
QueryInterface to get IDispatch interface.
Dim x As New interface
Find CLSID for interface.
CoCreateInstance
QueryInterface

Related

Confusion in creating excel application object using VB.net: CreateObject vs New

I am facing difficulty in understanding the following concepts. I had posted a question some time back - read through the answers but some things are still not clear. I state my confusion below:
My first question refers to the following code piece
Option Strict On
Imports Microsoft.Office.Interop
Dim oxl As Excel.Application
oxl = CreateObject("Excel.Application")
In the above code piece, the statement oxl = CreateObject("Excel.Application") throws an error stating, Option Strict On disallows implicit conversions from Object to Application. My question is I read from many sources that it is always better to keep Option Strict ON but in this case when we need to create a new excel application, the Option Strict ON is preventing us from doing so. So what is the best practice that should be followed for such a conflict?
Next I tried replacing the statement oxl = CreateObject("Excel.Application") with oxl = New Excel.Application. It was observed that even with Option Strict ON, we can create a new excel application object with the NEW keyword. It was also checked with GetType that in both cases that is, using CreateObject and NEW, the type of object being created was: System._ComObject.So my question is if the type of object being created remains remains the same, why is that Option Strict disallows CreateObject but allows the creation of the excel application object using NEW?
To study it further, I extended the above code to the following:
Option Strict On
Imports System
Imports Microsoft.Office.Interop
Module Program
Dim oxl As Excel.Application
Dim owb As Excel.Workbook
Dim osheet As Excel.Worksheet
Sub Main()
oxl = New Excel.Application
'oxl = CreateObject("Excel.Application")
Console.WriteLine(oxl.GetType)
oxl.Visible = True
owb = oxl.Workbooks.Add()
osheet = owb.Worksheets("Sheet1") ‘Error: Option Strict ON disallows implicit conversions from ‘Object’ to ‘Worksheet’
osheet.Range("A1").Value = 53
Console.WriteLine("Hello World!")
Console.ReadLine()
End Sub
End Module
When we run the code we see that the error Option Strict ON disallows implicit conversions from ‘Object’ to ‘Worksheet’ comes at the line: osheet = owb.Worksheets("Sheet1")
Question:
Why is the error coming? I mean if, owb = oxl.Workbooks.Add()can work (that it returns a workbook which is referred to by owb) then why is osheet = owb.Worksheets("Sheet1") not working because the right hand side returns the “Sheet1” of the workbook which osheet should be able to point to (given that it is of the type Excel.Worksheet)?
Sometimes it just doesn't have the information that something is more specific than an Object. If you don't use the default property and use Item instead, as in owb.Worksheets.Item("Sheet1"), you can hover over the Worksheets part to see that represents the .Sheets, but hovering over the Item part reveals it has no details of the items therein - it says it returns an Object.
You know what it should be, so if you had
Imports XL = Microsoft.Office.Interop.Excel
then you could do
osheet = DirectCast(owb.Worksheets("Sheet1"), XL.Worksheet)
and the types would all work out.
This is what VB statements about COM objects actually do.
Information for Visual Basic Programmers
Visual Basic provides full support for Automation. The following table
lists how Visual Basic statements translate into OLE APIs.
Visual Basic statement OLE APIs
CreateObject (“ProgID”)
CLSIDFromProgID
CoCreateInstance
QueryInterface to get IDispatch interface.
GetObject (“filename”, “ProgID”)
CLSIDFromProgID
CoCreateInstance
QueryInterface for IPersistFile interface.
Load on IPersistFile interface.
QueryInterface to get IDispatch interface.
GetObject (“filename”)
CreateBindCtx creates the bind context for the subsequent functions.
MkParseDisplayName returns a moniker handle for BindMoniker.
BindMoniker returns a pointer to the IDispatch interface.
Release on moniker handle.
Release on context.
GetObject (“ProgID”)
CLSIDFromProgID
GetActiveObject on class ID.
QueryInterface to get IDispatch interface.
Dim x As New interface
Find CLSID for interface.
CoCreateInstance
QueryInterface
A standard COM VTable the first three entries are IUnknown
AddRef, Release (decreases the ref count), and QueryInterface to find what interfaces this object support.
The next four entries are IDispatch
GetIDsOfNames, Invoke , GetTypeInfoCount, GetTypeInfo.
The entries after that are your methods and properties, and all are a indirect function call.
To get the code in memory you use the COM API calls, such as CoCreateInstance
You need to decide to early or late bind. Early binding requires the program to be installed so its type library can be read so it types are compiled into the program. Late binding doesn't care about compile time. There is a conversation Hello object, do you have a function called x. Object replies Yes, it is function 7, Can you please do function 7 object. Early binding function 7 is hard coded. You can only late bind to generic objects. –
So a COM object is 4 x 32 bit. One is the reference count, one is the address if the Virtual Function Table (VTable), 2 are unused. In early binding to call a function 7 the compiler does Address_Of_Vtable + (4 x 7) (being 4 bytes for an address). See IDispatch. N.B. Microsoft.Office.Interop is not used at all in late binding. –
Only the generic object can be used in late binding and cannot be used in early binding. Early binding requires you to tell it the specific object. You are mixing and matching. The compiler is confused, just like you. –
Option Strict Restricts implicit data type conversions to only widening conversions, disallows late binding, and disallows implicit typing that results in an Object type. learn.microsoft.com/en-us/dotnet/visual-basic/… –

How can I downcast an object using only late-binding in VBA?

I am writing a VBA application, and for a specific function, I am using only late-binding, as most of the users of the application won't have the reference installed (and won't use this specific function).
The object I am using behaves like:
class PISDK{
PIServer GetServer(string hostName)
}
The GetServer method returns a PIServer object, but a more specific interface exists, implementing PIServer:
interface IGetPoints2 : PIServer{}
I would like to downcast the PIServer object to a IGetPoints2 object.
Without doing anything, I get a PIServer object:
Dim PiSdk As Object
Dim PiServer As Object
Set PiSdk = CreateObject("PISDK.PISDK")
Set PiServer = PiSdk.GetServer("foo")
Looking at PiServer in the debugger confirms that.
Using a strongly typed variable should work, but I do not want to reference any of the types used here.
How can I downcast this object using late-binding only?
Please read this:
As you are not adding a reference to the PI SDK Type Library, I
believe you cannot use "rtInterpolated" as the second parameter of
the ArcValue method; instead, you can use the corresponding number
(which is 3 for "rtInterpolated" in the RetrievalTypeConstants
enumeration).
VBA with late binding is tricky with optional
parameters, as we cannot omit them when calling a method. Instead,
you need to use either Nothing (in case the optional parameter is
an object) or "" (in case the optional parameter is a string) as
"parameter placeholders" (by the way, the same happens in
VBScript, a scripting language for scripts contained in files with
.vbs extension that run independently from any application).
able to put some functional sample code together, which is more
complete and will hopefully help you.

How to get the class name when running a constructor function in duktape?

I'd like to use a single duktape/C constructor function as dispatcher for these kind of calls. When the dispatcher function is called I need to know for which class this happend to call the appropriate C++ construction function.
I guess the this binding won't help since it represents the (not yet fully initialized) JS object we are creating here.
Another option would be the current function, but from the docs I can't see how to get the class name from that. What else could I use?
Could you elaborate what you mean by "class name"? Do you mean the .name property of the Ecmascript function object which is used as a the 'new' target?
If so, you can use duk_is_constructor_call() to see if the current call is a constructor call, then use duk_push_current_function() to get access to the Ecmascript constructor function object, and then read its properties using the usual property API calls. For example, if by "class name" you mean .name of the function object, you'd just read its "name" property using duk_get_prop_string().

Does the Windows shell support multiple shell property handlers?

I was just trying out the Windows app sample for the Recipe Property Handler which is available here and I modified it to be used on .doc files instead of .recipe files:
const WCHAR c_szRecipeFileExtension[] = L".doc";
But, this seemed to overwrite the previous Office handler's properties with itself, which begs the question, does the Windows shell support multiple shell property handlers, or can you only use one at a time for a given file type? If its possible, what am I missing from the code or logic in the sample?
I couldn't find a concrete answer on MSDN for this question.
No.
But there is a variant you can use (I dont like it but I dont see any additional variant). Save previous Property handler CLSID when you register your own. And when shell request the property that you cannot process - just create instance of previous handler and pass request to them.
CoCreateInstance(SavedCLSID, nil, CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER, IPropertyStore, PS)
PS.QueryInterface(IInitializeWithStream, IWS)
IWS.Initialize(Stream, Mode)
PS.GetValue(AUnknownKey)

Add Permission to Object

I have a System called 'A' that holds the objects of itself into data structure by name. Basically System 'A' has a function called getObject(obj_name). This function creates an object with the given name, obj_name, if it's not already exists and then return it otherwise it just return the object.
Now, Program 1 uses System 'A' and creates an object called "Program1_Object" using above function (getObject)
Program 2 calls getObject with "Program1_Object" as its argument.
The problem in here is getObject returns Program 1 object to Program 2. I want to add permission to that object that if object is not meant for the caller program returns an error or create a new one for the caller program.
What is a trick behind it?
Thanks
A could be a simple wrapper for a hash table. Permissions could be implemented with an additional parameter to getObject stating the permissions of the calling code.

Resources