|
Include a copy of the MFC 7.0 DLL with setup.
Kuphryn
|
|
|
|
|
I am exporting a function with a CString object as its parameter, as show below:
extern "C" DllExport const char* ActivatePlot(CString szPlot);
When I called this function from another DLL or module, the application crashes. From debug/call-stack I found that while returning from the function ActivatePlot() the control is in the destructor of CString object and is trying to free the memory.
When I changed the parameter type to const char* it worked fine.
Can you explain whether we can use CString object in a DllExport functions? If not why?
|
|
|
|
|
You should check MSDN. Go to www.msdn.microsoft.com And type MFC DLL export in the search field. You will find enough information on how to export functions depending on what kind of DLL are you building.
-- Sebastián.
|
|
|
|
|
Hello Kishor,
Usage of CStrings in an exported function is perfectly fine as far as I know. Your function is declared as :
extern "C" DllExport const char* ActivatePlot(CString szPlot);
This means that when your ActivatePlot() is called, MFC creates a temporary CString for szPlot to be used within the context of the ActivatePlot() function.
Now, if this input is another CString as in the following example :
CString cstr("Country road.");
ActivatePlot(cstr);
the temporary CString "szPlot" which is created and gets passed into ActivatePlot() will contain a pointer to the same string that "cstr" points to.
The reference count of the actual string ("Country road.") is incremented and "cstr" and the "szPlot" both share the same string.
It is true that when the ActivatePlot() function exits, the CString destructor is called. This is done to free the temporary CString object "szPlot".
Let's take a look at the actual source codes of the CString destructor :
CString::~CString()
// free any attached data
{
if (GetData() != _afxDataNil)
{
if (InterlockedDecrement(&GetData()->nRefs) <= 0)
FreeData(GetData());
}
}
What happens here is that the szPlot's string pointer's reference count is decremented and only if this reference count drops to zero (or negative) will the actual string be released.
In our example, if szPlot still points to the same string "Country road.", the reference count of this string in memory is decremented but the ref count will not be zero yet (cstr still holds a ref count) and no freeing is actually performed.
I believe no harm is actually done by the destructor in this sense.
Please provide more info on how you call the ActivatePlot() function as well what actually takes place in the function ActivatePlot() so that we can have a better picture of the nature of your crash.
Thanks,
Bio.
|
|
|
|
|
I desesperatly need help for passing a DISPPARAMS strucutre to IDispatch::Invoke.
Here is the calling code, in C++:
<br />
HRESULT hr;<br />
OLECHAR FAR* szMember = L"MyFunction";<br />
DISPID DispatchID;<br />
<br />
int i = 10;
<br />
DISPPARAMS DispatchParams;<br />
DispatchParams.cArgs=1;<br />
DispatchParams.rgvarg = new VARIANTARG[1];<br />
DispatchParams.rgvarg[0].vt = VT_BYREF|VT_INT;<br />
DispatchParams.rgvarg[0].pintVal = &i;<br />
DispatchParams.rgdispidNamedArgs=NULL;<br />
DispatchParams.cNamedArgs=0;<br />
<br />
CoInitialize(NULL);<br />
<br />
if (FAILED(hr = CoCreateInstance(MyCLSID, NULL, CLSCTX_SERVER, IID_IUnknown, (void FAR* FAR*)&pUnknown))) return hr;<br />
if (FAILED(hr = pUnknown->QueryInterface(IID_IDispatch, (void FAR* FAR*)&pDispatch))) return hr;<br />
if (FAILED(hr = pDispatch->GetIDsOfNames(IID_NULL, &szMember, 1, LOCALE_USER_DEFAULT, &DispatchID))) return hr;<br />
<br />
<br />
hr = pDispatch->Invoke(DispatchID, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &DispatchParams, NULL, NULL, NULL);<br />
<br />
And this is the function I'm trying to call, in VB:
<br />
Public Function MyFunction(ByRef Parameter As Integer)<br />
MsgBox Str(Parameter), , "Parameter:"<br />
End Function<br />
When I run the calling code, IDispatch::Invoke returns a type mismatch error. However, if I enlarge the rgvarg field of the DispatchParams structure and write the parameter into rgvarg[1] instead of rgvarg[0] (while cArg is still 1), it does not return any error and MyFunction does show the message box, but it shows the value is 0, while it is supposed to be 10. I would add that I have no problems when using IDispatch::Invoke for calling functions that have no parameters.
I've spent hours trying to figure out what was wrong but it went nowhere. Would someone please help me ?
|
|
|
|
|
You have to use the VT_I2 or VT_I4 instead of VT_INT, because VT_INT is not OLE-compatible type at all.
Also the VB type "Integer" is the C/C++ type "short int". Therefore, you have to write
short int i = 10;
...<br />
DispatchParams.rgvarg[0].vt = VT_BYREF|VT_I2;<br />
DispatchParams.rgvarg[0].piVal = &i;
With best wishes,
Vita
|
|
|
|
|
Thank you so much, it helped a lot. Now I'm going to be careful with data types. However I have another question. I was wondering if it was possible to pass an array containing pointers to variables, these variables being either long integers or BSTR. I was thinking I could pass an array of variant, but I'm not sure about the result.
|
|
|
|
|
[quote]I was wondering if it was possible to pass an array containing pointers to variables, these variables being either long integers or BSTR. I was thinking I could pass an array of variant, but I'm not sure about the result. [/quote]
I think that this has no sense.
There is no array with reference data. Because the VARIANT with vt==VT_BYREF|VT_ARRAY|VT_?SIMPLETYPE? means the "pointer to SAFEARRAY with SIMPLETYPE members" (aka "SAFEARRAY(SIMPLETYPE)*") instead of the "SAFEARRAY with pointers to SIMPLETYPE data" (aka "SAFEARRAY(SIMPLETYPE*)").
Therefore, there is only SAFEARRAY(VARIANT) way, but the VB can use (or get) the VARIANT with VT_BYREF|VT_?SIMPLETYPE?, but cannot set such type. So I think that you can use only SAFEARRAY(VARIANT) with VT_?SIMPLETYPE? members.
With best wishes,
Vita
|
|
|
|
|
|
I want to find a LocalServer COM example not using ATL here. I have finished one but I don't know how to Register. I have tried it as below: mycom.exe -/RegServer
but my client can't create instance.so I think I have made mistaken on Registry.who can tell me something about registry?
|
|
|
|
|
i my project i search the /RegServer and /UnregServer in order to reg or unreg my server.
i do it like this in my CWinApp::InitInstance:
// ( _AtlModule is derived from CAtlMfcModule )
<br />
TCHAR szToken[] = _T("-/");<br />
long operation = 0;<br />
LPCTSTR lpsztoken = _AtlModule.FindOneOf( lpCmdline, szToken );<br />
<br />
while ( lpszToken != NULL )<br />
{<br />
if ( lstrcmpi( lpszToken, _T("RegServer") ) == 0 )<br />
{<br />
operation = 1;<br />
break;<br />
}<br />
if ( lstrcmpi( lpszToken, _T("UnregServer") ) == 0 )<br />
{<br />
operation = 2;<br />
break;<br />
}<br />
lpsztoken = _AtlModule.FindOneOf( lpCmdline, szToken );<br />
}<br />
<br />
switch ( operation )<br />
{<br />
case 0:
break:<br />
case 1:
_AtlModule.UpdateRegistryFromResource( MYUINT, TRUE );<br />
_AtlModule.RegisterServer( TRUE );<br />
break;<br />
case 2:
_AtlModule.UpdateRegistryFromResource( MYUINT, TRUE );<br />
_AtlModule.UnregisterServer( TRUE );<br />
break;<br />
}<br />
try like this ...
modified 14-Jun-22 21:01pm.
|
|
|
|
|
You have to use either
mycom.exe -RegServer
or
mycom.exe /RegServer
With best wishes,
Vita
|
|
|
|
|
Would this be safe? (the following code is implemented in a DLL, used by a single EXE and a bunch of COM DLLs)
CComAutoCriticalSection cs;
DWORD dwOwnerThreadId;
ISomeInterface* pObject = 0;
IStream* pObjMarshalled = 0;
HRESULT RegisterGlobalObject(ISomeInterface* pObj)
{
if(!cs.Lock())
return E_FAIL;
if(pObject != 0) {
cs.Unlock();
return E_UNEXPECTED;
}
HRESULT hr = CoMarshalInterThreadInterfaceInStream(
__uuidof(ISomeInterface),
pObj,
&pObjMarshalled
);
if(FAILED(hr)) {
cs.Unlock();
return hr;
}
pObject = pObj;
dwOwnerThreadId = GetCurrentThreadId();
cs.Unlock();
return S_OK;
}
HRESULT GetGlobalObject(ISomeInterface** ppObj)
{
if(!ppObj)
return E_POINTER;
if(!pObject)
return E_FAIL;
if(!cs.Lock())
return E_FAIL;
if(GetCurrentThreadId() == dwOwnerThreadId) {
*ppObj = pObject;
(*ppObject)->AddRef();
cs.Unlock();
return S_OK;
}
*ppObj = 0;
LARGE_INTEGER seek;
seek.QuadPart = 0;
HRESULT hr = pObjMarshalled->Seek(seek, STREAM_SEEK_SET, NULL);
if(FAILED(hr) {
cs.Unlock();
return hr;
}
hr = CoUnmarshalInterface(
pObjMarshalled,
__uuidof(ISomeInterface),
(void**)ppObj
);
cs.Unlock();
return hr;
}
I'm marshalling the interface pointer upon registration using the inter thread marshalling function, because I know that this function will not be called from any other process (it can't be). I also assume that CoUnmarshalInterface() will work for interfaces marshalled with CoMarshalInterThreadInterfaceInStream() .
I have yet to try this out (it's way past bedtime ). But if you read this and spot any inherent danger with this code, please let me know.
--
Sancte Míchael Archángele, defénde nos in proélio contra nequítiam et
insídias diáboli esto præsídium. Imperet illi Deus, súpplices deprecámur:
tuque, princeps milítiæ cæléstis, Sátanam aliósque spíritus malígnos, qui
ad perditiónem animárum pervagántur in mundo, divína virtúte,
In inférnum detrude. Amen.
|
|
|
|
|
Once the marshalled interface has been "picked up" from the stream and used, it seems that it's been used up already. I receive RPC_E_DISCONNECTED on method access.
I decided to make a singleton COM object which stores the ISomeInterface pointer instead. Then COM will handle everything automatically.
--
Sancte Míchael Archángele, defénde nos in proélio contra nequítiam et
insídias diáboli esto præsídium. Imperet illi Deus, súpplices deprecámur:
tuque, princeps milítiæ cæléstis, Sátanam aliósque spíritus malígnos, qui
ad perditiónem animárum pervagántur in mundo, divína virtúte,
In inférnum detrude. Amen.
|
|
|
|
|
You might have look to the IGlobalInterfaceTable . This allows multiple unmarshalling of once marshalled interface - if it helps you somehow.
|
|
|
|
|
Hello there,
Does anyone know how I can search for all registered COM objects that expose some specific (defined by me) interface?
|
|
|
|
|
hi frnd
One can search a component installed on a particular machine based on the CATID i.e category ID in which it falls.
there are two interfaces
ICatInformation using methods of which you can enumerate all the component of a CATID.
and ICatRegister interface which provides methods for registering and unregistering component category information in the Registry.
have look on these interfaces in your MSDN , u might find your solution.
Abhishek Srivastava
Software Engg (VC++)
India ,Noida
Mobile no 9891492921
|
|
|
|
|
HI!
I need Yahoo messenger login interface urgently. I want to access yahoo messenger window from my application bypassing the login screen for a particular user. any links or suggestions is most welcome.
|
|
|
|
|
Hi, I need to access COM objects during runtime or dynamically using VC++6. Can somebody please help me in this? Is there a way I can call the COM objects during runtime by entering the GUID or something like that? I am a beginner in COM..
Thx!!
|
|
|
|
|
Is this the function you're looking for?
<code>
CoCreateInstance(REFCLSID rclsid,
LPUNKNOWN pUnkOuter,
DWORD dwClsContext,
REFIID riid,
LPVOID * ppv);
</code>
I hope this helps you.
-John
|
|
|
|
|
I forgot to mention you might want to call CoIntialize(NULL) to initialize the COM runtime before making a call to CoCreateInstance(). Once you're through using your COM objects be sure and call CoUnitialize().
|
|
|
|
|
Hi there,
One can access COM objects at run time , but the interface supported by this COM object should
support IDispatch interface.
CLSID objClsid;
// initialize your obj CLSID in this variable
using CoCreateInstance() get the IDispatch pointer.
IDispatch *dispPtr;
CoCreateInstance(objClsid, NULL, CLSCTX_ALL, IID_IDispatch , (void **) &dispPtr);
if your object support IDispatch interface , it will return its instance , else it will return NULL.
now using this dispPtr and IDispatch
int isInfoAvailable;
dispPtr->GetTypeInfoCount(&isInfoAvailable);
if isInfoAvailable = 0 , that means this object does not provide run time type information of interfaces it supports.
if isInfoAvailable = 1 , that mean now you can query for ITypeInfo interface pointer for getting information about the interface this object supports.
now using GetTypeInfo() method you can further query for ITypeInfo interface , using which you can browse all the interface and methods of these interface supported by your COM object.
and then using Invoke and GetIDsOfName methods of IDispatch you can also execute your method at run time.
Regards
Abhishek Srivastava
Software Engg (VC++)
India ,Noida
Mobile no 9891492921
|
|
|
|
|
|
Hello,
I want to learn COM+. I am an intermediate level programmer and am currently learning C#. Can anyone suggest a good book to purchase to learn COM+?
Thanx for the help.
-Flack
|
|
|
|
|
I want to extract Thumbnails Asynchronously...
I use IExtractImage::GetLocation with the flag IEIFLAG_ASYNC .
I get back an E_PENDING which as documented is the sign that things can go on Asynchronously...
I get the object's IRunnableTask (simple QueryInterface )...
And then nothing happens.
IRunnableTask::IsRunning() always returns 0 (which is IRTIR_TASK_NOT_RUNNING ).
IRunnableTask::Run() returns E_NOTIMPL (some documentation said there's no need to call it manually, but anyhows).
So, Can someone tell me what's going wrong here ?
thanks
|
|
|
|
|