views:

240

answers:

1

Hello friends,

I am developing an application using C# having similar functionality of copy,paste as in Windows. I have added menu items and linked with respective applications.

Please look at the following image for getting more idea.

Items added to shell menu

Like we select multiple items in windows explorer, you need to select multiple files and/or folders and then select OS Util->FastCopy. A form is opened as shown below

Form shown on FastCopy

The application is working perfectly. The major problem here is that after selecting the files all these files are opening up within there respective softwares. That is if i selected word document then the filename is added to FastCopy form but the is also opening up within Word also.

When i investigate i found that this problem is due to SendMessage. I have to use PostMessage instead of SendMessage. But when i do so the application is not working.

Below is my Main function coding in C# 2005

static class Program
{
    static Mutex mutex = new Mutex(true, "{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE92}");
    [STAThread]
    static void Main(string[] args)
    {
        string fileName = "";
        if (args.Length > 0)
        {
            fileName = args[0];
        }
        if (mutex.WaitOne(TimeSpan.Zero, true))
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            frmFastCopy frm = new frmFastCopy();
            frm.AddItemToList(fileName);
            Application.Run(frm);

        }
        else
        {
            //The following message is sent just to show up the form
            NativeMethods.PostMessage(
                    (IntPtr)NativeMethods.HWND_BROADCAST,
                    NativeMethods.WM_SHOWME,
                    IntPtr.Zero,
                    IntPtr.Zero);

            //Send the filename
            SendFileName(fileName);
        }
    }

    static void SendFileName(string s)
    {
        Win32.CopyDataStruct cds = new Win32.CopyDataStruct();

        cds.cbData = (s.Length + 1) * 2;
        cds.lpData = Win32.LocalAlloc(0x40, cds.cbData);
        Marshal.Copy(s.ToCharArray(), 0, cds.lpData, s.Length);
        cds.dwData = (IntPtr)1;
        Win32.SendMessage((IntPtr)NativeMethods.HWND_BROADCAST, Win32.WM_COPYDATA, IntPtr.Zero, ref cds);
        //NativeMethods.PostMessage((IntPtr)NativeMethods.HWND_BROADCAST, Win32.WM_COPYDATA, cds.lpData, IntPtr.Zero);
    }
}

}


Below is the copy for WndProc and other code from within the Form

public partial class frmFastCopy : Form { delegate void AddItemToListDelegate(string itm);

    public frmFastCopy()
    {
        InitializeComponent();
    }

    public void AddItemToList(string itm)
    {
        if (lvFilesAndFolders.InvokeRequired)
        {
            AddItemToListDelegate m = new AddItemToListDelegate(AddItemToList);
            this.Invoke(m, new object[] { itm });
        }
        else
        {
            lvFilesAndFolders.Items.Add(itm);
        }
    }
    protected override void WndProc(ref Message m)
    {
        if (m.Msg==NativeMethods.WM_SHOWME)
        {
                ShowMe();
        }
        if (m.Msg==Win32.WM_COPYDATA)
        {
                //string s = Marshal.PtrToStringUni(m.LParam);
                MessageBox.Show("Got message");

                Win32.CopyDataStruct st = (Win32.CopyDataStruct)Marshal.PtrToStructure(m.LParam, typeof(Win32.CopyDataStruct));
                string strData = Marshal.PtrToStringUni(st.lpData);
                AddItemToList(strData);
        }
        base.WndProc(ref m);
    }
    private void ShowMe()
    {
        this.Show();
        if (WindowState == FormWindowState.Minimized)
        {
            WindowState = FormWindowState.Normal;
        }
        // get our current "TopMost" value (ours will always be false though)
        bool top = TopMost;
        // make our form jump to the top of everything
        TopMost = true;
        // set it back to whatever it was
        TopMost = top;
    }

Here is the NativeCode class

internal class NativeMethods { public const int HWND_BROADCAST = 0xffff; public static readonly int WM_SHOWME = RegisterWindowMessage("WM_SHOWME"); [DllImport("user32")] public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam); [DllImport("user32")] public static extern int RegisterWindowMessage(string message);

}

I know you guys are genius. Could someone tell me where should i make changes to that the selected files should be opened or rather how i should use postmessage.

Thanks for sharing your valuable time.

Regards

Irfan

+1  A: 

Please look at my comment (I wonder why you don't use the Clipboard class here). But ignoring that: Why do you broadcast the message?

Can you locate your application (by name, window class, whatever) and only send the message to your own application?


To elaborate on the message handling: You say regarding HWND_BROADCAST in the comments below:

Thats nothing but the global handle to my application.

No, it's not. It is a special value that tells Windows "this message is for all applications". You are sending a WM_SHOWME to all applications. Which is why I asked why you would want to do that?

Please see this post on the old new things blog regarding message broadcasts.

Benjamin Podszun
Yeah I have used the mutex to create only the single instance. I think you not observed my code. The application is working fine as i needed only the problem here is that the selected files are also opening up in there respective software.
IrfanRaza
Good new my friends!!!!The Clipboard class solved my problem. Thanks Benjamin a lot.But still i would like to ask you guys how to use postmessage here?
IrfanRaza
Glad that you found out about the (ready, usable) Clipboard class. Regarding the code: I just wanted to understand why you'd use HWND_BROADCAST instead of searching your own app and posting or sending your message _directly_, without a broadcast.
Benjamin Podszun
Thats nothing but the global handle to my application.
IrfanRaza
Using the Clipboard is 100% *wrong*. The clipboard belongs to the application user, not your program. IOW, the only time things should be put into or taken out of the Clipboard is when the application's *user* decides to do so. Otherwise, your app can destroy content that the user actually +did+ put there, and can get content it didn't expect as well.
Ken White
@Ken: Did you actually read his requirement? He has a context menu item that _copies_ something and is called "FastCopy". You can argue if that is useful and I agree that you shouldn't do Shell Extensions in C#. But if _my_ program would offer copy and paste and labels it as that there's one class to use: The Clipboard. It's not that he randomly chooses to put things on there...
Benjamin Podszun
Thanks Benjamin for correcting me. Honestly some of the code here is copy/paste by googling. I was thinking that HWND_BROADCAST is global handle to my application.Hi Ken, you are correct but what i have done here is i have created my own data format for clipboard. Is it wrong to do so?
IrfanRaza