Is passing NULL for COM interface arguments valid? - com

If I have a COM interface method expecting BSTR and SAFEARRAY parameters, but these are optional, what is the correct way to implement this? Can I pass NULL or do I need to pass empty strings and zero-length arrays? Or would I be better passing VARIANTs which can be VT_EMPTY or VT_BSTR / VT_ARRAY?
e.g.
Login([in]BSTR Name, [in]BSTR Password /*optional*/);
SendEmail([in]SAFEARRAY *To, [in]SAFEARRAY *Cc /*optional*/);
In these examples, should Password be passed as NULL or ""? And should Cc be passed as NULL, or do I need to create a 0-length SAFEARRAY, or pass a VARIANT of type VT_EMPTY... which are valid/sensible options?

Well, those sort of arguments really aren't quite right--the MIDL compiler should throw a warning or even an error if you try to make anything other than a VARIANT to be "optional".
The correct way is to define default values ("defaultvalue"). For BSTRs you want to make the default value to be L"" and not 0 (NULL). If you make the default value for BSTRs to be 0, you will run into problems down the road--I think in some .NET interop.
For the SAFEARRAY it should be safe to make the "defaultvalue" to be NULL.
Of course, this advice is from the point of designing how the interface ought to be. You may be in the situation where someone has already designed and implemented the interface. In that case, you're at the mercy of their implementation. For the BSTR arguments, I would try passing in empty strings (L"") and for the SAFEARRAY I would try passing in NULL.
If you are going to define it as "optional", make it a variant. And in that case, the correct argument is VT_EMPTY.

Related

Should I enforce out-parameters being non-NULL?

Example method in IDL:
HRESULT _stdcall a_method( [in] long value, [out] BSTR *comment );
My function logic is that for some values, no comment is necessary. Should I throw an exception if this function is called with comment == NULL by a client? Or is it OK to be permissive and allow this case?
(I'm developing my object in C++).
My rationale for trying to be strict with parameter checking is that I'm concerned about memory leaks, and about having the client make calls that are correct according to the COM spec but my object not accepting the call.
The semantics of [out] parameters are very explicit about this.
A method that gets an [out] parameter should never - ever - look at the parameter's value until it puts something on it. It is uninitialized memory. Garbage. In fact, if your method is called via a marshalled call (inter-apartment or inter-process), garbage is exactly what you get: whatever your caller might have put there when it called your method, was discarded and ignored by the proxy/stub; you never get it.
If the client/caller puts something on the parameter before making a call to your method, it is definitely a memory leak (given that it's an allocated object like a BSTR, of course), but it's the caller's fault. It is never the responsibility of a called method to deal with it. The called method can't handle the leak even if it wanted to.
If you want to handle whatever values might be passed in by the caller, you need to use an [in, out] parameter instead of [out].
One last warning: Automation clients (VBA, VBScript, etc.) don't support [out] parameters. Automation will silently handle any [out] parameter as if it was [in, out], which puts you in an awkward position: any value placed in the parameter by the client application will be leaked, and your method can't do anything about it.
If you plan on your object being used by an automation client, don't use [out] parameters. Use [in, out] instead, and make sure to check if the caller put a value on the parameter before the call. The proxy/stub will always marshal values both ways for an [in, out] parameter. If the caller placed a value on the parameter before the call, your method is responsible for releasing that value before writing to the parameter.
Edit: Expanding on the pointer itself being NULL:
You could think about checking for NULL and return E_INVALIDARG if it's NULL, but I wouldn't recommend it.
It is illegal to pass NULL as the pointer value for an [out] parameter. Even if your code handles a NULL value, if the call is marshalled, the marshaller will hit an Access Violation. The marshaller has to access the pointed value on the way back (to store the marshalled output on it) and it will do so without checking for null.
In your specific scenario (the call semantic being that there is nothing to return in a given case), the proper process is for the caller to always provide a pointer to storage, and for the called method to set the value to NULL. Something like this:
// Caller
BSTR comment;
hr = obj->a_method( 42, &comment);
// Callee
HRESULT a_method( value, BSTR *comment )
{
if (...)
{
//... I've decided we don't need to return a comment
*comment = NULL;
}
...
}
If you really want to have the pure null pointer semantic you mentioned, you can; but you have to mark the parameter with the [ptr] attribute. As far as I know, that doesn't work very well with Automation clients, and you have to use a custom marshaller. If you don't anticipate ever using an Automation client, this is clearly an option.

Difference between using GetterUtils and ParamUtils

For instance, when to use
GetterUtil.getBoolean()
and when
ParamUtil.getBoolean()?
Are both same, or is it expected to be used differently according to a parameter, a variable, etc? Can you give some examples for both?
Both are util methods to avoid Null-Pointer Exceptions.
GetterUtil internally returns the default type and does the casting too. So in case where someone has passed a null value, it will return default value of the type.
Example:
Assume you have a String value "true", and you are expecting it will always be of type boolean. So you use GetterUtil.getBoolean("true") which will internally do the casting to boolen and return the value as boolean-true. Incase someone passes rubbish characters like "tr", it will be converted to boolean-false.
As mentioned ParamUtil does the same treatment with request parameters. ParamUtil internally uses the GetterUtil to have the above behaviour. It first retrieves the parameter (which always would be a string) and then passes it to GetterUtil.getType() method and in turn returns the proper type.
GetterUtil and ParmUtil both are different classes.
GetterUtil is to get the default values for basic Java data types.
ParamUtil is to retrive the values(of primitive data types) from the HttpReqeust.
Check the source code here for these two classes here
For GetterUtil
http://docs.liferay.com/portal/6.0/javadocs/src-html/com/liferay/portal/kernel/util/GetterUtil.html
For ParamUtil
http://docs.liferay.com/portal/5.1/javadocs/portal-kernel/com/liferay/portal/kernel/util/ParamUtil.java.html

What's the Matlab equivalent of NULL, when it's calling COM/ActiveX methods?

I maintain a program which can be automated via COM. Generally customers use VBS to do their scripting, but we have a couple of customers who use Matlab's ActiveX support and are having trouble calling COM object methods with a NULL parameter.
They've asked how they do this in Matlab - and I've been scouring Mathworks' COM/ActiveX documentation for a day or so now and can't figure it out.
Their example code might look something like this:
function do_something()
OurAppInstance = actxserver('Foo.Application');
OurAppInstance.Method('Hello', NULL)
end
where NULL is where in another language, we'd write NULL or nil or Nothing, or, of course, pass in an object. The problem is this is optional (and these are implemented as optional parameters in most, but not all, cases) - these methods expect to get NULL quite often.
They tell me they've tried [] (which from my reading seemed the most likely) as well as '', Nothing, 'Nothing', None, Null, and 0. I have no idea how many of those are even valid Matlab keywords - certainly none work in this case.
Can anyone help? What's Matlab's syntax for a null pointer / object for use as a COM method parameter?
Update: Thanks for all the replies so far! Unfortunately, none of the answers seem to work, not even libpointer. The error is the same in all cases:
Error: Type mismatch, argument 2
This parameter in the COM type library is described in RIDL as:
HRESULT _stdcall OurMethod([in] BSTR strParamOne, [in, optional] OurCoClass* oParamTwo, [out, retval] VARIANT_BOOL* bResult);
The coclass in question implements a single interface descending from IDispatch.
I'm answering my own question here, after talking to Matlab tech support: There is no equivalent of Nothing, and Matlab does not support this.
In detail: Matlab does support optional arguments, but does not support passing in variant NULL pointers (actually, to follow exactly how VB's Nothing works, a VT_EMPTY variant, I think) whether as an optional argument or not. There is documentation about some null / pointerish types, a lot of which is mentioned in my question or in various answers, but these don't seem to be useable with their COM support.
I was given a workaround by Matlab support using a COM DLL they created and Excel to create a dummy nothing object that could be passed around in scripts. I haven't managed to get this workaround / hack working, and even if I had unfortunately I probably could not redistribute it. However, if you encounter the same problem this description might give you a starting point at least!
Edit
It is possible this Old New Thing blog post may be related. (I no longer work with access to the problematic source code, or access to Matlab, to refresh my memory or to test.)
Briefly, for IUnknown (or derived) parameters, you need a [unique] attribute for them to legally be NULL. The above declaration required Matlab create or pass in a VT_EMPTY variant, which it couldn't do. Perhaps adding [unique] may have prompted the Matlab engine to pass in a NULL pointer (or variant containing a NULL pointer), instead - assuming it was able to do that, which is guesswork.
This is all speculation since this code and the intricacies of it are several years behind me at this point. However, I hope it helps any future reader.
From the mathworks documentation, you can use the libpointer function:
p = libpointer;
and then p will be a NULL pointer. See that page for more details.
See also: more information about libpointer.
Peter's answer should work, but something you might want to try is NaN, which is what Matlab ususally uses as a NULL value.
In addition to using [] and libpointer (as suggested by Peter), you can also try {}.
The correct answer for something in VB that is expecting a Nothing argument, is to somehow get a COM/ActiveX Variant which has a variant type of VT_EMPTY. (see MSDN docs which reference marshaling behavior for Visual Basic Nothing)
MATLAB may do this with the empty array ([]), but I'm not sure.... so it may not be possible purely in MATLAB. Although someone could easily write a tiny COM library whose purpose is to create a Variant with VT_EMPTY.
But if the argument has the [optional] atttribute, and you want to leave that optional argument blank, you should not do this. See the COM/ActiveX docs on Variants which say under VT_EMPTY:
VT_EMPTY: No value was specified. If an optional argument to an Automation method is left blank, do not pass a VARIANT of type VT_EMPTY. Instead, pass a VARIANT of type VT_ERROR with a value of DISP_E_PARAMNOTFOUND.
Matlab should (but probably does not) provide methods to create these objects (a "nothing" and an "optional blank") so you can interface correctly with COM objects.

ComBSTR assignment

I'm confused about COM string assignments. Which of the following string assignment is correct. Why?
CComBSTR str;
.
.
Obj->str = L"" //Option1
OR should it be
Obj->str = CComBSTR(L"") //Option2
What is the reason
A real BSTR is:
temporarily allocated from the COM heap (via SysAllocString() and family)
a data structure in which the string data is preceded by its length, stored in a 32-bit value.
passed as a pointer to the fifth byte of that data structure, where the string data resides.
See the documentation:
MSDN: BSTR
Most functions which accept a BSTR will not crash when passed a BSTR created the simple assignment. This leads to confusion as people observe what seems to be working code from which they infer that a BSTR can be initialized just like any WCHAR *. That inference is incorrect.
Only real BSTRs can be passed to OLE Automation interfaces.
By using the CComBSTR() constructor, which calls SysAllocString(), your code will create a real BSTR. The CComBSTR() destructor will take care of returning the allocated storage to the system via SysFreeString().
If you pass the CComBSTR() to an API which takes ownership, be sure to call the .Detach() method to ensure the BSTR is not freed. BSTRs are not reference counted (unlike COM objects, which are), and therefore an attempt to free a BSTR more than once will crash.
If you use str = CComBSTR(L"") you use the constructor:
CComBSTR( LPCSTR pSrc );
If you use str = L"" you use the assignment operator:
CComBSTR& operator =(LPCSTR pSrc);
They both would initialize the CComBSTR object correctly.
Personally, I'd prefer option 1, because that doesn't require constructing a new CComBSTR object. (Whether their code does so behind the scenes is a different story, of course.)
Option 1 is preferred because it only does one allocation for the string where as option 2 does 2 (not withstanding the creation of a new temporary object for no particular reason). Unlike the bstr_t type in VC++ the ATL one does not do referenced counted strings so it will copy the entire string across.

How to I pass a checkbox value by reference with CLI?

I have a GUI app written in C++/CLI which has a load of configurable options. I have some overloaded functions which grab values from my data source and I'd like to connect my options to those values.
So here's a couple of data retrievers:
bool GetConfigSingle(long paramToGet, String^% str, char* debug, long debugLength);
bool GetConfigSingle(long paramToGet, bool^% v_value, char* debug, long debugLength);
I was hoping to pass in the checkbox's Checked getter/setter as follows:
result = m_dataSource->GetConfigSingle(CONFIG_OPTION1, this->myOption->Checked, debug, debugLen);
...but for some reason I get an odd compiler error which suggests the Checked value isn't being passed as I'd expect:
1>.\DataInterface.cpp(825) : error C2664: 'bool DataInterface::GetConfigSingle(long,System::String ^%, char*, long)' : cannot convert parameter 2 from 'bool' to 'System::String ^%'
Previously this code passed the checkbox in and modified the values itself, but I'm keen to break the dependency our data collection currently has on windows forms.
So what am I missing here?
[Edit] I've filled out the function definitions as they originally were to avoid confusion - my attempt to reduce the irrelevent information failed.
I'm fairly certain that the CheckBox getter / setter returns a bool.
Figured I'd clarify my comments from above and make it a "real" answer...
When you call Checked, what you're getting back as a return value is a bool that represents the current state of the CheckBox. It is not, however, a reference to the actual data member that holds the CheckBox's state. In fact, a properly encapsulated class shouldn't give access to it. Furthermore, since Checked returns a bool by value, that bool is a temporary object that doesn't necessarily exist by the time GetCongigSingle is called.
This leaves you with several options. Either pass the bools by value, and later set the CheckBox's state, or pass the CheckBox itself by reference and "check" it wherever you want.
The two overload of the method GetConfigSingleFile that you have mentioned both take two arguments whereas you are passing 4 arguments to the method. Are there any default arguments? If yes, can you please reproduce the original method declarations?
Most probably, the 4 argument overload of this method is expecting a String^% as the 2nd argument. This is what the compiler is suggesting anyway. But if we can have a look at the method declarations that could help diagnosing the problem.
This isn't an answer to my question, but worth being aware of - apparently there's a quirk in passing properties by reference.