|
Thanks a lot! I'll try the CoFreeUnusedLibraries()
And I would agree with you on the access violation (question 1), but I have a programmer that sitts right across from me and he just wrote that code and it worked. I didn't try that. He says that through the A->B->C is about 3 times slower than direct A->C (when A create C on it's own). I refused to beleave but don't have time to verify that so I asked here.
|
|
|
|
|
OK, without seeing the code, it is hard to know exactly what he is doing.
Trying to copy a pointer into another process by simply moving the rvalue will result in an invalid call, because the rvalue is an address in another process.
If it works what he is doing is marshalling the pointer into process A. This is a valid COM operation. What happens when you marshall a pointer between two processes is COM is creating a proxy behind the scenes in A that allows A to call B and request a function call on C. The reason this is slower is because A is still not calling the C DLL directly (this is not possible under any circumstances). Instead it is calling a proxy that forwards the request to B, which then forwards the request to C on behalf of A. The behind the scenes proxy call from A to B is out-of-process, so it runs more slowly than a in-process DLL function call.
There are scenarios when an "A->B->C" style call arrangement is appropriate - usually if the C DLL maintains any state that both A and B either require access to, or that must be maintained by C across both A nd B function calls - i.e. A calls a function in C that results in setting some state variables. B then calls another function in C that also depends upon the state set by the previous function call from A).
In this case you would design your DLL to be loaded by whichever process - A or B - is anticipated to make the most calls to the DLL to minimize the performance hit.
If the rationale for an "A->B->C" style call is not based on a shared state requirement, then the performance hit is probably not worth it. For exampole, suppose you want to load only one instance of C to reduce memory consumption. When A and B are created they run on separate threads, each of which is allocated a pretty big chunk of memory at startup. Calling C from A via B is probably causing a pointless performance hit because A may not be using memory it already has allocated. Unless your C DLL is really huge, you might as well load the C DLL in both processes and eliminate the proxy.
Robert
|
|
|
|
|
Quick links for your question
Ans 1. Check Aggregation and Conatainment topics/features in COM
Ans 2. Check CoFreeUnusedLibrary API and DllCanUnloadNow wellknown exported function from INPROCSERVERS
Have a great day ahead!
Regards,
Sohail Kadiwala
(My Blog - http://blogs.wdevs.com/sohail/[^])
modified 21-Apr-21 21:01pm.
|
|
|
|
|
Hi,
I'm trying to write an Out of proc DCOM server in C#. I have the Server written, its now a COM object so thats done.
Where i'm stuck is this. As far as I kmow, DCOM works by having a stub object on the machine that the server is running on, and then a proxy on each of the client machines that communicates with the stub object.
How are the stub and proxy objects created? I'm told that in C++, they are created automatically but I am developing this in C# so I need to know if it works the same. The client is written in C++ and the DCOM server is written in C#.
Any help or comments will be appreciated
Thanks
Millzy
|
|
|
|
|
Hi all!
I have a COM DLL (Project1) which defines an enum, along with interfaces that uses it.
I have a 2nd COM DLL (Project2) which also needs to use this enum in its interfaces.
I've split the enum out into a separate .IDL file, and then tried various combinations of importing or #including this into both main IDL files. I've eventually managed to get them both to build, but then when I try to write a #import both DLLs into a test app, I get redefinition errors for the enum.
Does anyone have any experience with this sort of thing?
Many thanks,
Gary
|
|
|
|
|
Include the IDL file containing the enums inside a namspace in your Project1.IDL and Project2.IDL
I think this will solve your problem.
Have a great day ahead!
Regards,
Sohail Kadiwala
(My Blog - http://blogs.wdevs.com/sohail/[^])
modified 21-Apr-21 21:01pm.
|
|
|
|
|
Gary,
Try importing the Type library (using importlib("..")) of the enum idl into the type library definition of your components idl and not anywhere else. This might work.
for eg.. consider ur enum idl as "SampleEnum.idl" and its tlb as "SampleEnum.tlb"... then your component idl shud be like,
#import "SampleEnum.idl"
[...]
interface Izzzzzz : Ixxxxx
{
}
[...]
library xxxxx
{
importlib("SampleEnum.tlb");
// your coclass definition goes here
}
Hariharan.T
|
|
|
|
|
Hi Gurus,
I have to call a function in VB COM, with parameter SAFEARRAY ** (it's originally "ByRef TabList() As String" in VB), as below:
HRESULT bGetTab(SAFEARRAY ** TabList, long* iMaxNumber).
I successfully called it with Smart Pointer without any problem (but seems Smart Pointer is doing early binding, I guess it might not be compatible with the next version of that VB COM).
So, I tried the InvokeHelper to do late binding. It's working with the simple functions generates by ClassWizard, but not with that bGetTab function. Here is my code for InvokeHelper (I have to make it by myself, cause the ClassWizard is not capable to generate for that function)
// Function to get a string table with iMaxNumber elements
// VB Code: Public Function bGetTab(ByRef TabList() As String, ByRef iMaxNumber As Long) As Boolean
BOOL CKMServices::bGetTab(SAFEARRAY **TabList, long *iMaxNumber)
{
BOOL result;
static BYTE parms[] =
VTS_PVARIANT VTS_PI4;
InvokeHelper(GetDispid(this->m_lpDispatch, _T("bGetTab")), DISPATCH_METHOD, VT_BOOL, (void*)&result, parms, TabList, iMaxNumber);
return result;
}
// And how do I call that function
SAFEARRAY *arrTab = NULL;
arrTab = SafeArrayCreateVector(VT_BSTR, 0, iMaxNumber);
if (!arrTab) _com_issue_error(E_OUTOFMEMORY);
if(!m_KMServer->bGetTab(&arrTab, &iMaxNumber))
{// Return custom error message }
I've allocated my TabList before calling. But I'm not sure what the type to put for SAFEARRAY **. I have tried VTS_PBSTR, with the same result (it raised COleException).
Thanks before,
Hany
|
|
|
|
|
Hi all!
I tried to post this in the C# forum, but without replies. I tought I might try here too.
I have a small Interop question:
I have a COM object that takes a structure as in-parameter. One of the fields in the structure is an IID*. When doing this in C++ the code:
GUID rrid = __uuidof( _InterfaceName );
parStruct.riid = &rrid;
works fine.
How would I do this in C#? I have tried several things, but can´t get it to work. The type of the struct-field in C# is intPtr. And the only way I can find such a type, that I can think of, is:
Type t = typeof( _InterfaceName );
System.RuntimeTypeHandle h = t.TypeHandle;
parStruct.riid = h.Value;
But I guess that I am way off here.
Any one that can give me a hand here?
Regards
Mikke
Added info:
Hi again!
I tried to create a C++ .Net project instead, just to try and find a work-around. When I took the COM objects needed and tried to import them into my brand new cpp project i got this error message:
TlbImp warning: The type library importer could not convert the signature for the member 'RobEventParams.riid'.
And a couple of other ones like this one for other similar parameter-structs with riid fields. What does that mean for me? Is it impossible to marshal something from .Net into this COM? The purpose is to set up a sink and recieve events from the COM object, to do this I should send a ref to an object that should recieve the events and the signature of an interface implemented in the receiver. It is the interface "signature" that is the riid, and also the problem here. When I execute my C# code above I get an exception telling me that "No such interface supported". Do I have to submit a non-.net method as a sink here?
Best regards again / Mikke
|
|
|
|
|
I can see why no one responded to your inquiry. The way you phrased it is confusing, even to me, and I read it and then re-read it several times.
The basic concept is that you are trying to write a .NET application that will respond to events fired from a COM object that you have imported.
While it appears that this should be a simple matter, it is actually confusing as hell. I have a copy of the book, ".NET and COM: The Complete Interoperability Guide", by Adam Nathan, that I have learned an immense amount of 'stuff' from. I would highly recommend it, especially if you do this type of thing alot. He has an entire chapter devoted to the subject, "Responding to COM Events", which is about 50 pages long and describes the techniques clearly and in detail.
To be perfectly honest with you, I don't completely understand the matter, and I am reluctant to provide you with confusing information.
However, you are working in the right direction. In his book, Adam Nathan describes the callback mechanisms for both .NET and COM, and, while similar, they differ significantly. Basically, he describes the way the type library importer transforms the Source Interface in order to expose the COM object connection points as .NET events using a number of additional types (these are: an event interface, a delegate, a private class that handles interaction with the connection point, and a private sink class that implements the source interface).
It is just too much information to adequately describe here. I suggest that you consult his book.
|
|
|
|
|
Hi Folks )
i've got a strange problem with BSTRs in my DCOM application.
I'm passing 6 BSTRs in a class object (its properties) to a method on a remote server that has to write these strings in some registry values on a pre-defined key.
I've tried both allocating a BSTR and passing it to the server function (see next few lines
BSTR bsBuffer;
bsBuffer=SysAllocString(OLESTR("Prova"));
theApp.m_pHello->SetName(bsBuffer);
SysFreeString(bsBuffer);
and calling server functions directly passing a string (confiding in the operator= that BSTR involves).
theApp.m_pHello->SetDescription("Prova 02/05/2005");
theApp.m_pHello->SetDriver("0.01a");
theApp.m_pHello->SetName("Prova");
theApp.m_pHello->SetVendor("Execute, Crash & Sigh LTD");
theApp.m_pHello->SetLocalBus("VXI");
theApp.m_pHello->SetFirmware("0.00001a");
//Adding Object
theApp.m_pHello->Add();
Running application there is no errors, no code violations, no abnormal program terminations, NOTHING....
BUT
In the registry I get a strange thing like this (I report values in tabular format)
sDesc=Execute, Crash & Sigh LTD
sDriver=0.00001a
sFirmware=0.00001a
sLocalBus=0.00001a
sName=0.00001a
sVendor=Execute, Crash & Sigh LTD
All server functions do nothing but extract the string part in the BSTR and save it in the registry using Windows API functions.
What can I do?
What can it be?
Thanks a lot in advance,
Moreno.
|
|
|
|
|
Try the first one an don't free the Memory (SysFreeString)
Best now?
|
|
|
|
|
OK, I will not free the memory soon, but WHEN can I free that memory?
I don't want to make a memory-consuming server...
Thanx again....
|
|
|
|
|
Marshaling layer in COM do free for you in the client side if parameter is [in] type and in server side in [out] parameter. You must free memory (SysfreeString) in client side for [out] parameter,...
Try to use _bstr_t type and forget memory alloc and free.
Regards...
|
|
|
|
|
OK, I tried to follow your tip and went into trouble again (i'm not SO experienced ).
Most of my server Interface's methods use the BSTR type. I tried to change it, but now I need to know how to declare the _bstr_t type in my IDL file. I tried using both import and include (with and without #) WTYPES.H (where _bstr_t is defined) and it seemed not to work (preprocessor error). How to declare it?
Another STRAAAAANGE thing is that it fails calling methods that has three int parameters... I know that native C types do not need to be marsaled, am I right?
i.e.:
theApp.m_pIHello->SetLocation (2,1,0)
seems to fail, where function prototype in server side is
STDMETHODTYPE CHardwareAsset::SetLocation (int Master, int slot, int SubAssy)
I put a statement to log on a file somw phrases just to know where the program goes and what it does, but when I call the method above, the server creates the object, but does NOT log the SetLocation Fu8nction (the logFile statement is the first, just before variable declaration!)
Very strange, isn't it? Or it's me that need to return to school and study a lot?
Thanks again...
|
|
|
|
|
Looks like the theApp.m_pHello object doesn't rightly store the transmitted BSTR strings inside.
BSTR strings should be stored by copying of the body, not the pointer.
HRESULT C::SetName(IN BSTR name) <br />
{<br />
m_nameSaved = name;
}<br />
<br />
HRESULT C::Add()<br />
{<br />
}
With best wishes,
Vita
|
|
|
|
|
OK, and that's what I did, but now that I think, I should do the same thing not only on client side, but also on server side....
I'll give it a shot, and I'll report how things went....
Thanks again...
|
|
|
|
|
I've been successfully using the MS Excel 9.0 object library for some time now to perform simple tasks manipulating excel. However I now only have the version 10.0 library available. I assumed there would be backwards compatibility but I am having issues. When refreing to cell contents I used to use .value but this seems to have disapeared in version 10 which only seems to have .value2???
Has anyone seen this issue before?
|
|
|
|
|
Hi,
I am writing an application which will work as client as Microsoft Netmeeting 3.0 using the interfaces exposed by NetMeeting SDK.
I have created a conference and hosted that. When i am getting the Sharable Application list through IEnumNmSharableApp::Next() API, I am getting all the running application handles in my machine and I am able to share the applications. I want to share my desktop, but I am not getting the handle to the running Desktop so that I can share the desktop. Is there any way I can get the handle to my desktop and share it so that any body joins the conference will be able to see my desktop.
Any help from any one will be highly appreciated.
Thanks & Regards
Shaini
|
|
|
|
|
Hi All,
I am implementing an MFC application which is using two COM DLL(say First.dll and Second.dll) files.
Both Dlls are having same coclass name and interfaces.Only their GUIDs are different.
To do the above, I have imported the tlb files for btoh the dlls i.e. A.tlb and B.tlb.
In the MFC application,I am using these interfaces like
CComPtr<isamename> m_pSameName;
m_pSameName.CoCreateInstance(__uuidof(SameName));
But the above was giving ambiguous error.To remove the error,I tried by importing type library without no_namespace attribute. And modified the above code to..
CComPtr<alib::isamename> m_pASameName;
m_pASameName.CoCreateInstance(__uuidof(SameName));
CComPtr<blib::isamename> m_pBSameName;
m_pBSameName.CoCreateInstance(__uuidof(SameName));
But this code appears that so much code to be in repetition as above.
Please suggest me to approach any better way to avoid these repetition.
Regards
jabhi1974
|
|
|
|
|
Maybe this work?
#import "A.tlb" named_guids
#import "B.tlb" named_guids
CComPtr<alib::samename> m_pASameName;
CComPtr<blib::samename> m_pBSameName;
...with the right names obviously
|
|
|
|
|
I am complete newbie in this field. I need to install DLL in MTS via VC++ 6.0 program. Any help is appreciable.
Thanks in advance.
|
|
|
|
|
What you mean.... you need to install the files in MTS via VC or you have build the COM in VC and want to install on MTS ?
any ways install the component on MTS and then export the package. which will give you the installation package for clients. which you can run to install on clients..run it through your VC program...
|
|
|
|
|
I want to perform all the steps of installation in MTS, exporting the package programmatically. Need a one-click go stuff.
|
|
|
|
|
well Pavneet I dont know exactly why you want to do this. What I used to do is the following
on my test machine I create a package in Transaction Server. then I export it as a server side package. Now this package can be installed on client and server both. So your setup is ready for transaction server for client. Now go to your Setup builder (install shield ,wise or dotnet built-in package builder ) and include this package to run at the end of the setup and give that package to client. when CLient will install the application the Components will be installed automatically with that. Why you want that client will install your application then he will get a new package from MTS to install on different machines.
if this helps you then great if not then wait for some one else who knows how to do this....
|
|
|
|
|