|
I've a program written on Delphi whith implemented Automation interface. This program is not register itself in Running Object Table in the runtime. How can I connect to the running instance of this program's automation interface from my C++ client?
Thanks.
|
|
|
|
|
There is a activex written using MFC and COM .
The main class inherits
CComObjectRootEx
IDispatchImpl
CComCoClass
IObjectSafetyImpl
Now 2threads are created inside this class in the constructor.
When IE is refreshed/reloaded, I loss the pointer of the process and
threads are not deallocated.
So what I did is, made thread ID's as static in the class and
deallocate them in the constructor before creating new threads.
When I WaitforSingleObject() I always get time out(258).
so I call TerminateThread().
I know this is wrong way.
Now this method is leaving lot of leaks.
Please suggest me a remedy so that I can trap the refresh ask my thread
to exit gracefully.
Thanks a lot in advance.
-Tenali-
|
|
|
|
|
Hello.
I know how to send longs, ints, booleans, (basic types) between a COM component and a client using VARIANT.
However, how do I send a user defined object using VARIANTs as well?
Is it possible?
Could you post please a small source code example?
THANK YOU
Dario
|
|
|
|
|
I have written a COM service using ATL 7.0 and VS 2003 which contains one COM Class. The class uses a number of member variables, some of which are CComBSTRs. Clients can use the get/put methods on these strings. The strings are processing parameters for calls to the calculation operation in the COM object. The string variables are changed to alter the output each time the object is called. Sometimes, the result of the get function is not what was sent to the put function.
Server Code:
<br />
CComBSTR m_bstrTheString;<br />
<br />
m_bstrTheString = SysAllocString(L"Testing");<br />
<br />
[propget, helpstring("property m_bstrTheString")] HRESULT m_bstrTheString([out, retval] BSTR* pVal);<br />
[propput, helpstring("property m_bstrTheString")] HRESULT m_bstrTheString([in] BSTR newVal);<br />
<br />
STDMETHOD(get_m_bstrTheString)(BSTR* pVal);<br />
STDMETHOD(put_m_bstrTheString)(BSTR newVal);<br />
<br />
STDMETHODIMP CMyClass::get_m_bstrTheString(BSTR* pVal)<br />
{<br />
*pVal = m_bstrTheString;<br />
return S_OK;<br />
}<br />
<br />
STDMETHODIMP CHunter::put_m_bstrTheString(BSTR newVal)<br />
{<br />
size_t s = ::SysStringLen(m_bstrTheString);<br />
if(s > 0)<br />
::SysFreeString(m_bstrTheString);<br />
m_bstrTheString= ::SysAllocString(newVal);<br />
return S_OK;<br />
}<br />
In the client code(simplified):
<br />
BSTR bstrIn;<br />
BSTR bstrOut;<br />
<br />
HRESULT hr = CoInitialize(NULL);<br />
CT2CW szIn(argv[3]);<br />
bstrIn = ::SysAllocString(szIn);<br />
if(bstrIn == NULL)<br />
return E_OUTOFMEMORY;<br />
MyService::IMyPtr pMine(__uuidof(MyService::CMy));<br />
hr = pHunter->put_m_bstrTheString(bstrIn);<br />
hr = pHunter->get_m_bstrTheString(&bstrOut);<br />
My question is: Is this a good way to go about this. I am having the problem of the string sometimes being overwritten by other variables of the same type when performing operations on them.
Thanks in advance for any help.
Rob
|
|
|
|
|
http://msdn.microsoft.com/library/en-us/vclib/html/_atl_CComBSTR.3a3a.Copy.asp?frame=true[^]
CComBSTR does all the SysAllocString stuff for you.
Try this instead:
<br />
CComBSTR m_bstrTheString;<br />
<br />
m_bstrTheString = L"Testing";
<br />
[propget, helpstring("property m_bstrTheString")] HRESULT m_bstrTheString([out, retval] BSTR* pVal);<br />
[propput, helpstring("property m_bstrTheString")] HRESULT m_bstrTheString([in] BSTR newVal);<br />
<br />
STDMETHOD(get_m_bstrTheString)(BSTR* pVal);<br />
STDMETHOD(put_m_bstrTheString)(BSTR newVal);<br />
<br />
STDMETHODIMP CMyClass::get_m_bstrTheString(BSTR* pVal)<br />
{<br />
*pVal = m_bstrTheString.Copy();<br />
return S_OK;<br />
}<br />
<br />
STDMETHODIMP CHunter::put_m_bstrTheString(BSTR newVal)<br />
{<br />
m_bstrTheString= newVal;<br />
return S_OK;<br />
}<br />
|
|
|
|
|
Gerald,
Thanks a metric tonne for the info. It seems to have solved the issues and greatly simplifies the code.
Cheers.
Rob
|
|
|
|
|
How to detect ActiveX on IE when it begins run using BHO?
exactly, I want to know CLSID of ActiveX.
How to catch it?
help me.
and thanks.
|
|
|
|
|
Hi, I have an activeX object ( no GUI ) that I want to use in my MFC project. The problem is I can't seem to capture the messages fired by the activeX. It works fine in the control container, in Visual Basic, .NET but I can't seem to get it to work in VC6.0. What I did to test it, was create a simple dialog based application, added the component through the Add to project/components and controls, used class wizard to add a variable, and also added a handler for the OnMessage. I than created a simple button to invoke a method that fires a message. The message is not retrieved by the OnMessage handler. What could be the problem?
When I debug the ActiveX itself, I see it entering the Fire_OnMessage function but nConnections = 0??? Why is this, how do I have to instantiate the ActiveX object to make it work?
HRESULT Fire_OnMessage(BSTR bstrResult)
{
CComVariant varResult;
T* pT = static_cast<t*>(this);
int nConnectionIndex;
CComVariant* pvars = new CComVariant[1];
int nConnections = m_vec.GetSize();
|
|
|
|
|
Does anybody have a template project or information on how to create an ActiveX EXE (out of process) server in Visual c++? All of the templates included with the compiler either create an in-process ActiveX or an out of process COM object that is not an ActiveX object.
Thanks in advance,
Dave
-- modified at 15:17 Tuesday 28th February, 2006
|
|
|
|
|
I think this is a question of terminology.
"ActiveX EXE" in the VB programmer's world usually mean an "out-of-process COM server with automation interface" in the C++ programmer's world.
My suggestion is this, given that I've understood you correctly:
run the ordinary MFC AppWizard and create an SDI application and have the document support automation.
Hope this helps
--
Roger
It's supposed to be hard, otherwise anybody could do it!
|
|
|
|
|
Thanks, Roger.
Your suggestion was helpful, thanks for clearing that up. I did as you suggested and solved my problem.
Dave.
|
|
|
|
|
I have a C# (managed code) DLL and I am accessing this DLL's functions from C++ (unmanaged code) using COM.
I create a COM object with CoCreateInstance function. Then I do work on this object. After that I call Release() function on this object. But after calling Release() function the object is not destroyed automatically. After calling Release function I called some more functions on this object and all those calls were successful.
I also checked the return value of Release function call which is ZERO which shows the reference count of the object is ZERO and it should automatically destroy the object as soon as the reference count becomes ZERO. But in my case the object is not destroyed.
Actually in my project work I have to create and destroy the COM object many times (1000-2000). So in each iteration the memory size is increasing and after some iteration it becomes more than 1 GB and fills all the page file space and the program hangs.
Could Anybody suggest me how to delete the COM object. I have also given below the server side code which is in C#.
The client side code which I am using is following :
#import "ServerSideCode.tlb" named_guids high_method_prefix("")
#include <iostream.h>
#include <comdef.h>
using namespace ServerSideCode;
class Test
{
public:
IEnterDetails *pPER1;
IEnterDetails *pPER;
IEnterAge *pAge;
public:
void Func1();
};
void Test::Func1()
{
pPER1 = NULL;
HRESULT hr = CoInitialize(NULL);
hr=CoCreateInstance(__uuidof(Manager), NULL, CLSCTX_INPROC_SERVER,
__uuidof(IEnterDetails), reinterpret_cast<void**>(&pPER1));
pPER1->Print();
long a = pPER1->Release();
a = pPER1->Release();
a = pPER1->Release();
a = pPER1->Release();
// pPER1 = NULL;
pPER1->EnterName();
pPER1->Print();
pPER1->QueryInterface(__uuidof(IEnterAge), reinterpret_cast<void**>(&pAge));
pAge->EnterAge();
pAge->Print();
a = pPER1->Release();
CoUninitialize();
}
void main()
{
Test tt;
tt.Func1();
}
The C# code which was used to build the DLL (ServerSideCode.dll) is the following
using System;
namespace ServerSideCode
{
public interface IEnterDetails
{
void EnterName();
void EnterDesignation();
void EnterIncome1();
void EnterIncome2();
void Add();
void Print();
}
public interface IEnterAge
{
void EnterAge();
void Print();
int Age {get; set;}
}
public class Person : IEnterDetails
{
private string Name = "DefaultName", Des = "DefaultDesignation";
private int inc1=0, inc2=0,inc=0;
public void EnterName()
{
Console.WriteLine("Enter your Name : ");
Name = Console.ReadLine();
}
public void EnterDesignation()
{
Console.WriteLine("Enter your Designation : ");
Des = Console.ReadLine();
}
public void EnterIncome1()
{
Console.WriteLine("Enter your source1 income :");
inc1 = Int32.Parse(Console.ReadLine());
}
public void EnterIncome2()
{
Console.WriteLine("Enter your source2 income :");
inc2 = Int32.Parse(Console.ReadLine());
}
public void Add()
{
inc=inc1+inc2;
}
public void Print()
{
Console.WriteLine("Emplyee Name : {0}", Name);
Console.WriteLine("Employee Designation : {0}", Des);
Console.WriteLine("Income from Source1 : {0} \n Income from Source2 : {1}", inc1, inc2);
Console.WriteLine("Total Income of the Employee : {0}",inc);
}
}
public class Manager: Person, IEnterAge
{
private int age;
public void EnterAge()
{
Console.WriteLine("Enter the Age in years :");
age = Int32.Parse(Console.ReadLine());
}
public int Age
{
get
{
return age;
}
set
{
age = value;
}
}
public void Print()
{
base.Print();
Console.WriteLine("The Age of the Employee : {0}", age);
}
}
}
Please tell me if I am wrong anywhere in my server code.
-- modified at 6:35 Tuesday 28th February, 2006
|
|
|
|
|
|
I have a C# (managed code) DLL and I am accessing this DLL's functions from C++ (unmanaged code) using COM.
I create a COM object with CoCreateInstance function. Then I do work on this object. After that I call Release() function on this object. But after calling Release() function the object is not destroyed automatically. After calling Release function I called some more functions on this object and all those calls were successful.
I called CoCreateInstance only once and there is only one reference of this object in my code. I also checked the return value of Release function call which is ZERO which shows the reference count of the object is ZERO and it should automatically destroy the object as soon as the reference count becomes ZERO. But in my case the object is not destroyed.
Actually in my project work I have to create and destroy the COM object many times (1000-2000). So in each iteration the memory size is increasing and after some iteration it becomes more than 1 GB and fills all the page file space and the program hangs.
Could Anybody suggest me how to delete the COM object.
The code I am using is following :
#include<iostream.h>
#include <afxmt.h>
#include <comdef.h>
#include<string.h>
#import "mscorlib.tlb" raw_interfaces_only
#import "Flowmaster.Automation.Gui.tlb" no_namespace named_guids
#import "Flowmaster.Automation.Analysis.tlb" no_namespace named_guids
class CFDlinkDoc
{
IFM2_AnalysisControl* m_pAnalCntrlv7;
BSTR sDataSource;
BSTR sDataBase;
BSTR sProject;
BSTR sUserName;
BSTR sPassword;
BSTR Project;
BSTR NetworkName;
BSTR Description;
BSTR Owner;
int ResultID;
public:
CFDlinkDoc();
void func1();
};
CFDlinkDoc::CFDlinkDoc()
{
m_pAnalCntrlv7 = NULL;
sDataSource = L"pcpune26";
sDataBase = L"FM100206";
sProject = L"Flowmaster";
sUserName = L"Admin";
sPassword = L"";
Project = L"Flowmaster";
NetworkName = L"AmitG";
Description = L"Hi, COM testing From C++";
Owner = L"AG";
}
void CFDlinkDoc::func1()
{
HRESULT hr = CoInitialize(NULL);
hr = CoCreateInstance(__uuidof(FM2_AnalysisControl) ,NULL, CLSCTX_INPROC_SERVER, __uuidof(IFM2_AnalysisControl), reinterpret_cast<void**>(&m_pAnalCntrlv7));
long lP= m_pAnalCntrlv7->DatabaseLogin(sDataSource, sDataBase, sProject, sUserName, sPassword);
m_pAnalCntrlv7->PutProjectName(Project);
m_pAnalCntrlv7->PutNetworkName(NetworkName);
m_pAnalCntrlv7->PutDescription(Description);
m_pAnalCntrlv7->PutOwnername(Owner);
m_pAnalCntrlv7->PutAnalysisType(_T("SS"));
m_pAnalCntrlv7->PutHeatTransfer(0);
if(m_pAnalCntrlv7->Initialise() == 0)
cout<<"Failed to initialise network";
m_pAnalCntrlv7->RunToCompletion();
m_pAnalCntrlv7->Release();
m_pAnalCntrlv7 = NULL;
CoUninitialize();
}
void main()
{
CFDlinkDoc CFDlink = CFDlinkDoc();
for(int i = 0 ; i <1000 ; i++)
{
CFDlink.func1();
}
}
-- modified at 4:25 Tuesday 28th February, 2006
|
|
|
|
|
Your code seems to be ok. But it is possible that the database server add's a refcount to your interface. Therefore uninitialize your interface (calls like: close() uninitialize() or some like that). If all dependencies are release your interface will be destroyed finally. By the way you should never delete an interface (delete m_pAnalCntrlv7; ).
|
|
|
|
|
hi mbue,
Thank you very much for responding.
You are right that I should never delete a interface pointer (delete m_pAnalCntrlv7;). I am not doing it.
You say that there is a possibility that database server adds a refcount to my COM object. Yes, there may be a possibility. I have got another very simple code and I have not to use any database in that. But I am still getting the same problem in that code also.
I am goofed up trying it.
Can you (or anybody else) suggest me any other reasons why it is happening to me?
Many heartiest Thanks in Advance
Amit
-- modified at 5:21 Tuesday 28th February, 2006
|
|
|
|
|
here comes a very small demonstration how COM works:
<br />
void CFDlinkDoc::func1()<br />
{<br />
HRESULT hr = CoInitialize(0);<br />
hr = CoCreateInstance(__uuidof(FM2_AnalysisControl) ,0, CLSCTX_INPROC_SERVER, __uuidof(IFM2_AnalysisControl), &m_pAnalCntrlv7);<br />
if(S_OK==hr)<br />
{<br />
m_pAnalCntrlv7->Release();
}<br />
CoUninitialize();<br />
}<br />
<br />
HRESULT CoCreateInstance(REFCLSID rclsid,LPUNKNOWN pout,DWORD dwClsContext,REFIID riid,LPVOID* ppv)<br />
{<br />
char dll[MAX_PATH];<br />
HINSTANCE hi = LoadLibrary(dll);<br />
LPFNGETCLASSOBJECT fn=(LPFNGETCLASSOBJECT)(hi?GetProcAddress(h,"DllGetClassObject"):0);<br />
if(fn)<br />
{<br />
IClassFactory* fac;<br />
HRESULT hr;<br />
if(S_OK==fn(IID_NULL,riid,(void**)ppv)) return S_OK;<br />
if(S_OK!=fn(IID_NULL,IID_IClassFactory,(void**)&fac)) return E_NOINTERFACE;<br />
hr = fac->CreateInstance(pout,riid,(void**)ppv); fac->Release();<br />
return hr;<br />
}<br />
return E_FAIL;<br />
}<br />
<br />
class iAnalysisControl : public IAnalysisControl<br />
{<br />
public:
virtual HRESULT __stdcall QueryInterface(REFIID riid,void** ppv)<br />
{<br />
if(riid==__uuidof(IFM2_AnalysisControl)) return *(IAnalysisControl**)ppv=this,AddRef(),S_OK;<br />
if(riid==IID_IUnknown) return *(IUnknown**)ppv=this,AddRef(),S_OK;<br />
return E_NOINTERFACE;<br />
}<br />
virtual unsigned long __stdcall AddRef(){ return ++_ref; }<br />
virtual unsigned long __stdcall Release(){ if(!--_ref){ delete this; return 0; } return _ref; }<br />
<br />
iAnalysisControl(){ _ref=1; }<br />
~iAnalysisControl(){ ASSERT(!_ref); }<br />
long _ref;<br />
};<br />
<br />
HRESULT FAR PASCAL DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID* ppv)<br />
{<br />
if(riid==__uuidof(IFM2_AnalysisControl))<br />
{<br />
iAnalysisControl* me = new iAnalysisControl;<br />
return me?*(IAnalysisControl**)ppv=me,S_OK:E_OUTOFMEMORY;<br />
}<br />
return E_NOINTERFACE;<br />
}
Debug through the code and you can see whats wrong in your modules. In this example the external interface refcount goes to zero when you call Release(). Sorry for the vanished tabs.
|
|
|
|
|
hi,
Thanks Again.
Your mail is helpful but I am very new to COM so find it a bit difficult to understand.
You have written some server side code also. Here I want to know "Do we need to override the Addref() and Release() functions of IUnknown interfaces or there is no need to do it"
Actually I have just got the DLL by building the C# code. I have not written the coding of Addref, QueryInterface and Release functions. Is that wrong ?
I have posted an other message on the board which contains both codes (client side and server side). Can you please see that message and help me in sorting the problem out. I logged that message because for the problem of the present message I cannot provide server side code. Please see that message also and let me know your comments. Your mail is very very helpful to me and it may take me out of the misery I am going through for so long. I can just say Thank You Very Very Much, dear.
Best Regards,
-- modified at 6:39 Tuesday 28th February, 2006
|
|
|
|
|
This was only a basically introduction how COM works. If you use abstract classes (your class is derived from) its not necessary to implement the basic functions again (from IUnknown). If you use C# you should never do that except you need it anyway. Remember the example is reduced to the native and also don't work outside inproc environments! Sorry it's only to understand the mechanism.
|
|
|
|
|
Hi all
Can i have examples on Multipleclients connected to a single server using DCOM
Thanks in advance
abhi
|
|
|
|
|
I cannot give you an example, but I can tell you how to set one up for yourself, assuming that you have some knowledge of COM. If you have any problems with these suggestions, that you will need to consult the help documentation, or post a simple question. Before I start, I would like to say that operation of DCOM is much the same as the operation of COM. If you get the server and clients to work together on the same computer, then all you need to do is to change a few calls, and make sure that the security privileges are set, and then everything should work. Unfortunately, security is not a trivial matter, and you will probably have to study it for yourself, in order to get everything working.
Firstly create a com out-of-process exe server, with your desired remote interface included.
Secondly create a client application that is able to use the above created server interface on your local computer. Use CoCreateInstanceEx() to create the instance of the interface, setting the "ServerComputerName" to your local computer name eg:
<br />
<br />
COSERVERINFO csi = {0};<br />
csi.pwszName = L"ServerComputerName"<br />
csi.pAuthInfo = NULL;<br />
<br />
MULTI_QI qi[1] = {0};<br />
qi[0].pIID = &IID_IMyInterface<br />
if ( SUCCEEDED( CoCreateInstanceEx(CLSID_MyInterface, NULL, CLSCTX_REMOTE_SERVER, &csi, 1, qi ) )<br />
{<br />
CMyInterface *pMyInterface = static_cast<IMyInterface *>( qi[0].pItf);<br />
}<br />
Test it to make sure your server interface works as anticipated. When it does, you can replace ServerComputerName with the actual intended server.
Security is the number one headache when programming DCOM. Inserte calls to CoInitializeSecurity() in the server and client InitInstance() like this:
<br />
CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE,RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);<br />
which will reduce the security checking.
Install the server onto another computer by registering it and running it. Use DCOMCNFG to check that permissions have been set so that remote users have access to your server program. You may also need to set the COM default limits. You should be able read up on using DCOMCNFG in any good COM documentation. Finally on XP etc, check that the firewall will allow this program to allow/have access to remote users.
You may also need to set the firewall on the client computer to allow your computer program to connect out.
If all the steps have been followed successfully, then you should be able to connect multiple clients to same server version.
Lastly, if you get stuck, there are several good com server articles on CP that may also be able to assist you.
-- modified at 7:52 Monday 6th March, 2006
|
|
|
|
|
Thanks
I will try using your inputs.
abhi
|
|
|
|
|
hi
iam working on a single computer.
What i have done is , i have designed a GUI in server containg a multiline edit box. and whenever iam executing client application clients message is capturing in the edit box of server GUI.
And what iam trying to do is whenever multiple clients are executed clients messages should be captured in the editbox of server GUI.
But the problem is whenever iam executing a client a new server application is executing and message is captured in the GUI of that server.
But what i want is all client should communicate to a single serverand messages should be captured in that Servers GUI.
I think you understood my problen .
can u please help me on this.
Thank You
abhi
|
|
|
|
|
The most important thing to check is the InitInstance of the server app. The function _Module.RegisterClassObjects() is called to setup the class factory. For the multiple user situation that you need it is important that the parameter REGCLS_SINGLEUSE is not used.
Make sure that a line similar to this is applied:
_Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE )
(NB In vc7.1, the object might be _AtlModule)
Make sure that the server is running before you use the client. Assuming that that messages can be posted to your edit box from anywhere in your server app, you can send a message from the constructor of your interface class to show that the interface has been created from the running instance of your server.
If this does not work, or is not applicable then please let me know.
|
|
|
|
|
Its working fine
Thankyou very much.
abhi
|
|
|
|
|