|
I'm putting together a project and need to extend Windows' shell to add a owner-drawn menu item to the context menu. If I use only IContextMenu, the menu item and owner-drawn (blank) sub menu are added fine.
As soon as I implement IContextMenu2 and HandleMenuMsg, I get a memfault from Explorer whilst debugging. A breakpoint is hit inside the IContextMenu2.HandleMenuMsg but subsequently, Explorer crashes. I'm returning "0" from int HandleMenuMsg(uint, IntPtr, IntPtr).
Any ideas?
--------------------------------
Extension code:
[ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), GuidAttribute("000214e8-0000-0000-c000-000000000046")]
public interface IShellExtInit {
[PreserveSig()]
int Initialize (IntPtr pidlFolder, IntPtr lpdobj, uint /*HKEY*/ hKeyProgID);
}
[ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), GuidAttribute("000214e4-0000-0000-c000-000000000046")]
public interface IContextMenu {
[PreserveSig()]
int QueryContextMenu(HMenu hmenu, int iMenu, int idCmdFirst, int idCmdLast, CMF uFlags);
[PreserveSig()]
void InvokeCommand(IntPtr pici);
[PreserveSig()]
void GetCommandString(int idcmd, uint uflags, int reserved, StringBuilder commandstring, int cch);
}
[ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), GuidAttribute("000214e4-0000-0000-c000-000000000046")]
public interface IContextMenu2 : IContextMenu {
[PreserveSig()]
int HandleMenuMsg(uint Msg, IntPtr LParam, IntPtr WParam);
[PreserveSig()]
new int QueryContextMenu(HMenu hmenu, int iMenu, int idCmdFirst, int idCmdLast, CMF uFlags);
[PreserveSig()]
new void InvokeCommand(IntPtr pici);
[PreserveSig()]
new void GetCommandString(int idcmd, uint uflags, int reserved, StringBuilder commandstring, int cch);
}
--------------------------------
Shell code:
public int QueryContextMenu(HMenu hmenu, int iMenu, int idCmdFirst, int idCmdLast, CMF uFlags) {
//
HMenu AppMenu;
Int32 NewMenuID = 1;
// Check Flags
if ((uFlags & (CMF.CMF_VERBSONLY|CMF.CMF_DEFAULTONLY|CMF.CMF_NOVERBS)) == 0 ||
(uFlags & CMF.CMF_EXPLORE) != 0) {
//
// Create Popup Menu
AppMenu = Helpers.CreatePopupMenu();
// Append SubMenus
Helpers.AppendMenu(AppMenu, MFMENU.MF_OWNERDRAW|MFMENU.MF_ENABLED,
new IntPtr(idCmdFirst + NewMenuID++), null);
Helpers.InsertMenu(hmenu, 3, MFMENU.MF_BYPOSITION|MFMENU.MF_POPUP|MFMENU.MF_ENABLED, AppMenu.handle, "MediaExplorer");
}
return NewMenuID;
}
#region IContextMenu2 Members
public int HandleMenuMsg(uint Msg, IntPtr LParam, IntPtr WParam) {
//
return 0;
}
#endregion
--------------------------------
>
|
|
|
|
|
I don't think you need the redefinitions of IContextMenu methods in there, they may be causing your the problem when it tries to marshal the interface. Even if your interface inherits another interface, in this case IContextMenu2 : IContextMenu, you don't redefine the members from the original interface.
Also, if i remember correctly, there is an entry on Raymod Kim's blog as well an anecdotal evidence that IContextMenu2 isn't very useful. The system checks for IContextMenu2 and if present then tries to use IContextMenu3, if that isn't present it falls back to the original IContextMenu. So you will need to implement the 3 interface for it to work i think.
I think your definitions of IContextMeuu are wrong as well. PreserveSig is used to prevent the signiture being changed because typically COM methods will return an HResult value. Your methods aren't returning HResult (or int) values and yet you've marked them with PreserveSig. Either remove the attribute or change the function definitions to match the definitions found in the header files exactly, otherwise i think you're either hiding errors or causing deeper problems which may not be apparent until the shell dies on you.
|
|
|
|
|
Thanks for the comments Wraith.
In the .NET SDK, the IContext Interface is specified as such:
// IContextMenu methods
[PreserveSig()]
int QueryContextMenu(uint hmenu, uint iMenu, int idCmdFirst, int idCmdLast, uint uFlags);
[PreserveSig()]
void InvokeCommand (IntPtr pici);
[PreserveSig()]
void GetCommandString(int idcmd, uint uflags, int reserved, StringBuilder commandstring, int cch);
That's where I got it from. I've repeated the interface methods in the implemented IContextMenu2 because I read several articles that stated the implemented interfaces in COM interop fail if you don't redefine the methods. Wierd I know.
I did have IContextMenu3 implemented as well but was receiving the same problem so I took it out to try and find which was causing the error. All implemented interface methods in my class receive notification (IShellExtInit.Initialize(), IContextMenu.QueryContextMenu() etc.) but the shell/explorer fails after having sent notification to IContextMenu2.HandleMenuMsg a few times.
I'll try implement IContextMenu3 as well.
Also, what should be returned from IContextMenu2.HandleMenuMsg()? 0? One of the params?
>
|
|
|
|
|
Can you privode a link, or tell me how to find that definition you used? Because it seems to be contrary to the documentation i've read. I also couln'dt find a useful implementation of IContextMenu and provided my own. While i cant claim its perfect i've not had any problems with the shell crashing in quite a while now so i think i'm at or close to a correct definition. I'd also be interested to see those articles, i've read around COM interop articles a bit lately and i've not found any that specifically mentioned the redefinition argument.
IContextMenu2.HandleMenuMsg is defined as
HRESULT HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam);
In c# i'd probably make that
[PreserveSig] int HandleMenuMsg(uint uMsg, IntPtr wParam,IntPtr lParam);
though of course i'd have to look up the header definitions of LPARAM and WPARAM to be certain of their size/type. Without PreserveSig that would return void instead of int and if you have an error you'll have to throw an exception with an hresul generated using the Marshal class functions.
In my limited experience if you do something wrong with your marshalling you end up corrupting the shell memory and eventually it'll either start to behave very oddly or it'll just crash unexpectedly.
|
|
|
|
|
|
Interesting, Mattias Sjögren is very knowledgable about these things. I've come across posts of his many times.
The first thing that struck me was that the order of your methods doesn't match the example at the end of the discussion. COM methods have a defined order, if you change the order it won't work so well. If you look at the c or c++ definitions of the itnerfaces in the PSDK you'll find the correct order to use, this is also usually the order used in the documentation but its always worth checking to make sure. Make sure they are in the order IUnknown (implicitly added so don't bother), IContextMenu, IContextMenu2.
I'm no expert on COM, the shell interfaces are really my first try, but i've picked up a few things on the way through the docs. I think i'm being lucky and a bit cheeky with my definitions and that its working because the COM interop has to interpret the exported methods into a vtable rather than building it at compile time. I'm going to have a tinker with IContextMenu2 and IContextMenu3 and see what happens later. I do remember reading an article (possibly here ar codeproject) which states that you don't have ti implement inherited interfaces in the using interface but i'm more certain that Mattias is correct.
|
|
|
|
|
WRT the ordering, if I put HandleMenuMsg at the bottom of the decleration, it doesn't receive windows messages.
>
|
|
|
|
|
But does it crash? Because not getting any messages may be the correct behavior while crashign certainly isn't.
|
|
|
|
|
The method should receive a call when the context menu is activated via explorer. When it does receive a call, it receives the Msg, LParam and WParam no problems, but crashes shortly thereafter with a memory fault (explorer.exe - Application Error. Instruction at "0x78312aa5" referenced memory at "0x00000028". Memory could not be "read".) and subsequently shuts down the explorer window (not the process).
>
|
|
|
|
|
Personally i define crashing as an error condition, and one of the bigger ones as well. I realize that HandleMenuMsg should be called but it should also not cause the hosting application to crash. If you look at the definitions of ContextMenu, 2 and 3 in ShlObj.h the methods are specified in a specific and exact order. When the runtime interop does its work it doesn't have a lookup table of method names, it puts the methods in the order they are in the class/interface. If you've got them in the wrong order they wrong method could be called.
Put them in the right order and then go back and read through what is required for IContextMenu2 to run, perhaps a precondition isn't being met, perhaps a marshalling error is occuring before your function body is reached. Perhaps it is wrong in some way, but at least you'll know that the right method is being called with the right parameters at the right time if it ever is called.
|
|
|
|
|
I need to create mpeg or some other video format from sequence of pictures in jpeg or bmp format. Could somebody point me to good tutorial about this or give me advice about proper library to use under .Net Thanks
Salut!
|
|
|
|
|
|
how to use the multithreading concept in an MDI form
Titli
|
|
|
|
|
Your going to have to be ALOT more specific about what you want. All you've done so far is ask "How to use a knife in the kitchen?".
What do you want these other threads to do?
RageInTheMachine9532
"...a pungent, ghastly, stinky piece of cheese!" -- The Roaming Gnome
|
|
|
|
|
Is there any way to get the value of a Paragraph Leading? i.e. the distance between two consecutive (base) lines of an RTF page?
please guide
|
|
|
|
|
I think my question was not giving the entire information.
I want to find the way to get Paragraph leading when any image is inserted in the page. In my case if I insert images in consecutive lines irrespective of image height the distance between two images remains same. Where as it differs in case of text, if font size is changed.
I want to fetch the paragraph leading in case of image, to calculate exact base line to base line height for page layout purpose. In case of normal text, Font.Height solves my purpose.
regards
|
|
|
|
|
I have several text files with 150,000 unique English words that I want to INSERT INTO an MDB file that has a table for words with 3 letter, 4 letter, 5 and so on.
I've scoured MSDN and all my printed C# documentation but can not find an example of what the correct syntax is.
There are 4 files Nouns, Verbs, Adjectives and Adverbs.
Here is what the beginning of the Nouns file looks like:
entity
thing
anything
something
nothing
nonentity
whole
wholething
unit
livingthing
animatething
organism
being
benthos
heterotroph
life
biont
cell
causalagent
I've got about 20 hours into this and the C# code invariably boinks on a sytax error in the INSERT INTO command.
I would appreciate any leads that someone could contribute.
Thank you very much,
Bill Prada
bprada@comcast.net
Best Regards,
Bill Prada
|
|
|
|
|
bprada wrote:
C# code invariably boinks on a sytax error in the INSERT INTO command.
Well, you show us the list of words, but not the INSERT command.
But it should look like this:
OleDbCommand cmd = new OleDbCommand("INSERT INTO Table3Letters VALUES (?);", conn);
cmd.Parameters.Add("@param1", strMy3LetterWord);
cmd.ExecuteNonQuery();</code> Good luck!
Check the syntax of the INSERT statement here[^].
-- LuisR
Luis Alonso Ramos
Intelectix - Chihuahua, Mexico
Not much here: My CP Blog!
|
|
|
|
|
Thanks for the quick response.
Here is a snippet:
I've read the text word and am trying to put a one Char string in each field.
switch (nCharCount)
{
case 3:
cmd.CommandText = "INSERT INTO 3 VALUES ca[0], ca[1], ca[2]";
cmd.ExecuteNonQuery();
break;
case 4:
cmd.CommandText = "INSERT INTO 4 VALUES ca[0], ca[1], ca[2], ca[3]";
cmd.ExecuteNonQuery();
break;
case 5:
cmd.CommandText = "INSERT INTO 5 VALUES ca[0], ca[1], ca[2], ca[3], ca[4]";
cmd.ExecuteNonQuery();
break;
case 6: /* The first word in Nouns.txt has 6 letter so I am trying different thinggs here */
try
{
OleDbDataAdapter myAdapter = new OleDbDataAdapter();
DataSet ds = new DataSet("six");
myAdapter.Update(ds, "C:\\Keep\\Gloss\\Working Data\\Gloss.mdb.6");
cmd.CommandText = "INSERT INTO '6' (1, 2, 3, 4, 5, 6) VALUES ('cA[0].String()', cA[1].ToString(), cA[2].ToString(), cA[3].ToString(), cA[4].ToString(), cA[5].ToString()";
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
break;
I hope this shows what I am doing wrong
Best Regards,
Bill Prada
|
|
|
|
|
From that code, I suppose your tables have one field for each character (so, the 3-char-words table has 3 fields).
Your INSERT commands, in cases 3, 4 and 5, are missing parenthesis:
INSERT INTO Table VALUES <big><big><big><big>(</big></big></big></big>field1, field2, ...<big><big><big><big>)</big></big></big></big>; -- LuisR
Luis Alonso Ramos
Intelectix - Chihuahua, Mexico
Not much here: My CP Blog!
|
|
|
|
|
bprada wrote:
cmd.CommandText = "INSERT INTO 3 VALUES ca[0], ca[1], ca[2]";
And also, the ca[n] are variables, so you should put them out of the string literal, and since their data type is char , enclose them in single quotes in the SQL statement:
cmd.CommandText = "INSERT INTO 3 VALUES ('" + ca[0] + "','" + ca[1] + "','" + ca[2] + "')"; But I don't recommend string concatenation as it is any easy way to allow SQL-injecton attacks. So I'd use the Parameters property of the OleDbCommand as I mentioned in my first post:
OleDbCommand cmd = new OleDbCommand("INSERT INTO 3 VALUES (?, ?, ?);", conn);
cmd.Parameters.Add("@param1", ca[0]);
cmd.Parameters.Add("@param1", ca[1]);
cmd.Parameters.Add("@param1", ca[2]);
cmd.ExecuteNonQuery(); And by the way, in your case 6, you also need to change your SQL statement so you take your variables our of the string literal (or better yet, use parametized queries.)
-- LuisR
Luis Alonso Ramos
Intelectix - Chihuahua, Mexico
Not much here: My CP Blog!
|
|
|
|
|
hi,
basically I am a VB/ASP developer, and I am poor in OOP's concepts. I just started learning C#, and when I am trying to execute my first C# program which i got in one book, after execution it is not returning any line to out put screen. plz help me in this.
CODE:
<br />
using System;<br />
<br />
namespace Wrox.ProCSharp.Basics<br />
{<br />
class MyFirstCSharpClass<br />
{<br />
static void Main()<br />
{<br />
Console.WriteLine("This isn't at all like Java!");<br />
Console.ReadLine();<br />
return;<br />
}<br />
}<br />
}<br />
nagarajuepuri
|
|
|
|
|
Check if you created a console application or a windows application. On project properties, check "Output Type", and set it to "Console Application".
If you set it to "Windows Application", it will have no console and all your Console.WriteLine will be ignored.
Yes, even I am blogging now!
|
|
|
|
|
Thanks for you intrest...
actually, i didn't get you exactly.
I have written this code in a text file and saved it with .CS extension, then i have executed this "sample.cs" file through command line like....
"csc sample.cs"
Here i am not at all creating any application nor project, i am executing all my code through command line only.
thanking you in advance,
nagarajuepuri
|
|
|
|
|
You've only compiled the program, you need to execute it. By default, the executable is placed in the same directory where you compiled it and is named after the source file you compiled. So go to the directory where you compiled and run sample.exe .You'll see the output.
Regards
Senthil
|
|
|
|
|