|
You need to use COM interfaces to create a shell menu item handler. The interfaces you'll need are
[ComImport(),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
GuidAttribute("000214e8-0000-0000-c000-000000000046")]
internal interface IShellExtInit
{
[PreserveSig()]
int Initialize (IntPtr pidlFolder, IntPtr lpdobj, uint hKeyProgID);
}
[ComImport(),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
GuidAttribute("000214e4-0000-0000-c000-000000000046")]
internal 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);
}
You'll create a class that implements both interfaces. Your class will need a Guid attribute so it can be registered as a COM object with the shell.
The menu code you'll need will be similar to this
int IContextMenu.QueryContextMenu(HMenu hMenu, int iMenu, int idCmdFirst, int idCmdLast, CMF uFlags)
{
StringBuilder sb = new StringBuilder(1024);
uint selected = Helpers.DragQueryFile(_hDrop, 0xffffffff, null, 0);
if(selected > 0)
{
_fileArray = new string[(int)selected];
for(uint i = 0; i < selected; i++)
{
Helpers.DragQueryFile(_hDrop, i, sb, sb.Capacity + 1);
fileArray[i] = sb.ToString();
}
}
int id = 1;
if ( (uFlags & (CMF.CMF_VERBSONLY | CMF.CMF_DEFAULTONLY | CMF.CMF_NOVERBS)) == 0 || (uFlags & CMF.CMF_EXPLORE) != 0)
{
HMenu submenu = Helpers.CreatePopupMenu();
Helpers.AppendMenu(submenu, MFMENU.MF_STRING | MFMENU.MF_ENABLED, new IntPtr(idCmdFirst + id++), "Custom Sub Item 1");
Helpers.AppendMenu(submenu, MFMENU.MF_STRING | MFMENU.MF_ENABLED, new IntPtr(idCmdFirst + id++), "Custom Sub Item 2");
Helpers.InsertMenu(hMenu, 7, MFMENU.MF_BYPOSITION | MFMENU.MF_POPUP | MFMENU.MF_ENABLED, submenu.handle, "My Item");
}
return id;
}
void IContextMenu.GetCommandString(int idCmd, uint uFlags, int pwReserved, StringBuilder commandString, int cchMax)
{
switch((GCS)uFlags)
{
default:
break;
}
}
void IContextMenu.InvokeCommand(IntPtr pici)
{
try
{
Type typINVOKECOMMANDINFO = Type.GetType("My.Full.Namespace.INVOKECOMMANDINFO");
INVOKECOMMANDINFO ici = (INVOKECOMMANDINFO)Marshal.PtrToStructure(pici, typINVOKECOMMANDINFO);
switch (ici.verb - 1)
{
case 0:
MyMethod();
break;
case 1:
MyOtherMethod();
break;
}
}
catch
{
}
}
int IShellExtInit.Initialize(IntPtr pidlFolder, IntPtr lpdobj, uint hKeyProgID)
{
try
{
_dataObject = null;
if (lpdobj != (IntPtr)0)
{
_dataObject = (IDataObject)Marshal.GetObjectForIUnknown(lpdobj);
FORMATETC fmt = new FORMATETC();
fmt.cfFormat = CLIPFORMAT.CF_HDROP;
fmt.ptd = 0;
fmt.dwAspect = DVASPECT.DVASPECT_CONTENT;
fmt.lindex = -1;
fmt.tymed = TYMED.TYMED_HGLOBAL;
STGMEDIUM medium = new STGMEDIUM();
_dataObject.GetData(ref fmt, ref medium);
_hDrop = medium.hGlobal;
}
}
catch(Exception)
{
}
return 0;
}
#region MIIM
internal enum MIIM : uint
{
STATE = 0x00000001,
ID = 0x00000002,
SUBMENU = 0x00000004,
CHECKMARKS = 0x00000008,
TYPE = 0x00000010,
DATA = 0x00000020,
STRING = 0x00000040,
BITMAP = 0x00000080,
FTYPE = 0x00000100
}
#endregion
#region MF
internal enum MF : uint
{
INSERT = 0x00000000,
CHANGE = 0x00000080,
APPEND = 0x00000100,
DELETE = 0x00000200,
REMOVE = 0x00001000,
BYCOMMAND = 0x00000000,
BYPOSITION = 0x00000400,
SEPARATOR = 0x00000800,
ENABLED = 0x00000000,
GRAYED = 0x00000001,
DISABLED = 0x00000002,
UNCHECKED = 0x00000000,
CHECKED = 0x00000008,
USECHECKBITMAPS=0x00000200,
STRING = 0x00000000,
BITMAP = 0x00000004,
OWNERDRAW = 0x00000100,
POPUP = 0x00000010,
MENUBARBREAK = 0x00000020,
MENUBREAK = 0x00000040,
UNHILITE = 0x00000000,
HILITE = 0x00000080,
DEFAULT = 0x00001000,
SYSMENU = 0x00002000,
HELP = 0x00004000,
RIGHTJUSTIFY = 0x00004000,
MOUSESELECT = 0x00008000
}
#endregion
#region CLIPFORMAT
internal enum CLIPFORMAT : uint
{
CF_TEXT = 1,
CF_BITMAP = 2,
CF_METAFILEPICT = 3,
CF_SYLK = 4,
CF_DIF = 5,
CF_TIFF = 6,
CF_OEMTEXT = 7,
CF_DIB = 8,
CF_PALETTE = 9,
CF_PENDATA = 10,
CF_RIFF = 11,
CF_WAVE = 12,
CF_UNICODETEXT = 13,
CF_ENHMETAFILE = 14,
CF_HDROP = 15,
CF_LOCALE = 16,
CF_MAX = 17,
CF_OWNERDISPLAY = 0x0080,
CF_DSPTEXT = 0x0081,
CF_DSPBITMAP = 0x0082,
CF_DSPMETAFILEPICT =0x0083,
CF_DSPENHMETAFILE = 0x008E,
CF_PRIVATEFIRST = 0x0200,
CF_PRIVATELAST = 0x02FF,
CF_GDIOBJFIRST = 0x0300,
CF_GDIOBJLAST = 0x03FF
}
#endregion
#region DVASPECT
internal enum DVASPECT: uint
{
DVASPECT_CONTENT = 1,
DVASPECT_THUMBNAIL = 2,
DVASPECT_ICON = 4,
DVASPECT_DOCPRINT = 8
}
#endregion
#region TYMED
internal enum TYMED: uint
{
TYMED_HGLOBAL = 1,
TYMED_FILE = 2,
TYMED_ISTREAM = 4,
TYMED_ISTORAGE= 8,
TYMED_GDI = 16,
TYMED_MFPICT = 32,
TYMED_ENHMF = 64,
TYMED_NULL= 0
}
#endregion
#region CMF
internal enum CMF: uint
{
CMF_NORMAL = 0x00000000,
CMF_DEFAULTONLY = 0x00000001,
CMF_VERBSONLY = 0x00000002,
CMF_EXPLORE = 0x00000004,
CMF_NOVERBS = 0x00000008,
CMF_CANRENAME = 0x00000010,
CMF_NODEFAULT = 0x00000020,
CMF_INCLUDESTATIC= 0x00000040,
CMF_RESERVED = 0xffff0000
}
#endregion
#region GCS
internal enum GCS: uint
{
VERBA = 0x00000000,
HELPTEXTA = 0x00000001,
VALIDATEA = 0x00000002,
VERBW = 0x00000004,
HELPTEXTW = 0x00000005,
VALIDATEW = 0x00000006,
UNICODE = 0x00000004,
VERB = GCS.VERBA,
HELPTEXT = GCS.HELPTEXTA,
VALIDATE = GCS.VALIDATEA
}
#endregion
#region MENUITEMINFO
[StructLayout(LayoutKind.Sequential)]
internal struct MENUITEMINFO
{
public uint cbSize;
public uint fMask;
public uint fType;
public uint fState;
public int wID;
public int hSubMenu;
public int hbmpChecked;
public int hbmpUnchecked;
public int dwItemData;
public String dwTypeData;
public uint cch;
public int hbmpItem;
}
#endregion
#region FORMATETC
[StructLayout(LayoutKind.Sequential)]
internal struct FORMATETC
{
public CLIPFORMAT cfFormat;
public uint ptd;
public DVASPECT dwAspect;
public int lindex;
public TYMED tymed;
}
#endregion
#region STGMEDIUM
[StructLayout(LayoutKind.Sequential)]
internal struct STGMEDIUM
{
public uint tymed;
public uint hGlobal;
public uint pUnkForRelease;
}
#endregion
#region INVOKECOMMANDINFO
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
internal struct INVOKECOMMANDINFO
{
public uint cbSize;
public uint fMask;
public uint wnd;
public int verb;
[MarshalAs(UnmanagedType.LPStr)]
public string parameters;
[MarshalAs(UnmanagedType.LPStr)]
public string directory;
public int Show;
public uint HotKey;
public uint hIcon;
}
#endregion
#region IDataObject
[ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), GuidAttribute("0000010e-0000-0000-C000-000000000046")]
internal interface IDataObject
{
[PreserveSig()]
int GetData(ref FORMATETC a, ref STGMEDIUM b);
[PreserveSig()]
void GetDataHere(int a, ref STGMEDIUM b);
[PreserveSig()]
int QueryGetData(int a);
[PreserveSig()]
int GetCanonicalFormatEtc(int a, ref int b);
[PreserveSig()]
int SetData(int a, int b, int c);
[PreserveSig()]
int EnumFormatEtc(uint a, ref Object b);
[PreserveSig()]
int DAdvise(int a, uint b, Object c, ref uint d);
[PreserveSig()]
int DUnadvise(uint a);
[PreserveSig()]
int EnumDAdvise(ref Object a);
}
#endregion
|
|
|
|
|
Wow. Thanks Acoustic. Im not sure i understand everything thats going on there, but i will try to implement this into my program and see how it goes. In the code i dont see any writing to the registry going on, so i assume i will still need to use the 'registry hacks' to get the menu items to appear?
|
|
|
|
|
You don't need any hacks. There are standard context menu entries. You should try using Google. There are plenty of C# examples that do what my code does. The registry settings are all documented on MSDN.
|
|
|
|
|
When i should get the "press <tab> to insert interface members" box, i only get it about 10% of the time, and it's driving me nuts.
Is there anyway to force VS.net to do this via some drop down menu or other?
Cheers
Cata
|
|
|
|
|
Hello,
I have a DataGrid control, that I populate from a DataTable . I've already set the table styles to display the columns I want as I want them.
But the user is not supposed to add new records or delete existing ones. He only can change one column on each record. I've managed to make the other column read only, but I can't find a way to prevent the user from clicking on the new row, or deleting an entire row.
Any ideas?
-- LuisR
Luis Alonso Ramos
Intelectix - Chihuahua, Mexico
Not much here: My CP Blog!
|
|
|
|
|
control this via the underlying datasource. for example, if you're binding your grid to a dataview the AllowDelete/AllowEdit/AllowNew properties should be what you're looking for.
hope this helps.
-jim
|
|
|
|
|
I wasn't binding to a DataView , but to a DataTable directly, which doesn't expose those properties. But I quickly created a DataView around it and that solved my problem.
Thanks!
-- LuisR
Luis Alonso Ramos
Intelectix - Chihuahua, Mexico
Not much here: My CP Blog!
|
|
|
|
|
I want to know how to make a connection between mobile (Nokia) and computer such that the mobile can sends MMS (picture) to the computer.
Any help will be greatly appreciated.
Thanks,
Sara.
|
|
|
|
|
i have created a 3D world scene and i want it to be in movie (2D)
i tried to do that by Audio Video PlayBack in directX but i get flicker
i tried it also to do that by VMR9 but it takes bitmaps as an input and i have textures so it'll take a time to convert.
I need it in run time. Thanks for your help
|
|
|
|
|
hi!
im trying to build a data grid which has a different appearance than the traditional one. like the header row will have a different background...how can i attain that in windows data grid?
can anybody help me?
Rajesh
|
|
|
|
|
you have to subclass the existing winforms datagrid class, add the appropriate properties and draw them yourself in the paint implementation.
this is not difficult, but could be time consuming depending on your own personal skill level.
hope this helps.
-jim
|
|
|
|
|
But in that case will i be able to disable to display the extra column shown at the beginning(the one with arrow and a star)? in my design i dont want that.
|
|
|
|
|
in that case i would recommend looking at one of the many freely available open source datagrid controls that are out there such as SourceGrid by Davide Icardi. Not sure if this is going to have all of the functionality you need, but at least it will be a starting point. You can then use the source code to help start designing a custom grid of your own, or extend it to do exactly what you need. Be sure to check the license agreement for usage restrictions.
hope this helps.
-jim
|
|
|
|
|
thanks a lot Jim. Im sure that i can proceed on with this.
|
|
|
|
|
Hi,
Sorry for the off-topic post. I'm looking for some advice about how to make tray icons look nice. WinXP seems to want to take my 32x32 by 256 color icons and compress them down into something that doesn't look very good - it seems to ignore the 16x16 plane. I've noticed that other tray icons look very nice so I assume that there is a better format to use for tray icons -- any tips?
Thanks,
Chris
|
|
|
|
|
|
Hi everyone..
I am still stuck at the problem and any help would be appreciated..
How do I open a connection to a database stored on the IBM server?? I know how to open it with a database stored on my machine with OleDb, but can't find the way to do it for a Db2 database.
If anyone has a sample code they know it works, please help!!!
Thanks
E.T.
|
|
|
|
|
Hi, everybody!!!
I have a control that I would like to drag on a form, but I would not like to drag the control with the top left hand corner showing the dragging rectangle at System.Drawing.Location(0, 0). Instead, I would like to drag the control by dragging at the point where the mouse is clicked on the control in the control's MouseDown event.
To accomplish this, I have declared a variable dragPoint at the form level, and then in the MouseDown event, I make the assignment to the position on the control where the mouse was clicked.
In the DragOver event, the control is simply repositioned based upon either a PointToClient or a RectangleToClient location assignment and then the control.Top and control.Left assignments are made for the new control's location. I would prefer to use the RectangleToClient approach because I need to be able to click on the control at any location of the control's bounds.
When using the RectangleToClient approach, I would like to assign the control.bounds to a rectangle object, because the RectangleToClient returns a rectangle. Then, assign the width and height of the boundingRect rectangle object so that the entire control is now able to be selected. Now, I need to be able to subtract the dragPoint.X from the boundingRect.X and then assign the result to the control.Left and the control.Top OR perhaps to the e.X and e.Y.
Here is the problem: I know that there should be a place where the dragPoint is subtracted from the boundingRect rectangle and then assigned to the control.Left and the control.Top properties, but when I try to do that using just integer numbers, the result no longer shows the dragging rectangle at the top left of the control while the control is being dragged. Instead, it shows a circle with a slash through it, thereby indicating that something is not mathematically correct. How would I set the control to drag from the dragPoint set in the MouseDown event, and then reposition itself in accordance with that dragPoint when the control is moved in the DragOver event.
The code is as follows:
<br />
private static System.Drawing.Point dragPoint;<br />
<br />
<br />
private void MouseDown(object sender, MouseDownEventArgs e)<br />
{<br />
dragPoint.X = e.X;<br />
dragPoint.Y = e.Y;<br />
}<br />
<br />
private void DragOver(object sender, DragEventArgs e)<br />
{ <br />
System.Drawing.Point NewLocation = cthis.PointToClient(new System.Drawing.Point(e.X, e.Y));<br />
ctrl.Left = NewLocation.X + 2;<br />
ctrl.Top = NewLocation.Y + 2;<br />
}<br />
<br />
<br />
private void DragOver(object sender, DragEventArgs e)<br />
{ <br />
Rectangle boundingRect = ctrl.Bounds;<br />
boundingRect.X = e.X;
boundingRect.Y = e.Y;
boundingRect.Width = ctrl.Width;<br />
boundingRect.Height = ctrl.Height;<br />
Rectangle NewLocation = cthis.RectangleToClient(new Rectangle(boundingRect.X, boundingRect.Y, boundingRect.Width, boundingRect.Height));<br />
ctrl.Left = NewLocation.X + 2;<br />
ctrl.Top = NewLocation.Y + 2;<br />
}<br />
<br />
<br />
Would really appreciate some insight as to how to drag a control in the DragOver event where the control is dragged from the dragPoint that is set in the MouseDown event and the dragPoint variable is set at the form level.
|
|
|
|
|
If all you want is to drag from the spot you "grabbed", then you don't need to use the Rectangles. You can to do that with something like the following. (Note that I didn't actually test this code...)
It works by turning your "dragPoint" variable into an offset from the top-left corner of the control being dragged. Then, every mouse move can subtract that offset from the current mouse position to get the control's desired position.
<br />
private void MouseDown(object sender, MouseDownEventArgs e)<br />
{<br />
dragPoint.X = e.X;<br />
dragPoint.Y = e.Y;<br />
dragPoint = PointToClient(dragPoint);<br />
dragPoint.X -= ctrl.X;<br />
dragPoint.Y -= ctrl.Y;<br />
}<br />
<br />
private void DragOver(object sender, DragEventArgs e)<br />
{ <br />
System.Drawing.Point NewLocation = cthis.PointToClient(new System.Drawing.Point(e.X, e.Y));<br />
ctrl.Left = NewLocation.X - dragPoint.X;<br />
ctrl.Top = NewLocation.Y - dragPoint.Y;<br />
}<br />
John
"You said a whole sentence with no words in it, and I understood you!" -- my wife as she cries about slowly becoming a geek.
|
|
|
|
|
John Fisher:
Thanks!!! I will try your code and will
let you know whether it worked.
Much appreciated!!!
New_Phoenix
|
|
|
|
|
Why does this match?
string sSearch = "-- --";
const string sRegEx = "[a-z]*[A-Z]*[0-9]*";
if (Regex.IsMatch(sSearch, sRegEx)) {
}
My understanding is, it should allow any number of characters in the range of a-z, A-Z or any number between 0-9. I guess there is something basic I'm missing out here
/matthias
I love deadlines. I like the whooshing sound they make as they fly by. [Douglas Adams]
|
|
|
|
|
* matches 0 or more occurences of the previous character or subexpression, while + matches 1 or more.
Try this instead:
const string sRegEx = "[a-z]+[A-Z]+[0-9]+";
|
|
|
|
|
Thanks for your reply!
dratcha wrote:
<* matches 0 or more occurences of the previous character or subexpression, while + matches 1 or more.
Yes, but if I use a + instead of a * doesn't that mean i will definetely need 1 char in the range [a-z], plus one in the range [A-Z] and so forth?
With the expression I've build in my previous post (using *), I thought to provide a subset of characters which should be allowed as input. But the string '-- --' marched right through claiming it was valid. How come? It wasn't listed in any of the subsets!
I just want to understand...
/matthias
I love deadlines. I like the whooshing sound they make as they fly by. [Douglas Adams]
|
|
|
|
|
|
Hi leppie,
thanks for your reply. I still don't understand why IsMatch is returning true. For my understanding it should return true if a match has been found. My regular Expression states, that allowed characters are a-z, A-Z, 0-9 in any quantity. It doesn't say that '--' is a valid character.
Could you please provide a short snippet that does the following: Check a given string (say, the SearchString) whether all input characters are falling into these categories a-z, A-Z, 0-9. If the SearchString contains one or more invalid characters, such as : or ; or -, the check should fail and an empty string should be returned. If all characters are valid, the snippet should return the complete SearchString as it was originally passed to the method.
I usually don't ask people writing code for me, but I really would like to understand the workings here. Drives me nuts to walk around and make a stupid face...
Thanks in advance!
/matthias
I love deadlines. I like the whooshing sound they make as they fly by. [Douglas Adams]
|
|
|
|
|