|
Hi Stewart,
Didn't mean to hold anything relevant back from the doctor...
However, I thought that the concept was clear...
Anyway, I was looking for an example of such implementation or a concrete referecne to some place I can get.
BTW - if I declare an "event" in my C# object - would that be interpreted by the tlb and C++ client as a "Connection Point" interface?
Thanks
|
|
|
|
|
No, you need to specify an interface that defines those events, which is described in the documentation for the ComSourceInterfaceAttribute that I mentioned previously.
For an example of use, see an old article of mine, User Controls for Windows and the Web[^]. In that article I use an event interface so that script (in the web page) can add a handler for an event exposed by my Windows UserControl that is hosted within the web page (like an ActiveX control or Java applet).
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
Hi Stewart,
I've been playing around today with my code, and got to a point which I could not pass.
My Server code looks like this:
namespace C_Sharp_DLL
{
// The event arguments class
[Serializable]
[Guid("C1BD9A0C-B6D1-4170-A60C-384857C3F84E")]
public class OnChangeEventArgs
{
private string m_msg;
public string Message
{
get {return m_msg;}
set {m_msg = value;}
}
}
public delegate void OnChangeEvent (OnChangeEventArgs onChangeEventArgs);
[Guid("F4A9D17D-6913-4b0a-A635-C5D6F8B1BD62")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsDual)]
public interface ITestInterface
{
int Test1(string sString);
event OnChangeEvent OnNotifyEvent;
void Notify(string msg);
}
[Guid("0A7F4E0F-59D4-4f59-8DFC-E71F76C96C76")]
[ComSourceInterfaces(typeof(ITestInterface))]
public class Test : ITestInterface
{
public Test()
{
}
int ITestInterface.Test1(string sString)
{
Console.WriteLine("Receive paramter in Test1 : " + sString);
return 1;
}
public event OnChangeEvent OnNotifyEvent;
void ITestInterface.Notify(string msg)
{
OnChangeEventArgs args = new OnChangeEventArgs();
args.Message = msg;
OnNotifyEvent.BeginInvoke(args, null, null);
}
}
}
while my C++ client code looks like:
int main (void)
{
try
{
CoInitialize(NULL);
HRESULT hr;
ITestInterface * pITestInterface = NULL;
hr = CoCreateInstance(CLSID_Test,
NULL,
CLSCTX_ALL,
IID_ITestInterface, reinterpret_cast<void**>(&pITestInterface));
if (FAILED(hr))//REGDB_E_CLASSNOTREG
{
_com_error COMError(hr);
printf (COMError.ErrorMessage());
printf(" Couldn't create the instance!... 0x%x\n", hr);
printf("Failed to create COM Class");
}
else
{
bstr_t s = "1234";
i = pITestInterface->Test1(s);
}
IConnectionPoint * p1 = NULL;
IConnectionPointContainer* pIConnectionPointContainerTemp = NULL;
IUnknown* pIUnknown = NULL;
/*QI this object itself for its IUnknown pointer which will be used */
/*later to connect to the Connection Point of the ISomeInterface object.*/
/* QI pISomeInterface for its connection point.*/
<==this is always succeeds (i.e. not NULL)
pITestInterface -> QueryInterface (IID_IConnectionPointContainer,
(void**)&pIConnectionPointContainerTemp);
if (pIConnectionPointContainerTemp)
{
pIConnectionPointContainerTemp->
FindConnectionPoint(__uuidof(ITestInterface),
&p1); <==this is always returns as NULL
pIConnectionPointContainerTemp -> Release();
pIConnectionPointContainerTemp = NULL;
}
if (p1)
{
//m_pIConnectionPoint -> Advise(pIUnknown, &m_dwEventCookie);
}
//pIUnknown -> Release();
//pIUnknown = NULL;
//
CoUninitialize();
}
catch (_com_error e)
{
printf("%s", e.ErrorMessage());
return 0;
}
catch(...)
{
long lErrorCode;
lErrorCode = GetLastError();
printf("Fatal error");
return 0;
}
return 1;
}
Can you try and point me where can the problem possibly be?
Why does FindConnectionPoint always fail while
pITestInterface -> QueryInterface (IID_IConnectionPointContainer,
(void**)&pIConnectionPointContainerTemp);
succeeds?
Thnks...
|
|
|
|
|
You don't actually implement the event source. Read Raising Events Handled by a COM Sink[^], and pay close attention to "Handling and Raising Events" which discusses events for managed code. I mention that last part only because your event naming convention isn't "correct". Being consistent is important. Besides, events in COM should begin with "On", and you'll almost never see this (except for MSHTML, but only because of the way it works with script). To handle that event in VB (6 and below), you'd have a handler called "OnOnNotifyEvent". You also shouldn't end the event name with "Event".
The guidelines are quite clear on this and are similar to what's recommended and common for COM, as well (since .NET is a natural progression of COM). Read the Naming Guidelines[^] for more information.
The times you will see "On" in COM is when you're not dealing with connection points, but with sinks like I mentioned before, which you were leaning to originally. In that case you're not actually sinking a connection point but calling a method on the sink. It's similar in nature, but you handle the sink a little differently than a connection point (the overall behavior is the same, however).
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
So I'm trying to access MS-Word's spell checker. However I won't know which version of word is install on the clients computer. So I'm using late binding to access the com interface.
So far I have been able to create a document. Get a reference to the application and call the GetSpellingSuggestions.
After calling GetSpellingSuggestions with "noow", I see that the count for the SpellingSuggestions is 4, which is correct.
My question is how do I access the SpellingSuggestions collection.
Using a BindingFlags.GetProperty I get a "'Item' is not a property"
Using a BindingFlags.InvokeMethod and passing the index as an argument, I get "Invalid number of parameters."
Any help would be greatly appreciated.
Here is the code I'm using.
<br />
using System;<br />
using System.Reflection;<br />
using System.Collections;<br />
<br />
namespace spellcs<br />
{<br />
class Class1<br />
{<br />
public static void Main()<br />
{<br />
object M = Type.Missing;<br />
object obj = null;<br />
<br />
Type oType = Type.GetTypeFromProgID("Word.Document");<br />
if(oType != null)<br />
{<br />
obj = Activator.CreateInstance(oType);<br />
}<br />
<br />
Console.WriteLine(obj.GetType().ToString());<br />
<br />
object[] args = new object[12];<br />
args[0] = M;<br />
args[1] = true;<br />
args[2] = true;<br />
args[3] = M;<br />
args[4] = M;<br />
args[5] = M;<br />
args[6] = M;<br />
args[7] = M;<br />
args[8] = M;<br />
args[9] = M;<br />
args[10] = M;<br />
args[11] = M;<br />
<br />
oType.InvokeMember("CheckSpelling",BindingFlags.InvokeMethod, null, obj, args);<br />
<br />
object oApp = oType.InvokeMember("Application", BindingFlags.GetProperty,null, obj,null);<br />
<br />
Type tApp = oApp.GetType();<br />
<br />
object list= null;<br />
object Count = null;<br />
try<br />
{<br />
<br />
list = tApp.InvokeMember("GetSpellingSuggestions",BindingFlags.InvokeMethod,null, oApp, new object[]{"noow", M, true, M, M, M, M, M, M, M, M, M, M});<br />
Count = list.GetType().InvokeMember("Count", BindingFlags.GetProperty, null, list, null);<br />
<br />
<br />
Console.WriteLine(Count);<br />
for(int i = 0; i < (int)Count ; i++)<br />
{<br />
object[] args2 = new object[] {0,0};<br />
<br />
object word = list.GetType().InvokeMember("Item",BindingFlags.Default | BindingFlags.InvokeMethod | BindingFlags.Instance, null, list, null);<br />
Console.WriteLine(word.ToString());<br />
}<br />
<br />
}<br />
catch(Exception e)<br />
{<br />
Console.WriteLine(e.Message);<br />
if(e.InnerException!=null)<br />
Console.WriteLine(e.InnerException.Message);<br />
<br />
Console.WriteLine(e.GetType().ToString());<br />
}<br />
<br />
Console.ReadLine();<br />
<br />
tApp.InvokeMember("Quit",BindingFlags.InvokeMethod,null, oApp,new object[]{0,0,false});<br />
}<br />
}<br />
}<br />
|
|
|
|
|
The fact that you're using a COM interop assembly generated from a typelib already means your accessing Word through it's IDispatch pointers, i.e. you're already late-binding to Word.
If you want to automate Word and its tools in such a manner, create an interop library (using tlbimp.exe or creating a managed reference from the COM tab for your project) from the oldest typelib you want to support. You can also use a newer typelib but this could lead to problems if you use any newer interfaces.
This is how COM is supposed to work when implemented correctly, and Office is a shining example of COM best practices. So long as you never changed published interfaces or the CLSIDs of classes, automation clients will continue to work for newer automation servers.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
Now that makes sense. I was developing on my laptop with that has office 2003 and then trying it on a machine with office 2000. For some reason I thought to use the interop would require finding a way to determine with one to use lib to use at runtime.
Thanks for the info. I'll try it out.
Darren
|
|
|
|
|
Heath...
That worked perfectly. I'm using a typelib from word 2000 and it also works with XP and 2003.
Thanks again.
Darren
|
|
|
|
|
Hi
how i can send an email from my computer to an email address on yahoo ??? or any where?
it means that i dont know some parameters of SMTP ' QuickSend method like
"SMTPServerName".
thanks.
|
|
|
|
|
For the uninformed, QuickSend and SMTPServerName are both API calls in Quiksoft STMP email API for .NET.
WDI, e-mails are sent using an SMTP mail server. If you're running Windows XP Pro, a mail server is built into the machine. Typically, the address of an SMTP server is something like smtp.provider.com -- you can use your XP Pro machine to be the mail server for you, or use an existing mail service, or one provided by your ISP; either case you need to get the smtp mail address for the mail service you want to use for sending your email.
Any remotely useful information on my blog will be removed immediately. There are 10 kinds of people in the world. Those who have heard of the ubiquitous, overused, worn-out-like-an-old-shoe binary "joke" and those who haven't.
Judah Himango
|
|
|
|
|
A CDO client is included with Win2K and above, and you can install the Virtual SMTP Service for IIS in Pro/eHome, but it is not there by default. It can be added easily enough through Add/Remove Programs, but many people have trouble configuring it especially when it comes to forwarding to an outgoing SMTP host that accepts forward from their "domain".
SMTP connections can often be - except when blocked by firewalls - made from your local machine directly, rather than forwarding to another SMTP host. To the original poster, if you click "Search comments" and search for "SMTP" you can find many messages related to sending emails yourself.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
Hi
I've written my own VNC Client using classes from cdot.senecac.on.ca/projects/vncsharp/
It works fine!
But I got one Problem!
I need a solution to expand the Contxt Menu that opens when you click
right on the Title bar from the Windows Form. It shows only 'Close',
'Minimize' etc.. It's the same Dialog when a Form is minimized to the Task bar.
In the Form Propertys I found no answer. Where is it anchored?
Thx from Germany!!
|
|
|
|
|
|
But there's just two values. True or false..How can I change the ContextMenu.
Or how can I add something to the ContextMenu??
thx
|
|
|
|
|
|
Hi!
Unfortunately, you can't do this with built-in properties.
You'll have to use P/invoke and override WndProc, but that's not too hard and works well.
There's even an article here on CP: Customizing WinForm's System Menu[^]
Best regards from Germany as well
mav
|
|
|
|
|
That is exactly what I'm looking for!
|
|
|
|
|
does any one know how to workaround the memory issues with the tree view web control.
|
|
|
|
|
1. What memory issues? (link would help)
2. What is the tree view web control? (link would help)
Any remotely useful information on my blog will be removed immediately. There are 10 kinds of people in the world. Those who have heard of the ubiquitous, overused, worn-out-like-an-old-shoe binary "joke" and those who haven't.
Judah Himango
|
|
|
|
|
3. Why are you posting here? Questions about ASP.NET development - despite what language you're using unless it's a language-specific problem - belong in the ASP.NET forum.
If you're referring to the Microsoft IE TreeView[^] you may have better luck in the Internet Explorer Web Controls[^] forum on http://asp.net[^], which exists soly for support of the IE WebControls.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
|
does any one know how to workaround the memory issues with the tree view web control.
|
|
|
|
|
I can create a singleton class that shares a single of a class within a application.. does anyone know how to approach sharing between application. Would I have to use serilzation to achieve this.. does anyone have examples..
Sk8tZ
|
|
|
|
|
Sharing between applications -- sharing a variable across applications? If this is the case, and both applications are .NET apps, you should look at .NET remoting (System.Runtime.Remoting). What you would do is extract an interface from the class you want to share. Give that interface to both applications. Have the class you want to share implement that interface and inherit System.MarshalByRefObject or be [Serializable]. Then from application with the shared class, call RemotingServices.Marshal(mySharedClassInstance, ...) and have the other application call RemotingServices.Connect(...) which will return the shared object. Cast it to the interface your previously created and VOILA, you've just shared a class instance across application boundaries.
Any remotely useful information on my blog will be removed immediately. There are 10 kinds of people in the world. Those who have heard of the ubiquitous, overused, worn-out-like-an-old-shoe binary "joke" and those who haven't.
Judah Himango
|
|
|
|
|
See I want to make a bar that behaves like a splitter bar and yet leave no frames.For example I made a panel and dock it to the left.then a splitter bar docking to left.Then another panel dock set to fill.Now the problem is when i moved the splitter bar it leaves frames of itself(one trailing with the mouse and the other stayed back at the original position).But I don't want those frames.Is there any way to do this.
Thanks in advance.
just.starting...
|
|
|
|
|