|
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.
|
|
|
|
|
Hi
I would add something. In my work I am using a DLL (Which has been built in C#) and I am using it in VC++ by using COM. Below is how I am doing it in my case.
If client uses VC++, it has to create a Type library (TLB) file from the DLL. In microsoft visual studio (.NET) 2003 there is a tool , Regasm.Exe ..
Use Regasm.exe tool to create TLB file .. Actually it registers the DLL in the system registry as well as creates a TLB file.
Now use this TLB in #import command.
#import "MyComponentDLL.tlb"
A set of Type Library Header files will be generated by the VC++ compiler.
Now Put the TLB file in your working folder and put the DLL in the folder where your solution EXE will be created.
and Start then building the code.
-- modified at 4:51 Wednesday 1st March, 2006
|
|
|
|
|
i want to expose all of my interfaces to a Vb application, but the vb
application sees nothing except the default interface.
thanx in advance
Z.A
-- modified at 2:11 Friday 24th February, 2006
|
|
|
|
|
Hello zubair_ahmed,
Yes, COM objects will by default expose its "default" interface. However, you can DIM an object of another interface and cast the original COM object to this interface. Doing so is equivalent to performing QueryInterface().
Here is an example :
'' Let's say TestObject supports its default interface
'' plus TestInterface01 and TestInterface02.
Set TestObjectObj = New TestObject
'' Define objects of the 2 desired interfaces...
Dim TestInterface01Ptr As TestInterface01
Dim TestInterface02Ptr As TestInterface02
'' Cast TestObjectObj to the desired interfaces.
'' This action is equivalent to QueryInterface().
Set TestInterface01Ptr = TestObjectObj
Set TestInterface02Ptr = TestObjectObj
'' Use the interfaces' properties and methods as per normal...
TestInterface01Ptr.strProperty = "Hello"
TestInterface01Ptr.Method01
TestInterface02Ptr.longProperty = 101
TestInterface02Ptr.Method01
'' Set the interfaces to nothing is equivalent to Release()'ing
'' the interface pointers.
Set TestInterface01Ptr = nothing
Set TestInterface02Ptr = nothing
Best Regards,
Bio.
|
|
|
|
|
You have to add the IDispatch to all your Interfaces. For further informations see in your documentation how to implement an IDispatch-interface.
|
|
|
|
|