Windows Form WinAPi custom Savefiledialog - Manage lost focus on control edit

0

I need to create on my windows form c# application a custom save file dialog. I'm used this example as starting point https://www.codeproject.com/Articles/8086/Extending-the-save-file-dialog-class-in-NET

I have modified the code and add 2 edit control for Width and Height. I'd like that when change text on width and lost focus, the height texbox update value proporzionally,

But I don't kwow how manage lost focus on edit control.

Here my 2 controls:

int textWidthHandle = CreateWindowEx(0, "Edit", width, ES_NUMBER | WS_VISIBLE | WS_CHILD | WS_TABSTOP | WS_BORDER, point.X + 108, point.Y + 8, 47, 20, parent, 0, 0, 0);
                SendMessage((int)textWidthHandle, WM_SETFONT, fontHandle, 0);

int textHeightHandle = CreateWindowEx(0, "Edit", height, ES_NUMBER | WS_VISIBLE | WS_CHILD | WS_TABSTOP | WS_BORDER, point.X + 199, point.Y + 8, 47, 20, parent, 0, 0, 0);
                SendMessage((int)textHeightHandle, WM_SETFONT, fontHandle, 0);

Can you help me please?

Here my full code:

  public enum EncodingType
   {
    A75 = 0,
    A76 = 1,
    A77 = 2,
    A78 = 3,
    A79 = 4,

    A80 = 5,
    A81 = 6,
    A82 = 7,
    A83 = 8,
    A84 = 9,
    A85 = 10,
    A86 = 11,
    A87 = 12,
    A88 = 13,
    A89 = 14,
    A90 = 15,
    A91 = 16,
    A92 = 17,
    A93 = 18,
    A94 = 19,
    A95 = 20,
    A96 = 21,
    A97 = 22,
    A98 = 23,
    A99 = 24,
    A100 = 25,
}
public class SaveFileDialogWithEncoding
{
    private delegate int OFNHookProcDelegate(int hdlg, int msg, int wParam, int lParam);

    private int m_LabelHandle = 0;
    private int m_ComboHandle = 0;
    private int m_WidthHandle = 0;
    private int m_HeightHandle = 0;

    private string m_Filter = "";
    private string m_DefaultExt = "";

    private string m_FileName = "";

    private EncodingType m_EncodingType;
    private int m_width;
    private int m_height;
    private Screen m_ActiveScreen;

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    private struct OPENFILENAME
    {
        public int lStructSize;
        public IntPtr hwndOwner;
        public int hInstance;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string lpstrFilter;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string lpstrCustomFilter;
        public int nMaxCustFilter;
        public int nFilterIndex;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string lpstrFile;
        public int nMaxFile;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string lpstrFileTitle;
        public int nMaxFileTitle;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string lpstrInitialDir;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string lpstrTitle;
        public int Flags;
        public short nFileOffset;
        public short nFileExtension;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string lpstrDefExt;
        public int lCustData;
        public OFNHookProcDelegate lpfnHook;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string lpTemplateName;
        //only if on nt 5.0 or higher
        public int pvReserved;
        public int dwReserved;
        public int FlagsEx;
    }

    [DllImport("Comdlg32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool GetSaveFileName(ref OPENFILENAME lpofn);

    [DllImport("Comdlg32.dll")]
    private static extern int CommDlgExtendedError();

    [DllImport("user32.dll")]
    private static extern bool SetWindowPos(int hWnd, int hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);



    private struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }

    private struct POINT
    {
        public int X;
        public int Y;
    }

    private struct NMHDR
    {
        public int HwndFrom;
        public int IdFrom;
        public int Code;
    }

    [DllImport("user32.dll")]
    private static extern bool GetWindowRect(int hWnd, ref RECT lpRect);

    [DllImport("user32.dll")]
    private static extern int GetParent(int hWnd);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern bool SetWindowText(int hWnd, string lpString);

    [DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
    public static extern bool SendMessage(IntPtr hWnd, uint Msg, int wParam, StringBuilder lParam);

    [DllImport("user32.dll")]
    private static extern int SendMessage(int hWnd, int Msg, int wParam, int lParam);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern int SendMessage(int hWnd, int Msg, int wParam, string lParam);



    [DllImport("user32.dll")]
    private static extern bool DestroyWindow(int hwnd);

    private const int OFN_ENABLEHOOK = 0x00000020;
    private const int OFN_EXPLORER = 0x00080000;
    private const int OFN_FILEMUSTEXIST = 0x00001000;
    private const int OFN_HIDEREADONLY = 0x00000004;
    private const int OFN_CREATEPROMPT = 0x00002000;
    private const int OFN_NOTESTFILECREATE = 0x00010000;
    private const int OFN_OVERWRITEPROMPT = 0x00000002;
    private const int OFN_PATHMUSTEXIST = 0x00000800;

    private const int SWP_NOSIZE = 0x0001;
    private const int SWP_NOMOVE = 0x0002;
    private const int SWP_NOZORDER = 0x0004;

    private const int WM_KILLFOCUS = 0x0008;
    private const int WM_INITDIALOG = 0x110;
    private const int WM_DESTROY = 0x2;
    private const int WM_SETFONT = 0x0030;
    private const int WM_GETFONT = 0x0031;

    private const int WM_COMMAND = 0x0111;

    private const int WM_GETTEXT = 0x000D;

    private const int CBS_DROPDOWNLIST = 0x0003;
    private const int CBS_HASSTRINGS = 0x0200;
    private const int CB_ADDSTRING = 0x0143;
    private const int CB_SETCURSEL = 0x014E;
    private const int CB_GETCURSEL = 0x0147;

    private const uint WS_VISIBLE = 0x10000000;
    private const uint WS_CHILD = 0x40000000;
    private const uint WS_TABSTOP = 0x00010000;

    private const uint WS_BORDER = 0x00800000;

    private const int ES_NUMBER = 0x2000;

    private const int CDN_FILEOK = -606;
    private const int WM_NOTIFY = 0x004E;

    private const int WM_KEYDOWN = 0x0100;

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern int GetDlgItem(int hDlg, int nIDDlgItem);

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    static extern int GetWindowTextLength(IntPtr hWnd);



    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern int CreateWindowEx(int dwExStyle, string lpClassName, string lpWindowName, uint dwStyle, int x, int y, int nWidth, int nHeight, int hWndParent, int hMenu, int hInstance, int lpParam);

    [DllImport("user32.dll")]
    private static extern bool ScreenToClient(int hWnd, ref POINT lpPoint);


    private int HookProc(int hdlg, int msg, int wParam, int lParam)
    {
        switch (msg)
        {

            case WM_INITDIALOG:

                //we need to centre the dialog
                Rectangle sr = m_ActiveScreen.Bounds;
                RECT cr = new RECT();
                int parent = GetParent(hdlg);
                GetWindowRect(parent, ref cr);

                int x = (sr.Right + sr.Left - (cr.Right - cr.Left)) / 2;
                int y = (sr.Bottom + sr.Top - (cr.Bottom - cr.Top)) / 2;

                SetWindowPos(parent, 0, x, y, cr.Right - cr.Left, cr.Bottom - cr.Top + 32, SWP_NOZORDER);


                //we need to find the label to position our new label under

                int fileTypeWindow = GetDlgItem(parent, 0x441);

                RECT aboveRect = new RECT();
                GetWindowRect(fileTypeWindow, ref aboveRect);

                //now convert the label's screen co-ordinates to client co-ordinates
                POINT point = new POINT();
                point.X = aboveRect.Left;
                point.Y = aboveRect.Bottom;

                ScreenToClient(parent, ref point);

                //create the label
                int labelHandle = CreateWindowEx(0, "STATIC", "mylabel", WS_VISIBLE | WS_CHILD | WS_TABSTOP, point.X, point.Y + 16, 200, 100, parent, 0, 0, 0);
                SetWindowText(labelHandle, "Jpeg Compression:");

                int fontHandle = SendMessage(fileTypeWindow, WM_GETFONT, 0, 0);
                SendMessage(labelHandle, WM_SETFONT, fontHandle, 0);




                //we now need to find the combo-box to position the new combo-box under

                int fileComboWindow = GetDlgItem(parent, 0x470);
                aboveRect = new RECT();
                GetWindowRect(fileComboWindow, ref aboveRect);

                point = new POINT();
                point.X = aboveRect.Left;
                point.Y = aboveRect.Bottom;
                ScreenToClient(parent, ref point);

                POINT rightPoint = new POINT();
                rightPoint.X = aboveRect.Right;
                rightPoint.Y = aboveRect.Top;

                ScreenToClient(parent, ref rightPoint);

                Form1 f = (Form1)(Application.OpenForms[0]);

                //we create the new combobox

                int comboHandle = CreateWindowEx(0, "ComboBox", "mycombobox", WS_VISIBLE | WS_CHILD | CBS_HASSTRINGS | CBS_DROPDOWNLIST | WS_TABSTOP, point.X, point.Y + 8, 50, 100, parent, 0, 0, 0);
                SendMessage(comboHandle, WM_SETFONT, fontHandle, 0);

                //create the label
                int labelHandle2 = CreateWindowEx(0, "STATIC", "mylabel2", WS_VISIBLE | WS_CHILD | WS_TABSTOP, point.X + 73, point.Y + 12, 100, 100, parent, 0, 0, 0);
                SetWindowText(labelHandle2, "Width:");
                SendMessage(labelHandle2, WM_SETFONT, fontHandle, 0);

                Size s = f.GetResolution();
                string width = s.Width != 0 ? s.Width.ToString() : "";
                string height = s.Height != 0 ? s.Height.ToString() : "";
                if (s.Width > 0)
                    m_width = s.Width;
                if (s.Height > 0)
                    m_height = s.Height;

                int textWidthHandle = CreateWindowEx(0, "Edit", width, ES_NUMBER | WS_VISIBLE | WS_CHILD | WS_TABSTOP | WS_BORDER, point.X + 108, point.Y + 8, 47, 20, parent, 0, 0, 0);
                SendMessage((int)textWidthHandle, WM_SETFONT, fontHandle, 0);

                //create the label
                int labelHandle3 = CreateWindowEx(0, "STATIC", "mylabel3", WS_VISIBLE | WS_CHILD | WS_TABSTOP, point.X + 162, point.Y + 12, 100, 100, parent, 0, 0, 0);
                SetWindowText(labelHandle3, "Height:");
                SendMessage(labelHandle3, WM_SETFONT, fontHandle, 0);

                int textHeightHandle = CreateWindowEx(0, "Edit", height, ES_NUMBER | WS_VISIBLE | WS_CHILD | WS_TABSTOP | WS_BORDER, point.X + 199, point.Y + 8, 47, 20, parent, 0, 0, 0);
                SendMessage((int)textHeightHandle, WM_SETFONT, fontHandle, 0);


                //and add the encodings we want to offer
                SendMessage(comboHandle, CB_ADDSTRING, 0, "75");
                SendMessage(comboHandle, CB_ADDSTRING, 0, "76");
                SendMessage(comboHandle, CB_ADDSTRING, 0, "77");
                SendMessage(comboHandle, CB_ADDSTRING, 0, "78");
                SendMessage(comboHandle, CB_ADDSTRING, 0, "79");
                SendMessage(comboHandle, CB_ADDSTRING, 0, "80");
                SendMessage(comboHandle, CB_ADDSTRING, 0, "81");
                SendMessage(comboHandle, CB_ADDSTRING, 0, "82");
                SendMessage(comboHandle, CB_ADDSTRING, 0, "83");
                SendMessage(comboHandle, CB_ADDSTRING, 0, "84");
                SendMessage(comboHandle, CB_ADDSTRING, 0, "85");
                SendMessage(comboHandle, CB_ADDSTRING, 0, "86");
                SendMessage(comboHandle, CB_ADDSTRING, 0, "87");
                SendMessage(comboHandle, CB_ADDSTRING, 0, "88");
                SendMessage(comboHandle, CB_ADDSTRING, 0, "89");
                SendMessage(comboHandle, CB_ADDSTRING, 0, "90");
                SendMessage(comboHandle, CB_ADDSTRING, 0, "91");
                SendMessage(comboHandle, CB_ADDSTRING, 0, "92");
                SendMessage(comboHandle, CB_ADDSTRING, 0, "93");
                SendMessage(comboHandle, CB_ADDSTRING, 0, "94");
                SendMessage(comboHandle, CB_ADDSTRING, 0, "95");
                SendMessage(comboHandle, CB_ADDSTRING, 0, "96");

                SendMessage(comboHandle, CB_ADDSTRING, 0, "97");
                SendMessage(comboHandle, CB_ADDSTRING, 0, "98");

                SendMessage(comboHandle, CB_ADDSTRING, 0, "99");
                SendMessage(comboHandle, CB_ADDSTRING, 0, "100");

                m_EncodingType = EncodingType.A94;

                SendMessage(comboHandle, CB_SETCURSEL, (int)m_EncodingType, 0);

                //remember the handles of the controls we have created so we can destroy them after
                m_LabelHandle = labelHandle;
                m_ComboHandle = comboHandle;
                m_WidthHandle = textWidthHandle;
                m_HeightHandle = textHeightHandle;

                break;
            case WM_DESTROY:
                //destroy the handles we have created
                if (m_ComboHandle != 0)
                {
                    DestroyWindow(m_ComboHandle);
                }
                if (m_WidthHandle != 0)
                {
                    DestroyWindow(m_WidthHandle);
                }
                if (m_HeightHandle != 0)
                {
                    DestroyWindow(m_HeightHandle);
                }

                if (m_LabelHandle != 0)
                {
                    DestroyWindow(m_LabelHandle);
                }
                break;
            case WM_NOTIFY:

                //we need to intercept the CDN_FILEOK message
                //which is sent when the user selects a filename

                NMHDR nmhdr = (NMHDR)Marshal.PtrToStructure(new IntPtr(lParam), typeof(NMHDR));

                if (nmhdr.Code == CDN_FILEOK)
                {
                    //a file has been selected
                    //we need to get the encoding

                    m_EncodingType = (EncodingType)SendMessage(m_ComboHandle, CB_GETCURSEL, 0, 0);

                    int max_length = GetWindowTextLength((IntPtr)m_WidthHandle);
                    StringBuilder widthtext = new StringBuilder(max_length + 1);

                    SendMessage((IntPtr)m_WidthHandle, WM_GETTEXT, widthtext.Capacity, widthtext);

                    int retWidth;
                    Int32.TryParse(widthtext.ToString(), out retWidth);

                    m_width = retWidth;


                    int max_lengthh = GetWindowTextLength((IntPtr)m_HeightHandle);
                    StringBuilder heighttext = new StringBuilder(max_lengthh + 1);

                    SendMessage((IntPtr)m_HeightHandle, WM_GETTEXT, heighttext.Capacity, heighttext);

                    int retHeight;
                    Int32.TryParse(heighttext.ToString(), out retHeight);

                    m_height = retHeight;



                }
                break;

        }
        return 0;
    }

    public string DefaultExt
    {
        get
        {
            return m_DefaultExt;
        }
        set
        {
            m_DefaultExt = value;
        }
    }

    public string Filter
    {
        get
        {
            return m_Filter;
        }
        set
        {
            m_Filter = value;
        }
    }

    public string FileName
    {
        get
        {
            return m_FileName;
        }
        set
        {
            m_FileName = value;
        }
    }

    public EncodingType EncodingType
    {
        get
        {
            return m_EncodingType;
        }
        set
        {
            m_EncodingType = value;
        }
    }

    public int Width
    {
        get
        {
            return m_width;
        }
        set
        {
            m_width = value;
        }
    }

    public int Height
    {
        get
        {
            return m_height;
        }
        set
        {
            m_height = value;
        }
    }

    public DialogResult ShowDialog()
    {

        //set up the struct and populate it

        OPENFILENAME ofn = new OPENFILENAME();

        ofn.lStructSize = Marshal.SizeOf(ofn);
        ofn.lpstrFilter = m_Filter.Replace('|', '\0') + '\0';

        ofn.lpstrFile = m_FileName + new string(' ', 512);
        ofn.nMaxFile = ofn.lpstrFile.Length;
        ofn.lpstrFileTitle = System.IO.Path.GetFileName(m_FileName) + new string(' ', 512);
        ofn.nMaxFileTitle = ofn.lpstrFileTitle.Length;

        Form1 f = (Form1)(Application.OpenForms[0]);
        RadioButton radioButtonIta = (RadioButton)f.Controls["radioButtonIta"];
        if (radioButtonIta.Checked)
        {
            ofn.lpstrTitle = "Salva immagine come";
        }
        else
        {
            ofn.lpstrTitle = "Save image as";
        }


        ofn.lpstrDefExt = m_DefaultExt;

        //position the dialog above the active window
        ofn.hwndOwner = Form.ActiveForm.Handle;

        //we need to find out the active screen so the dialog box is
        //centred on the correct display

        m_ActiveScreen = Screen.FromControl(Form.ActiveForm);

        //set up some sensible flags
        ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_NOTESTFILECREATE | OFN_ENABLEHOOK | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;

        //this is where the hook is set. Note that we can use a C# delegate in place of a C function pointer
        ofn.lpfnHook = new OFNHookProcDelegate(HookProc);

        //if we're running on Windows 98/ME then the struct is smaller
        if (System.Environment.OSVersion.Platform != PlatformID.Win32NT)
        {
            ofn.lStructSize -= 12;
        }

        //show the dialog

        if (!GetSaveFileName(ref ofn))
        {
            int ret = CommDlgExtendedError();

            if (ret != 0)
            {
                throw new ApplicationException("Couldn't show file open dialog - " + ret.ToString());
            }

            return DialogResult.Cancel;
        }

        m_FileName = ofn.lpstrFile;

        return DialogResult.OK;
    }
}

Thanks

winapi
savefiledialog
lostfocus
asked on Stack Overflow Jan 17, 2018 by user3930528 • edited Jan 17, 2018 by user3930528

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0