|
"iostream" object is C++ object, not accessible directly from scripts and non-C++ clients and unallowed in COM accordingly.
With best wishes,
Vita
|
|
|
|
|
Thanks. There is one more doubt please clear this also.
If i want to return any variable length string from COM then i can allocate memory in COM and return it to exe (return BSTR*). Finall exe which's using the COM will free the memory. Is this OK? How to make same parameter as input/output in COM function?
How to return more than one string through COM function. suppose if i have function
int func(BSTR inputstring, BSTR* outstring1, BSTR* outstring 2);
Here i want to return 2 strings from this function.
COM dont give the option to pass output argument when we call the function
Manoj Kumar Chauhan
|
|
|
|
|
I implement one function in COM which allocate some memory to array and return this.
int AllocateData(int length, BSTR* OutArray)
{
// there is some data in a ansi array, i return this data from this COM function
wchar_t* wstr = (wchar_t*)calloc(sizeof(WCHAR),length+1);
MultiByteToWideChar(CP_ACP, 0, ansiarray, length, wstr, length) ; free(ansiarray);
*OutArray = (BSTR)wstr;
}
When i use this dll i call this function like
BSTR st;
st = cominterface->AllocateData(500);
When this function is called i get some error for memory leak. Please suggest how to fix it.
Manoj Kumar Chauhan
|
|
|
|
|
MKUser wrote: COM dont give the option to pass output argument when we call the function
That's not true (see the [OUT] IDL attribute).
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
Thanks. As per your comments i have solved the error when use [out] in idl file. But if i use [out,retval] then i get error.
I create a sample. Please check the below code.
main()
{
BSTR ab;
ab = allocmem();//i get run time memory error when return from this function
}
_bstr_t allocmem()
{
BSTR x;
allocmem2(&x);
return _bstr_t(x, false);
}
void allocmem2(BSTR *x)
{
char ansi[27];
memset(ansi,0,27);
for(int i = 0; i < 26; i++)
ansi[i] = 48 + i + 1;
wchar_t* wstr = (wchar_t*)calloc(sizeof(WCHAR),26);
MultiByteToWideChar(CP_ACP, 0, ansi, 26, wstr, 26) ;
*x = (BSTR)wstr;
}
Please suggest how to solve this error.
Manoj Kumar Chauhan
|
|
|
|
|
BSTR are strange beasts, you need to use SysAllocString [^](or similar) to allocate a new BSTR object.
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
Ok Let me explain my problem in detail.
In COM i create one function which takes one input and another output argument
idl file contains
HRESULT functionname([in] int length,[out,retval] BSTR* OutArray)
In function definition in COM class
HRESULT functionname(int length,BSTR* OutArray)
{
WSTR warray;
suppose warray contains some string and i want to return that string so i'll write
*OutArray = (BSTR) warray;
or if i try with following code then i think it's not correct
*OutArray = SysAllocString(wstr);
}
i use this dll and call it like
BSTR str;
str = cominterface->functionname(pass input length here);
When i build exe it generate tlh and tli files.
The tli file contains following code for that function
inline _bstr_t IExportComDll::functionname( int length ) {
BSTR _result = 0;
HRESULT _hr = raw_functionname(length, &result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _bstr_t(_result, false);
}
Now please tell me where i can change the code. Where to use SysAllocString. I cant change the code inside tli file. This function returns a string. So ATL write its wrapper code in tli file. When i call this function in some exe,After returning from wrapper code of tli file i get memory error because it try to free BSTR string.
Manoj Kumar Chauhan
|
|
|
|
|
Why do you need to pass the length?
For instance the following should work fine:
HRESULT functionname(BSTR * OutArray)
{
*OutArray = SysAllocString( L"Foo");
}
in the client application you may do
BSTR str;
str = cominterface->functionname();
You should also remember to call SysFreeString(str); there.
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
I'm doing following
HRESULT functionname(BSTR * OutArray)
{
// suppose there is some ansi array which contains some data
// length is int type which keeps size of this ansi array
wchar_t* wstr = (wchar_t*)calloc(sizeof(WCHAR),length+1);
MultiByteToWideChar(CP_ACP, 0, ansiarray, length, wstr, length) ;
free(ansiarray);
ansiarray= NULL;
*OutArray = SysAllocString( wstr);//(BSTR)wstr;
memset(wstr,65,sizeof(WCHAR) * length+1);
free(wstr);
wstr = NULL;
}
When i use this dll
BSTR st;
st = functionname();
After this statement st contains some garbage data.
While when i debug the code in tli file, it returns valid data
inline _bstr_t IExportComDll::functionname( )
{
BSTR _result = 0;
HRESULT _hr = raw_functionname(&_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _bstr_t(_result, false);
//here _result contains valid data which is returned by COM function
//HRESULT functionname(BSTR * OutArray)
}
Now please tell me where i'm wrong. Please correct my mistake
Manoj Kumar Chauhan
|
|
|
|
|
MKUser wrote: inline _bstr_t IExportComDll::functionname( )
The above function returns a _bstr_t instance. Possibly it cannot assigned as it stands to as BSTR variable, hence you need either to
define st as _bstr_t , for instance
_bstr_t st;
st = YourCOMInterface->functionname();
or
use the Detach method of _bstr_t (see [^]), for instance
BSTR st;
st = (YourCOMInterface->functionname()).Detach();
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
Thanks
it's working now
Manoj Kumar Chauhan
|
|
|
|
|
Imported "cominterface->functionname" returns C++ class "_bstr_t", which has a destructor and misleading "operator wchar_t*".
Valid variant is:
str = cominterface->functionname(pass input length here).copy();
With best wishes,
Vita
|
|
|
|
|
Thanks it's also working
Manoj Kumar Chauhan
|
|
|
|
|
If i want to return any variable length string from COM then i can allocate memory in COM and return it to exe (return BSTR*). Finall exe which's using the COM will free the memory. Is this OK?
Yes.
String Manipulation Functions Descriptions
------------------------------------------
SysAllocString Creates and initializes a string.
SysAllocStringByteLen Creates a zero-terminated string of a specified length (32-bit only).
SysAllocStringLen Creates a string of a specified length.
SysFreeString Frees a previously created string.
SysReAllocString Changes the size and value of a string.
SysReAllocStringLen Changes the size of an existing string.
SysStringByteLen Returns the length of a string in bytes (32-bit only).
SysStringLen Returns the length of a string.
There are some C++ classes working with BSTR: CComBSTR, _bstr_t.
How to make same parameter as input/output in COM function?
You can specify [in] for input parameter and [out] for output. I have shown this recently.
How to return more than one string through COM function. suppose if i have function
int func(BSTR inputstring, BSTR* outstring1, BSTR* outstring 2);
Here i want to return 2 strings from this function.
Simple answer is:
int func([in] BSTR inputstring, [out] BSTR* outstring1, [out] BSTR* outstring 2)
But this code will not be working with some scripts, because the basic data for script is VARIANT and not all IDispatch handler can process these data. Moreover, for example, Jscript cannot receive any [out] data at all, but only with [out, retval].
With best wishes,
Vita
|
|
|
|
|
Vi2 wrote: "iostream" object is C++ object, not accessible directly from scripts
True.
Vi2 wrote: and unallowed in COM accordingly
False. It's not allowed in COM automation only.
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
Automation clients, such as scripts, deals only with BSTR , hence you need to use BSTR s if your COM server needs to support them.
On the other hand, clients such as C++ applications (or even VB6 ones) may use server methods accepting char * .
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
I would like to add an IHTMLElement dynamically to the HTML that contain an "A" ActiveX control.
That I want to add is another "B" ActiveX control.
So.. I programmed in "A" activex source code as below.
I created new element.
/* I deleted bstr, SysFreeString, VARIANT etc.. to understand easily */
IHTMLElement* pObjectElement=NULL;
m_pDoc2->createElement("<object>", &pObjectElement);
pObjectElement->setAttribute("classid", "clsid:AF0DDB60-76F8-4ADC-BF58-563EB7DF2B9D", 0); // "B" ActiveX control's Clsid
pObjectElement->setAttribute("width", "600");
pObjectElement->setAttribute("height", "400");
and.. attached it to the bodyElement.
m_pDoc2->get_body(&pElement);
pElement->QueryInterface(IID_IHTMLBodyElement, (LPVOID*)&pBody);
pBody->QueryInterface (IID_IHTMLDOMNode, (LPVOID*)&pParent);
pObjectElement->QueryInterface (IID_IHTMLDOMNode, (LPVOID*)&pChild);
pParent->appendChild (pChild, NULL);
It works well.
And.. I created another new element "param" to send "MyValue" to the "B" ActiveX control.
/* I deleted bstr, SysFreeString, VARIANT etc.. to understand easily */
IHTMLElement* pParamElement=NULL;
m_pDoc2->createElement("<param>", &pParamElement);
pParamElement->setAttribute("name", "src");
pParamElement->setAttribute("value", "MyValue");
and... attached it to the object element.
/* I inserted this code before object element is appended to the body element. like this..
* pChild->appendChild (pParam, NULL);
* pParent->appendChild (pChild, NULL);
*/
pParamElement->QueryInterface (IID_IHTMLDOMNode, (LPVOID*)&pParam);
pChild->appendChild (pParam, NULL);
But It doesn't work.
"B" ActiveX control couldn't receive "MyValue".
There are any problems in "B" ActiveX control. It works well in common situation.
so.. I thought it failed to append <param> to <object> element.
so, I appended a code to confirm whether param element is contained or not.
Surprisingly, <param> could find in it.
...I really really... don't know how I can solve this problem.
If anybody knows it, please answer me.
|
|
|
|
|
intresting . how about using setinnerhtml function .
|
|
|
|
|
hi,
i want to define an enum type variable on the Interface ,
so i have defined an enum within interface and then take a property from this enum,
but have encountered with a compile time error !?
what is my mistake and what is its solution?
interface IXFSReceipt : IDispatch
{
enum RPtrResolution
{
RPTR_RESOLUTION_LOW,
RPTR_RESOLUTION_MEDIUM,
RPTR_RESOLUTION_HIGH,
RPTR_RESOLUTION_VERYHIGH
};
HRESULT Resolution([out, retval] RPtrResolution* pVal);<<<<<<<< ERROR1
HRESULT Resolution([in] RPtrResolution newVal);
};
ERROR1 : error MIDL2025 : syntax error : expecting a type specification
|
|
|
|
|
Don't be afraid to search through the .IDL files that come with the compiler or SDK. On my system I searched all the .IDL files in "C:\PROGRAM FILES\MICROSOFT SDK\INCLUDE" for the word enum . Here's the first example:
typedef enum tagSCRIPTSTATE {
SCRIPTSTATE_UNINITIALIZED = 0,
SCRIPTSTATE_INITIALIZED = 5,
SCRIPTSTATE_STARTED = 1,
SCRIPTSTATE_CONNECTED = 2,
SCRIPTSTATE_DISCONNECTED = 3,
SCRIPTSTATE_CLOSED = 4,
} SCRIPTSTATE ;
[
object,
uuid(DB01A1E3-A42B-11cf-8F20-00805F2CD064),
pointer_default(unique)
]
interface IActiveScriptSite : IUnknown
{
HRESULT GetLCID(
[out] LCID *plcid
);
HRESULT GetItemInfo(
[in] LPCOLESTR pstrName,
[in] DWORD dwReturnMask,
[out] IUnknown **ppiunkItem,
[out] ITypeInfo **ppti
);
HRESULT GetDocVersionString(
[out] BSTR *pbstrVersion
);
HRESULT OnScriptTerminate(
[in] const VARIANT *pvarResult,
[in] const EXCEPINFO *pexcepinfo
);
HRESULT OnStateChange(
[in] SCRIPTSTATE ssScriptState
);
HRESULT OnScriptError(
[in] IActiveScriptError *pscripterror
);
HRESULT OnEnterScript(void);
HRESULT OnLeaveScript(void);
}
Steve
|
|
|
|
|
You should use the full name for enum, i.e. "enum RPtrResolution", because of C nature of MIDL compiler. For example,
HRESULT Resolution([out, retval] enum RPtrResolution* pVal);
HRESULT Resolution([in] enum RPtrResolution newVal);
OR you should use a "typedef" statement, suggested by Stephen Hewitt.
typedef enum RPtrResolution
{
...
} RPtrResolution;
With best wishes,
Vita
|
|
|
|
|
Hey!
I have some trouble when trying to pass an array of data through an event from an ActiveX class.
My function looks like this:
void MycFunction()
{
SAFEARRAY * m_psaVal;
unsigned char HUGEP *m_pVal;
m_psaVal = SafeArrayCreateVector(VT_UI1, 0, 4096);
HRESULT hr = SafeArrayAccessData(m_psaVal, (void HUGEP**) &m_pVal);
for (int i = 0; i < (m_psaVal->rgsabound)->cElements; i++)
{
m_pVal[i] = static_cast<unsigned char="">(0);
}
SafeArrayUnaccessData(m_psaVal);
m_pVal = 0;
CComVariant Values(m_psaVal);
FireOnNewBuffer(Values);
}</unsigned>
And:
void FireOnNewBuffer(VARIANT Values)
{
FireEvent(eventidOnNewBuffer,EVENT_PARAM(VTS_VARIANT), Values);
}
However, when generating the event my application crashes because of an NullReferenceException.
I have no idea what I am doing wrong, all my other events (not passing arrays) work fine. Can anyone help me on this one?
|
|
|
|
|
CComVariant Values(m_psaVal) is only visible in the function. Create with new
Greetings from Germany
|
|
|
|
|
Okay, so I changed to:
CComVariant Values = new CComVariant(m_psaVal);
But I still get the same error.
It sounded like the solution though.
|
|
|
|
|
Hello Hampus@foi,
I see 2 problems in your code :
1. The 2nd parameter to FireEvent() function is EVENT_PARAM(VTS_VARIANT). This means that the 3rd parameter should be a pointer to "Values".
As a further suggestion, make the "Values" parameter to FireOnNewBuffer() a VARIANT reference (i.e. VARIANT&) instead of a straight VARIANT type. Using a reference saves space and improves performance. Using a VARIANT type would entail copying of the original "Values" from MycFunction() to the stack of FireOnNewBuffer().
Hence a better definition for FireOnNewBuffer() is as follows :
void FireOnNewBuffer(const VARIANT FAR& Values)
{
FireEvent(eventidOnNewBuffer,EVENT_PARAM(VTS_VARIANT), &Values);
}
2. The use of CComVariant for a SAFEARRAY is not appropriate :
CComVariant Values(m_psaVal);
This is because there are no CComVariant constructors that take a SAFEARRAY*.
Instead, I suggest using a VARIANT type :
//CComVariant Values(m_psaVal); // <-- comment out.
VARIANT Values;
VariantInit(&Values);
VariantClear(&Values);
V_VT(&Values) = VT_ARRAY | VT_UI1;
V_ARRAY(&Values) = m_psaVal;
FireOnNewBuffer(Values);
Hope the above helps.
- Bio.
|
|
|
|
|