|
My COM object is not implemented as an STA.
so if it's marshalling, what can I do? (I know there probably isn't a short answer)
thanks.
|
|
|
|
|
Instead of importing the typelib automatically, you may have to define your own interface in .NET (that which reflects the class interface of your OCX), putting the appropriate marshaling attributes (MarshalAsAttribute ). See that class (and the System.Runtime.InteropServices namespace for more details (and it'd be good to take a quick glance before proceding).
Question, though. Are you trying to pass the first byte array element as a reference, or do you want to pass the entire array. The way you're doing it means that you're passing the address of the first element and this will definitely requiring marshaling. If you want to pass the whole array as a ref, use ref myByteArray as a parameter instead. .NET will take care of a lot of things for you, including stuff like this.
-----BEGIN GEEK CODE BLOCK-----
Version: 3.21
GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++
-----END GEEK CODE BLOCK-----
|
|
|
|
|
I want to pass the entire array, but what data type will my COM object be expecting if I pass ref bytearray ?
right now, the prototype for my COM method is:
STDMETHODIMP CUSB::WriteSPI(unsigned char* datain, int size)
so, when C# gets a hold of that, it takes the pointer as a ref byte
in other words, what is the C++/COM equivalent of a ref to an array?
|
|
|
|
|
First, an array is always a reference type. While some examples use ref with arrays, it's really only necessary for value types (int , long , byte , etc.) Passing a reference type results in the address passed to the native function.
For your interface, though, you'd want to write your method to that functions like so:
[Guid("...")]
public interface IUSB
{
void WriteSPI(
[MarshalAs(UnmanagedType.LPArray,SizeParamIndex=1)]byte[] array,
int size);
} This will marshal the array as the address to the first element, which is what you're wanting to do.
-----BEGIN GEEK CODE BLOCK-----
Version: 3.21
GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++
-----END GEEK CODE BLOCK-----
|
|
|
|
|
I understand, but C# still sees the unsigned char* from my COM method as a ref byte so how can I get around that?
sorry to keep bugging you.
|
|
|
|
|
Hmm, it's usually right...but not always the easiest to implement. It would make sense, since ref'ing the first element would return the address of the array, but as you can see...it's not working.
What I was referring to was actually defining the interface yourself and not using the interop assembly that's generated automatically. Especially for small typelibs or for typelibs which you only need a couple of things (like many do for mshtml's typelib), it's just easier defining the interface with the right attributes and method placements (for IUnknown interfaces, order of the methods is important; for IDispatch interfaces, using the DispIdAttribute with the correct ID is important). You can still instantiate the COM object through the interop, or derive a class from AxHost and override the necessary things, also implementing your interface, or using various methods in the Marshal class or Type class, and set the reference to a variable defined as your class interface. Access the methods from the interface (as in all COM you should, anyway).
Still, though, that method signature should be right. When you say jibberish, what exactly do you mean?
-----BEGIN GEEK CODE BLOCK-----
Version: 3.21
GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++
-----END GEEK CODE BLOCK-----
|
|
|
|
|
When I said it was putting out garbage data, when I call
WriteSPI(dataarray, size) I was looking at the output in bytes and I would get:
00 00 AA 00 size 00 ...
so the size value was being sent in the part that was supposed to be the data, the first three bytes of data was always the same though, no matter what I sent.
Are you saying that I can write a separate interface for my COM object in C#, that will override the one that was automatically generated when I compiled the C++ code for the COM object?
If so, I didn't realize you can do that. If I specify the GUID as an attribute for the object, it will be able to find it?
hmmmm...
|
|
|
|
|
This definitely sounds like a marshaling problem. Seems like data about the array is being sent when you want the array data since the bytes should be the same on both.
You shoud read Advanced COM Interop in the MSDN Library. Basically, you're interface is just a way to access the class. In COM, you treat every object through it's interface by QI'ing (QueryInterface) for the interface that the class implements. In .NET this is acheived by merely casting.
You can define the interface in your project regardless of what is in the interop assembly, yes. As long as the method signatures are marshalable and similar (proper number of params) and use the same return types (should all be void unless PreserveSignature is true , which then you use int to represent an HRESULT). Just instantiate your COM class and cast it to the interface you redefined (remember, use the same GUID for the interface in the GuidAttribute and keep all that stuff the same I said in the previous post) and you should have a valid reference to your object through that interface (again, it's like calling QI, which doesn't care about qualified names like .NET does).
I'm not sure I'm explaining this as easily as possible, but read that section in MSDN (or perhaps start with the more basic stuff that comes before it). COM interop is powerful but is also is a beast to tame.
-----BEGIN GEEK CODE BLOCK-----
Version: 3.21
GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++
-----END GEEK CODE BLOCK-----
|
|
|
|
|
okay, I get it...
Thanks a lot for your help.
just one last question, for my new interface, do I use the GUID from the COM interface or from the COM class itself?
that's it, I swear.
thanks again.
Jesse
|
|
|
|
|
The interface.
-----BEGIN GEEK CODE BLOCK-----
Version: 3.21
GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++
-----END GEEK CODE BLOCK-----
|
|
|
|
|
arrrrrgggggghh...
Using the interface works fine, except when it is in my new thread.
damn.
|
|
|
|
|
Hi
In my Application I can't set the AllowDrop Property of any component to true. I allways get the runtime error Drag&Drop registration failed.
My application is an MDI Container with two ListViews ,one TreeView and a login-window, that is loaded the actual Form.
The error also happends, when I try to load an MDI Child with a ListView and the AllowDrop Property on true.
I am not so long in C# so maybe I just missed some important detail. But I can't find it.
Thanks for your help
|
|
|
|
|
This is a threading problem. "Drag&Drop" registration includes a call to OleInitialize , which must be called on an STA (which all processes should be anyway). What does this mean? Well, first take a look at the STAThreadAttribute . Apply that to your entry point (Main ). Second, and in some cases*, you may have to call Thread.CurrentThread.ApartmentState = ApartmentState.STA before calling Application.Run (starts your application message pump):
public class MyApp : Form
{
private MyApp()
{
}
[STAThread]
public static void Main()
{
Thread.CurrentThread.ApartmentState = ApartmentState.STA;
Application.Run(new MyApp());
}
} * Those rare cases happen when the application is invoked in an MTA, like Internet Explorer invoking the app via IEExec.exe for Internet-deployed, touchless installations. The STAThreadAttribute does not seem to affect the runtime, so I had to include that one-liner hack.
-----BEGIN GEEK CODE BLOCK-----
Version: 3.21
GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++
-----END GEEK CODE BLOCK-----
|
|
|
|
|
Thank you. Now it works.
|
|
|
|
|
Hello, Sir
I have two ImageList and two ImageIndex as the code below.
My problem is indexA and indexB show the same list of images.
How to make the indexA show list of image in _imagelistA
and make the indexB show list of image in _imagelistB ?
Thank You.
Sorry for bad English.
public ImageList imagelistA
{
get { return _imagelistA;}
set { _imagelistA = value; }
}
[TypeConverter(typeof(ImageIndexConverter)), Editor("System.Windows.Forms.Design.ImageIndexEditor, System.Design,Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",typeof(System.Drawing.Design.UITypeEditor))]
public int indexA
{
get { return _indexA; }
set { _indexA = value; }
}
public ImageList imagelistB
{
get { return _imagelistB;}
set { _imagelistB = value; }
}
[TypeConverter(typeof(ImageIndexConverter)), Editor("System.Windows.Forms.Design.ImageIndexEditor, System.Design,Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",typeof(System.Drawing.Design.UITypeEditor))]
public int indexB
{
get { return _indexB; }
set { _indexB = value; }
}
|
|
|
|
|
If you mean in code, simple:
Image imgA = imageListA.Images[indexA];
Image imgB = imageListB.Images[indexB]; If you mean through the designer, you'll have to create your own TypeConverter (or derive from ImageIndexConverter ) and return the image indeces from the currect ImageList , meaning that you'll have to use two separate TypeConverter s.
See the docs about the TypeConverter.GetStandardValues method for clues on how to do this, or take a look at System.Windows.Forms.ImageIndexConverter through some disassembler (like ildasm.exe that comes with the .NET Framework SDK) or decompiler (like .NET Reflector).
-----BEGIN GEEK CODE BLOCK-----
Version: 3.21
GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++
-----END GEEK CODE BLOCK-----
|
|
|
|
|
How do I catch windows messages in c#??
In MFC, I would do this:
// to catch windows messages
MSG msg;
while( PeekMessage( &msg,NULL,0,0,PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
Thanks.
|
|
|
|
|
Within the application context, see the documentation for IMessageFilter . This installs a filter that allows you to process messages before they are dispatch from the pump.
For all applications (and a myriand of other things), you can install a Windows hook using a P/Invoked SetWindowsHookEx (and there is one or two articles about this on CP, posted just last month) but I doubt that's what you meant (just thought I'd throw in that many "old" ways are still possible).
-----BEGIN GEEK CODE BLOCK-----
Version: 3.21
GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++
-----END GEEK CODE BLOCK-----
|
|
|
|
|
in c# u can override WndProc methode of ur component.
for example u want to catch the WM_CHAR message:
<br />
private const int WM_CHAR = 0x0102<br />
<br />
protected override void WndProc(ref Message m) <br />
{<br />
switch (m.Msg)<br />
{<br />
case WM_CHAR:<br />
break; <br />
}<br />
base.WndProc(ref m);<br />
}<br />
good luck, i think it helps you to solve ur problem .
|
|
|
|
|
i want that by clicking on the button, it does not get the focus.
does any WM_message exist witch will be send wenn a component gets the focus?
|
|
|
|
|
This is the C# forum and, therefore, for .NET programming. Forget Windows messages when possible. Use the GotFocus event and set the focus to something else (you can't cancel it this way). If you just want to cancel focus, you can derive from Button and do several things, like call the protected method SetStyle such as:
public class MyButton : Button
{
public MyButton()
{
this.SetStyle(ControlStyles.Selectable, false);
}
} You could also override CreateParams and use a redefined BS_NOTIFY to remove that style from the button:
public class MyButton : Button
{
private const int BS_NOTIFY = 0x4000;
public MyButton()
{
}
protected override CreateParams CreateParams
{
get
{
System.Windows.Forms.CreateParams cp = base.CreateParams;
cb.Style &= ~BS_NOTIFY;
return cb;
}
}
}
-----BEGIN GEEK CODE BLOCK-----
Version: 3.21
GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++
-----END GEEK CODE BLOCK-----
|
|
|
|
|
thank u that is that i need LOL
|
|
|
|
|
Thanks, oOoman for the question! Thanks, Heath, for the answer.
I stumbled on the first solution (GotFocus) after fighting with the system. in fact it turns out to be unreliable, i end up using Validating and Leave events (not that i really know why, just the docs describe what the sequencing is and these events seem to occur when you think the focus events should!).
The VS system and its documentation is overall wonderful for designing UI, but inappropriate focus is bound to be a source of wasted days for people learning-- Heath, your post ought to be included in every tutorial!
", and Toto too."
(reassurance by Glenda, the good witch of the North)
|
|
|
|
|
i am happy that it was useful for u too
|
|
|
|
|
and where can i find the values of all BS_constants?
|
|
|
|
|