|
An COM writed with ATL has a parameter which type is BSTRS.
such as
STDMETHODIMP CPNRTool::GetPNRInf(BSTR PNRNo, BSTR* PNRInf, LONG* Flag)
An application writed by VB call this COM such as
Dim sPNRNO As String
Dim sPNRNO As String
Dim lLog As Long
Dim DCSTool As DCSTool.CPNRTool
Set DCSTool = New DCSTool.CPNRTool
Call DCSTool.GetPNRInf(sPNRNO, sPNRInf, lLog)
Set DCSTool = Nothing
After finish call, I am doubt whether I need to release the memory of param"PNRInf" and "Flag"
and how to release?
Will this situation make memory leaks?
TIA
Hello everyone
|
|
|
|
|
|
The situations here and there are not identical. VB supports perfectly the [out,retval] parameter. He also supports the [in,out] parameter. But I'm afraid that VB does not support the [out]-only parameter.
[idl] HRESULT SomeTestMethod([out] BSTR *pVal);
Dim s As String
s = "SomeText"
...
Call obj.SomeTestMethod(s)
' Here s will contain the new value. But old value will be freed or not?
The like example from C++:
BSTR s = SysAllocString(L"SomeText");
...
obj->SomeTestMethod( &s );
' Here s will contain the new value. But old value will never be freed.
With best wishes,
Vita
|
|
|
|
|
True enough.
There is a catch when non-VB clients call, of course, in that the BSTR* passed in must be either set to NULL or a valid BSTR, and not contain a random value, or the called object faults.
This happens, for instance, when uninitialised BSTR values are used from a C++ client.
The moral is for lower-level programmers to always init data to a known value.
Steve S
|
|
|
|
|
Hello Vita,
I wrote a simple VC++ ATL COM Object that implements SomeTestMethod() as described above (it takes an [out] parameter of type BSTR*). I ran a VB test client that performs the exact same calls as described :
Dim s As String
s = "SomeText"
...
Call obj.SomeTestMethod(s)
Listed below is my SomeTestMethod() implementation :
STDMETHODIMP CTest2::SomeTestMethod(BSTR *pbstr)
{
// TODO: Add your implementation code here
if (*pbstr)
{
::SysFreeString(*pbstr);
*pbstr = NULL;
}
*pbstr = _bstr_t(TEXT("New BSTR.")).copy();
return S_OK;
}
I noted that when control gets into SomeTestMethod(), pbstr points to a BSTR but that BSTR is actually NULL. Hence the contents of the "if" statement :
if (*pbstr)
{
::SysFreeString(*pbstr);
*pbstr = NULL;
}
did not get executed. This is because "*pbstr" is actually NULL. This makes me suspect strongly that the VB runtime will actually free the BSTR in "s" before passing it by reference to SomeTestMethod().
The rest of the function :
*pbstr = _bstr_t(TEXT("New BSTR.")).copy();
works as expected.
When I get the VB test client to display "s" (in a MsgBox) after calling SomeTestMethod(), the displayed text is indeed "New BSTR."
Hope the above can be of help.
Best Regards,
Bio.
|
|
|
|
|
Hi guys!
I'm trying to insert a DropdownButton in my Outlook plugin...a msoControlButtonDropdown button, but I just don't know how!
Here is (a piece of)my code:
CComVariant vToolBarType2(msoControlDropdown);
CComPtr < Office::CommandBarControl> spNewBar;
spNewBar = spBarControls->Add(vToolBarType,vEmpty,vEmpty,vEmpty,vShow);
ATLASSERT(spNewBar2);
The problem is that the Add Method only accepts as the first parameter msoControlButton, msoControlEdit, msoControlDropdown, msoControlComboBox, or msoControlPopup; and I want to use msoControlButtonDropdown.
Any ideas how should I do this, or how should I go around it?
As you see, the code is written in ATL / C++, but even if you have a VB sample, I guess it should do the trick.
Thanks a lot,
Doru K.
|
|
|
|
|
I am searching for a way to create a DVTARGETDEVICE structure with the information from the currently selected printer in a MFC application. Is there a way to do this automatically (e.g. if I have a CDC object)?
If this is not possible, how do I create the DVTARGETDEVICE structure if I have the DEVNAMES and DEVMODE structures.
Unfortunatly the MSDN docu is not very good here and I have not found any information about that.
By the way, why do I have to use a DVTARGETDEVICE, an Information context AND a Device context in so many COM methods (like IViewObject::Draw)? The 2 HDCs I have should be enough!?
Thanks in advance for your help.
|
|
|
|
|
OMG, I like those MS guys. After wasting 1 day, I finally found out how MS internally do it!
There is an internal function in OLEMISC.CPP called _AfxOleCreateTargetDevice. It takes the DEVAMES and DEVMODE structures and returns a the DVTARGETDEVICE structure:
Here is the code of this function:
<br />
DVTARGETDEVICE* AFXAPI _AfxOleCreateTargetDevice(LPDEVNAMES pDN, LPDEVMODE pDM)<br />
{<br />
USES_CONVERSION;<br />
<br />
DVTARGETDEVICE* ptd = NULL;<br />
DWORD dwDevNamesSize, dwDevModeSize, dwPtdSize;<br />
<br />
LPCTSTR lpszDriverName = DEVNAMEPART(pDN, wDriverOffset);<br />
LPCTSTR lpszDeviceName = DEVNAMEPART(pDN, wDeviceOffset);<br />
LPCTSTR lpszPortName = DEVNAMEPART(pDN, wOutputOffset);<br />
<br />
LPCOLESTR lpszDriverNameOle = T2COLE(lpszDriverName);<br />
LPCOLESTR lpszDeviceNameOle = T2COLE(lpszDeviceName);<br />
LPCOLESTR lpszPortNameOle = T2COLE(lpszPortName);<br />
int nDriverNameSize = (lpszDriverNameOle == NULL) ? 0 : (ocslen(lpszDriverNameOle)+1)*sizeof(OLECHAR);<br />
int nDeviceNameSize = (lpszDeviceNameOle == NULL) ? 0 : (ocslen(lpszDeviceNameOle)+1)*sizeof(OLECHAR);<br />
int nPortNameSize = (lpszPortNameOle == NULL) ? 0 : (ocslen(lpszPortNameOle)+1)*sizeof(OLECHAR);<br />
<br />
LPDEVMODEOLE lpDevModeOle = DEVMODET2OLE(pDM);<br />
<br />
dwDevNamesSize = nDriverNameSize + nDeviceNameSize + nPortNameSize;<br />
dwDevModeSize = (DWORD)(lpDevModeOle->dmSize + lpDevModeOle->dmDriverExtra);<br />
<br />
dwPtdSize = sizeof(DVTARGETDEVICE) + dwDevNamesSize + dwDevModeSize;<br />
<br />
if ((ptd = (DVTARGETDEVICE*)CoTaskMemAlloc(dwPtdSize)) != NULL)<br />
{<br />
ptd->tdSize = (UINT)dwPtdSize;<br />
<br />
ptd->tdDriverNameOffset = sizeof(DVTARGETDEVICE);<br />
ocscpy((LPOLESTR)((BYTE*)ptd + ptd->tdDriverNameOffset), lpszDriverNameOle);<br />
ptd->tdDeviceNameOffset = (WORD)(ptd->tdDriverNameOffset + nDriverNameSize);<br />
ocscpy((LPOLESTR)((BYTE*)ptd + ptd->tdDeviceNameOffset), lpszDeviceNameOle);<br />
ptd->tdPortNameOffset = (WORD)(ptd->tdDeviceNameOffset + nDeviceNameSize);<br />
ocscpy((LPOLESTR)((BYTE*)ptd + ptd->tdPortNameOffset), lpszPortNameOle);<br />
ptd->tdExtDevmodeOffset = (WORD)(ptd->tdPortNameOffset + nPortNameSize);<br />
memcpy((BYTE*)ptd + ptd->tdExtDevmodeOffset, lpDevModeOle,<br />
sizeof(DEVMODEOLE)+lpDevModeOle->dmDriverExtra);<br />
}<br />
return ptd;<br />
}<br />
And here is a sample from me and the MS file OLEDOCCL.cpp how to use, incl. getting the current application printer:
<br />
PRINTDLG pd;<br />
pd.lStructSize=(DWORD)sizeof(PRINTDLG);<br />
AfxGetApp()->GetPrinterDeviceDefaults(&pd);<br />
<br />
DVTARGETDEVICE* pTargetDevice = NULL;<br />
LPDEVNAMES lpDevNames = NULL;<br />
LPDEVMODE lpDevMode = NULL;<br />
<br />
lpDevNames = (LPDEVNAMES) GlobalLock(pd.hDevNames);<br />
if (lpDevNames != NULL)<br />
{<br />
lpDevMode = (LPDEVMODE) GlobalLock(pd.hDevMode);<br />
if (lpDevMode != NULL)<br />
{<br />
pTargetDevice = _AfxOleCreateTargetDevice(lpDevNames, lpDevMode);<br />
if (pTargetDevice != NULL)<br />
{<br />
CoTaskMemFree(pTargetDevice);<br />
} <br />
GlobalUnlock(pd.hDevMode);<br />
}<br />
GlobalUnlock(pd.hDevNames);<br />
}<br />
Thx MS for the "good" documentation!
|
|
|
|
|
I have wrote a SDI windows application(MyApp.exe) with an automation IDispatch interface for remote control. My problem is that I want to connect my client program to a running instance of MyApp.exe, rather than start up a new instance.
I succeeded doing this by changing the orignal initialisation
pIMyApp = new IMyApp;<br />
pIMyApp->CreateDispatch( "MyApp.Document" );
to the lines
pIMyApp = new IMyApp;<br />
CLSID clsid;<br />
if ( CLSIDFromProgID( OLESTR( "MyApp.Document" ), &clsid)==NOERROR)<br />
{<br />
IUnknown *pUnknown=NULL;<br />
HRESULT hr=GetActiveObject(clsid,NULL,&pUnknown);<br />
if ( SUCCEEDED(hr) )<br />
{<br />
IDispatch *pIDispatch=NULL;<br />
hr=pUnknown->QueryInterface(IID_IDispatch,(void **)&pIDispatch);<br />
if (SUCCEEDED(hr) )<br />
{<br />
pIMyApp->AttachDispatch(pIDispatch,FALSE );<br />
bInitialised = true;<br />
}<br />
pUnknown->Release();<br />
}<br />
}
which attaaches pIMyApp interface pointer to the running instance of MyApp.exe (the IMyApp is registered in the Running-Object-Table) on my own computer.
I want be able to do the same on a remote computer. Is it possible to get apply GetActiveObject() to a remote instsance? The MS Knowledge base has a over complicated example
of achieving this for a program called ROTMONK.EXE which seems over complicated to me.
As I missing something? Does anyone know of a straightforward way of achieving a connection to a runing instance on a remote computer? Or more importantly, does anyone have any suggestions of a better way of achieving my aim?
|
|
|
|
|
GetActiveObject cannot be applicable by ROTMONK.EXE's manner because the moniker by which the object is registered in ROT is really the non-bindable moniker.
With best wishes,
Vita
|
|
|
|
|
Thanks for the comment Vita. I wasn't completely sure without trying it whether I would be able to use BindToObject() to attach to the process but I won't even try now.
Anyway, I have reflectioning further on this, and guess that what I am trying to do is not strictly necessary and can hopefully achieve what I need using a slightly different approach. If I use the
pIMyApp->CreateDispatch( "InterfaceName" ) function to get the interfaces that I need then that should suffice, as long as the required interfaces all connect to just one singleton instance of my exe automation server. As per normal apps, the important thing is the data, which must
be common so that the interfaces can access it.
I am, of course, greatful for any help that I might receive.
|
|
|
|
|
I have a question about COM, MFC and Thread Neutral Apartment that I hope
someone can answer or at least give some hint where I can find the answer myself.
The current situation is that I have a couple of old COM components written in
MFC, all STA apartment, IDispatch only and with chatty (property based)
interfaces. The MFC components are currently installed in COM+ and are
frequently accessed by (ASP).NET applications. To reduce the number of
context and thread switched we are thinking about to change the threading
modell of most of the components from STA to TNA. The components will still
be accessed in a "STA" way, i.e. they will have only one client at the time.
I have done some minor tests and it seems to work, but ...
So my questions is: Based on the information above is it at all possible to
change the (registry) settings and change the threading model, and if so
will there be any (performance/functionality) issues to consider ?
|
|
|
|
|
how do i get the right click menu for a custom toolbar i created .
ie when i right click on it how do i get a menu and add items to it Any one please help me .
Thanks in advance
Srikar Y
NITK Surathkal
|
|
|
|
|
Since this is a cutom toolbar, you can handle RButtonDown notification, and then create a CMenu object, and use LoadMenu and TrackPopupMenu methods to display it.
"A robust program is resistant to errors -- it either works correctly, or it does not work at all; whereas a fault tolerant program must actually recover from errors."
|
|
|
|
|
Hey i'm making a COM dll using the ATL appwizard and... the COM dll is set support MFC...
The COM dll is used by a VB application... NOw i want to make an installation or setup so that my application is run in other computers without Visual C++...
How do i do these? What DLL's would i have to include in my installation... how about MFC dll's?
I tried installing the applicationsin other computers but there's an error saying that some DLL failed to register... I'm thinking i did not include other dll's that is needed by the application itself or the DLL that was included already.. what is it? i didn't use other third party libraries so i'm sure maybe its just the MFC dlls.. what is it?
"its all right, the gun isn't loaded" - hey
|
|
|
|
|
What you can do is, link the MFC Dll statically to your COM dll. Then you only need to distribute your COM dll, and dont forget to register your dll before using it from VB.
Registration can be done using 'Regsvr32' command. OR if you are using some installation pgms, then there will be some APIs for doing the same.
"A robust program is resistant to errors -- it either works correctly, or it does not work at all; whereas a fault tolerant program must actually recover from errors."
|
|
|
|
|
I added a toolbar button to IE, which is connected to a BHO object.
I implemented IOleCommandTarget and IObjectWithSite interfaces. the problem is once i click on the toolbar it is invokes IOleCommandTarget ::Exec, and disables the toolbar button. How do u stop this behaviour.. can any body help me
|
|
|
|
|
Is the following safe?
{<br />
map<<CComBSTR, CComBSTR>> mp;<br />
<br />
{<br />
CComBSTR& bstrNew = mp[L"1"];<br />
<br />
bstrNew = "Hello";<br />
}<br />
<br />
wprintf(mp[L"1"]);<br />
}
Will bstrNew get destroyed, thus invalidating the "Hello" string?
Jeremy Pullicino
C++ Developer
Homepage
|
|
|
|
|
I'm considering building an ActiveX control.
I would like to know which consideration I should take into account.
The application which is going to use the activeX control is a multi-threaded, it contains many features and might be big.
Does ActiveX slow down the system? are there problem with threaded?
What are the advantages and disadvantages of ActiveX? Should I write a java applet, or an MFC dll instead?
Thanks Dafna.
|
|
|
|
|
If you are not confident, that your control is thread-safe, always put it in an STA( Single Threaded Apartment ), so that only one thread can access it, and select the threading model as Apartment.
ActiveX unlike, VBX controls has got independent existence, irrespective of the language used. They are actually built on top of COM standards, and has got several adavntages as well, refer MSDN for more details. Disadvantages can be there unless otherwise not properly implemented.
Java Applet / MFC DLL ?? - Depends on the scenario.
"A robust program is resistant to errors -- it either works correctly, or it does not work at all; whereas a fault tolerant program must actually recover from errors."
|
|
|
|
|
consider the following code:
<br />
STDMETHODIMP CmyComObject::get_Address(BSTR *pVal)<br />
{<br />
*pVal = m_sAddress.copy();<br />
<br />
return S_OK;<br />
}<br />
i'm using this Com object in a Visual Basic Program... Now when i keep on calling this function many times, does my program goes to a memory leak?, or does visual basic frees the copies automatically? or should i manually free the strings first before making another copy?
i also got this in a .net examples on bstr::copy()..
"its all right the gun isn't loaded" - hey
|
|
|
|
|
Visual Basic is not going to do that for you, Its your responsibility to free it.
"A robust program is resistant to errors -- it either works correctly, or it does not work at all; whereas a fault tolerant program must actually recover from errors."
|
|
|
|
|
Nope, guess again. VB is calling this code, and it will manage the returned BSTR, disposing of it as appropriate. If it was VC++, then the caller would manage the returned string. VB, as caller, is doing that, and the fragment is fine.
You need to return a copy of the string because the ORIGINAL still belongs to the interface implementation (or object).
Steve S
|
|
|
|
|
|
You mean that i need not to release and do nothing,
This situation will not go to a memory leak?
"You need to return a copy of the string because the ORIGINAL still belongs to the interface implementation (or object)."
What does this mean?
Hello everyone
|
|
|
|
|