|
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
|
|
|
|
|
hi
what iam tring to do is iam trying to create tool that closely resembles the working of DbgView .
The way the DbgView tool works is:
You can launch the tool on the system.
OutputDebugString() is a Win32 API. If you use that API in your program, the output will then be shown on DbgView.
SO using this functionality i want to use OutputDebugString() in my applications and i want the output(string in OutputDebugString()) to be shown in servers GUI.
CAn u suggest me how to proceed.
Thanks in Advance
abhi
|
|
|
|
|
How many applications do you have that need to send output to the server GUI?
If the answer is just one or two, then you could just write a short function to create the COM interface object on the remote server, use it, and then release the interface. The downside of doing this would be that several round trips between the client and server computers would be necessary, resulting in time delays, plus you would need to deal with the security issues in all the client programs, and of course the server.
What sort of scale are we discussing here? How many messages would need to be sent. Would you need to keep the interface open during the total life of the client program, or could it open just when sending messages to the server?
If you wanted to recreate the com interface every time that you wish to send a message, you could write some code like this (using MFC CStrings, but these could be replaced with other types):
int PrintToServerGUI( LPCTSTR szFormat, ... )<br />
{<br />
int nTextLen = 0;<br />
if ( szFormat )<br />
{<br />
CString strOut;<br />
va_list p_arg;<br />
va_start( p_arg, szFormat );<br />
strOut.FormatV( szFormat, p_arg );<br />
nTextLen = strOut.GetLength();<br />
va_end( p_arg );<br />
}<br />
int nWritten = 0;<br />
if ( nTextLen > 0 )<br />
{<br />
IMyServerGUI *pMyServer = NULL;<br />
...
...
...
...<br />
if ( pMyServer )<br />
{<br />
if ( SUCCEEDED( pMyServer->OutputString( strOut ) ) )<br />
{<br />
nWritten = nTextLen;<br />
}<br />
pMyServer->Release();<br />
}<br />
}<br />
return nTextLen;<br />
}
You need to write your own interface creation code for your com interface. Note that is code assumes that you have a function in your interface called OutputString( LPCTSTR pString ).
If there are a lot of applications that need to communicate with the server, then it may be better to use an intermediate server programming on the local client, that would then pass the messages as appropriate to the server program. The advantage would be that in network security terms, you would only need to concern yourself with the traffic between the server and intermediate server.
|
|
|
|
|
Thanks for your suggestions.
now instead of server capturing client messages now i want client's Gui capture messages from serevr.
how to proceed further with this.
thanks in advance
abhi
|
|
|
|
|
Please could you clarify exactly what you are requesting. i.e. Are you looking to receieve messages on your client? Is this the same client as the previous client?
If the client is the same program, then the usual way to allow the server to call the client by using an event sink, which you can search for and read about on CodeProject, and most books on COM. This generally works very well, but the security issues can be a real pain to overcome.
I cannot say any more than this at this stage without knowing more details.
|
|
|
|
|
I have an asp page that gathers the file and folder listings of the local client's hard drive by using the ActiveX Object Scripting.FileSystemObject, but I get an "Automation server can't create object" error when I run the site. It throws that error when I try to instantiate the following, "var fos = new ActiveXObject('Scripting.FileSystemObject');".
I googled this error and almost everyone says to upgrade Windows Scripting, which I did to version 5.6, but I still get the error. Weird thing is that if I run the page locally I get no errors and it works, but if I run the page under my IIS I get this error, so is there a way I can update windows scripting under my IIS or is there an alternative solution to this?
|
|
|
|
|
For the first time you have to register the class by command: 'regsvr32 <dll or="" ocx="">'. or inside your programm you have to examine the 'DllRegisterServer' function and call it.
|
|
|
|
|
Hello All,
Im using a simple ODBC connection to pull values out of an excel spreadsheet. It seems to work pretty well, except when it gets to columns with multiple 0's. It does not import the 0's even though the column is specified as text in the spreadsheet. Everything else seems to import fine. A sample excel column would look like this:
200,-,00,-,414001,-,0000,.,00,-,704
It wont import the 0 only cells. Im doing a simple import like this:
oCmd.CommandText = "SELECT * FROM \"" + sName + "$\"";
oCmd.Connection = oConnection;
oDataAdapter.SelectCommand = oCmd;
oDataAdapter.Fill(oDataTable);
Any idea's would be greatly appreciated,
Thanks,
Ryan
|
|
|
|
|
Anyone can describe the progress or drag-and-drop in the explorer.exe?
I want to catch the dragged contents in the explorer.exe and how shou I do?
|
|
|
|
|
You cannot catch or hook drag and drop between other applications. The only thing you can do is to register an DragDropHandler for the application. For the explorer it is of your own risk.
|
|
|
|
|
I have a fundamental component..
Suppose if I developed a ATL componet(DLL)and
If I want to release to the client what should be given to the client
how the client know the CLSID and IID of this component.
If I am not wrong I should deliver to the client
DLL, TLB.
could anybody clarify me this
thanks
Siva
|
|
|
|
|
Hello Siva,
At minimum, deliver the DLL itself plus other dependent DLLs. These must be registered successfully in the client's OS.
Thereafter, if the client uses VC++, the user will need to #import the DLL, e.g. :
#import "MyComponentDLL.dll"
A set of Type Library Header files will be generated by the VC++ compiler.
If the client uses VB, the user will have to reference your DLL.
.NET dev environments (e.g. C#, VB.NET) will also need to reference the DLL.
For other development environments, check out the documentation.
Best Regards,
Bio.
|
|
|
|
|