NOVINKA - Online rekvalifikační kurz Java programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.
NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!

Diskuze: Přepis řešení v C++ co C#

V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.

Aktivity
Avatar
HONZ4
Člen
Avatar
HONZ4:9.2.2018 21:30

Zdravím vás, moc bych vás prosil o přepis řešení známého problému s výběrem položek myší v ListView do C# WinForms.
(Protože Microsoft na opravy chyb, kašle. Raději do W10 přidá nějakou novou hovadinu.)
Já vůbec nevím jak na to.
https://github.com/…tfw10fcu.cpp

 
Odpovědět
9.2.2018 21:30
Avatar
HONZ4
Člen
Avatar
HONZ4:9.2.2018 21:49

Pro upřesnění: nechci spouštět tu jeho aplikaci, ale využít toto řešení pro úpravu vlastních aplikací.

Editováno 9.2.2018 21:50
 
Nahoru Odpovědět
9.2.2018 21:49
Avatar
Odpovídá na HONZ4
Radek Chalupa:10.2.2018 7:28

Přiznám se že nevím o jaký problém se jedná.
Ale ten kód je dll knihovna obsahující tzv "system hook", v tomhle případě umožňuje sledovat události myši i když myš je v jiném okně/aplikaci. Podle toho kódu pokud je při pohybu myši stlačené tlačítko a myš je v listview, vyvolá předkreslení parent okna toho listview.
Pro aktivaci musíš použít LoadLibrary pro načtení té dll, a následně zavolat SetWindowsHookEx. Tyhle winAPI funkce můžeš v C# vyvolat přes DllImport.
Tu DLL su vytvoříš jako win32 aplikaci (Visual c++) s uvedeným kódem.

Radek Chalupa
http://www.radekchalupa.cz

 
Nahoru Odpovědět
10.2.2018 7:28
Avatar
HONZ4
Člen
Avatar
Odpovídá na Radek Chalupa
HONZ4:10.2.2018 16:35

Díky za reakci.
Myslíš, že by to nešlo zakomponovat přímo do aplikace, tak že by se vytvořil upravený ListView?

Přiznám se že nevím o jaký problém se jedná

Pokusím se tu chybu vysvětlit:

Chyba se projevuje u ListView s nastavením View=Details, FullRowSelect=true a MultiSelect=true, pokud ListView obsahuje víc položek (tolik aby se objevil vertikální ScrollBar).

  1. Stačí odrolovat v seznamu dolů a označit některý spodní řádek.
  2. Odrolovat nahoru
  3. Pokusit se označit myší více položek (jen pomocí "rectangle selection", bez Ctrl nebo Shift), např. označit od pátého řádku po první

(U starších aplikací (.net fram. 1.1) se chyba objeví rovnou. )

Cbyba spočívá v tom, že při startu označování myší, kurzor odskočí do levého dolního rohu obrazovky, tím se označí většinou všechny řádky pod prvním označeným, přestože uživatel chce označit řádky nad..

Editováno 10.2.2018 16:37
 
Nahoru Odpovědět
10.2.2018 16:35
Avatar
Odpovídá na HONZ4
Radek Chalupa:12.2.2018 15:11

Z toho kódu (fce MouseProc) je vidět že pokud je při pohybu myši v okně listview stisknuté tlačítko (pravé nebo levé) tak se vyvolá překreslení levého horního rohu parent okna toho listview. Nevím zda a jak se tímhle překreslením vyřeší zmíněný problém, ale ve vlastn íaplikaci můžeš v událostech listview odchytávat mousemove, testovat tlačítka a zavolat Repaint (nebo Refresh? - z hlavy nevím) metodu Formu (resp. okna na kterém je ten listview).

Radek Chalupa
http://www.radekchalupa.cz

 
Nahoru Odpovědět
12.2.2018 15:11
Avatar
HONZ4
Člen
Avatar
Odpovídá na Radek Chalupa
HONZ4:13.2.2018 20:14

Díky za popis té funkce, zkusil jsem při pohybu myši překreslovat pomocí Refresh i zavoláním RedrawWindow Parenta listview, ale z nějakého důvodu to nefunguje tak jak Tablacusova aplikace.
Sice se mě nedaří zjistit jestli je stlačené tlačítko myši, ale tam ta chyba asi nebude.
Takto to mám teď:

class ListViewXP : ListView
{
    const int WM_ERASEBKGND = 0x0014;
    const int WM_MOUSEMOVE = 0x0200;
    const int WM_LBUTTONDOWN = 0x0201;
    const int RDW_NOERASE_INVALIDATE = 0x0021;

    private struct RECT
    {
        public int left;
        public int top;
        public int right;
        public int bottom;

        public RECT(int l, int t, int r, int b)
        {
            left = l;
            top = t;
            right = r;
            bottom = b;
        }
    }

    [DllImport("user32.dll")]
    static extern bool RedrawWindow(IntPtr hWnd, ref RECT lprcUpdate, IntPtr hrgnUpdate, int flags);

    [DllImport("USER32.dll")]
    static extern short GetKeyState(Keys nVirtKey);

    RECT rc = new RECT(0, 0, 1, 1);

    public ListViewXP()
    {
        //proti blikání kresleného listu
        SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint |
                 ControlStyles.EnableNotifyMessage, true);
    }

    protected override void OnPaint(PaintEventArgs pe)
    {
        base.OnPaint(pe);
    }

    protected override void OnNotifyMessage(Message m)
    {
        if(m.Msg == WM_ERASEBKGND)
            m.Msg = 0; //proti blikání kresleného listu
        base.OnNotifyMessage(m);
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
        //if (e.Button == MouseButtons.Left) nefuguje
        //{
            RedrawWindow(Parent.Handle, ref rc, IntPtr.Zero, RDW_NOERASE_INVALIDATE);
        //Parent.Refresh();
        //}
        base.OnMouseMove(e);
    }
}

Ještě to budu zkoušet, ale kdyby se to někomu podařilo, budu rád.
Nebo kdyby mě někdo poradil, alespoň s tím myším tlačítkem...

Editováno 13.2.2018 20:17
 
Nahoru Odpovědět
13.2.2018 20:14
Avatar
Odpovídá na HONZ4
Radek Chalupa:14.2.2018 11:02

Ookud jde o mouse button, nevím co myslíš tím "nefunguje", ale ta property Button jsou bitové flagy, takže bys měl konkrétní tlačítko testovat nokoliv rovností ale:
if ((e.Button & MouseButton.left) != 0) ....

Ještě pokud se má překreslovat parent toho listview, tak vzhledem k tomu že předpokládám máš tu obsluhu v kódu Formu, ketrý už sám je parentem listview, měl bys mít v parametru RedrawWindow jen Handle.

Zkoušel jsi tu aplikaci s tím systémovým hookem zda funguje? Přijde mi divné že by ten problém vyřešilo pouhé vyvolání překreslení. Až budu mít čas, zkusím to napsat v céčku...

Radek Chalupa
http://www.radekchalupa.cz

 
Nahoru Odpovědět
14.2.2018 11:02
Avatar
Radek Chalupa:14.2.2018 17:37

Tak jsem to zkusil v céčku a vypadá to že to funguje pouze pokud se ten kód umístí do hook procedury, může to být i lokální hook (tj. pouze pro aktuální thread).
Ve WinForms si lze udělat class library v C++ (jako visual c++ CLR projekt typu class library), kód vypadá takhle (je to test, takže tam není důledné testováná chyb a pod.).

// ClassLibraryHooks.h

#pragma once

using namespace System;

__declspec(selectany) HHOOK __hhook_mouse = NULL;

__declspec(selectany) WCHAR sz_class[MAX_CLASS_NAME];

inline LRESULT CALLBACK mouse_proc(int nCode, WPARAM wParam, LPARAM lParam)
{
        if (nCode >= 0 || nCode != HC_NOREMOVE)
        {
                if (nCode == HC_ACTION)
                {
                        MOUSEHOOKSTRUCT *pmhs = (MOUSEHOOKSTRUCT*)lParam;
                        switch (wParam)
                        {
                        case WM_MOUSEMOVE:
                                if (GetKeyState(VK_LBUTTON) < 0 || GetKeyState(VK_RBUTTON) < 0)
                                {
                                        if (GetClassName(pmhs->hwnd, sz_class, MAX_CLASS_NAME))
                                        {
                                                if (PathMatchSpec(sz_class, L"*listview*"))
                                                {
                                                        RECT rc = { 0, 0, 1, 1 };
                                                        RedrawWindow(GetParent(pmhs->hwnd), &rc, 0, RDW_NOERASE | RDW_INVALIDATE);
                                                }
                                        }
                                }
                                break;
                        }
                }
        }
        return CallNextHookEx(__hhook_mouse, nCode, wParam, lParam);
}

namespace ClassLibraryHooks
{
        public ref class hooks_fce
        {
        public:
                static void spustit()
                {
                        __hhook_mouse = SetWindowsHookEx(WH_MOUSE, (HOOKPROC)mouse_proc, NULL, GetCurrentThreadId());
                        if (NULL == __hhook_mouse)
                                ::MessageBox(NULL, L"Chyba SetWindowsHookEx", L"Je to v prdeli", MB_ICONERROR);
                }
                static void zastavit()
                {
                        if (__hhook_mouse)
                        {
                                UnhookWindowsHookEx(__hhook_mouse);
                                __hhook_mouse = NULL;
                        }
                }
        };
}

v stdafx.h musí být:
#pragma once

#include <Windows.h>
#include <Shlwapi.h>

#pragma comment (lib, "user32.lib")
#pragma comment (lib, "shlwapi.lib")

Pak jsem ve winforms aplikaci přidal tu dll classlibrary do referencí a kód testovacího Formu s jedním listview:

public partial class Form1 : Form
{
        public Form1()
        {
                InitializeComponent();
        }

        private void on_load(object sender, EventArgs e)
        {
                ListViewItem lvi;
                for (int i = 0; i < 100; i++)
                {
                        lvi = lv_test.Items.Add((100 + i).ToString());
                        lvi.SubItems.Add((200 + i).ToString());
                        lvi.SubItems.Add((300 + i).ToString());
                }
                ClassLibraryHooks.hooks_fce.spustit();
        }

        private void on_closing(object sender, FormClosingEventArgs e)
        {
                ClassLibraryHooks.hooks_fce.zastavit();
        }
}

Radek Chalupa
http://www.radekchalupa.cz

Akceptované řešení
+20 Zkušeností
+2,50 Kč
Řešení problému
 
Nahoru Odpovědět
14.2.2018 17:37
Avatar
HONZ4
Člen
Avatar
Odpovídá na Radek Chalupa
HONZ4:14.2.2018 19:07

co myslíš tím "nefunguje", ale ta property...

Ono se stisknuté tlačítko detekuje pouze pokud je kurzor nad řádkem, jakmile jste v ose X za posledním sloupcem tak ne.

předpokládám máš tu obsluhu v kódu Formu...

nemám, jeto přepis (nebo jak se tomu v C# nadává) komponenty ListView class ListViewXP : ListView

Tak jsem to zkusil v céčku..

Tvé řešení opravdu funguje. Mockrát díky!

Tvé řešení mi stačí, ale pokud se Ti chce odpovídat, tak jen pro zajímavost:
Zajímalo by mě proč to vlastně funguje? Protože je to přes hook? Proč funguje vyvolání (částečné) překreslení na takový problém? Dalo by se to udělat bez hooku, přibližně jak jsem to dělal já?

 
Nahoru Odpovědět
14.2.2018 19:07
Avatar
HONZ4
Člen
Avatar
HONZ4:14.2.2018 20:00

takto jsem měl poslední pokus:
http://www51.zippyshare.com/…HP/file.html
je to celý projekt a archivu, heslo je w10bug

 
Nahoru Odpovědět
14.2.2018 20:00
Avatar
HONZ4
Člen
Avatar
HONZ4:15.2.2018 10:21

Bohužel jsem narazil na problém, aplikace neběží na jiném počítači než mém. Předpokládám, že bych musel doinstalovávat redistributable balíček, to se mě moc nelíbí, tak jsem se pokusil kód přepsat do C#, ale mám tam něco špatně.
Kompilace proběhne bez varování, ale aplikace padá s chybou:
Pomocník spravovaného ladění CallbackOnCollec­tedDelegate
Bylo provedeno zpětné volání u delegáta typu FCUFixTest!FCU­Fix.BugFix+Ho­okProc::Invoke zjištěného pomocí úklidového modulu. Výsledkem může být havárie aplikace, poškození a ztráta dat. Při předávání nespravovanému kódu musí být delegáti udržováni aktivní spravovanou aplikací, dokud není zaručeno, že již nikdy nebudou voláni.

Co mám špatně?

using System;
using System.Runtime.InteropServices;
using System.Text;

namespace FCUFix
{
    public static class BugFix
    {
        #region definitions
        const int MAX_CLASS_NAME = 1024;
        const int HC_NOREMOVE = 3;
        const int HC_ACTION = 0;
        const int WM_MOUSEMOVE = 0x0200;
        const int VK_LBUTTON = 1;
        const int VK_RBUTTON = 2;
        const int RDW_NOERASE_INVALIDATE = 0x0021;
        const int WH_MOUSE = 7;

        static IntPtr __hhook_mouse = IntPtr.Zero;
        static StringBuilder sz_class = new StringBuilder(MAX_CLASS_NAME);

        [StructLayout(LayoutKind.Sequential, Pack = 4)]
        private struct MOUSEHOOKSTRUCT
        {
            public int point_X;
            public int point_Y;
            public IntPtr hwnd;
            public uint hittestcode;
            public IntPtr dwExtraInfo;
            public uint mouseData;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct RECT
        {
            public int left;
            public int top;
            public int right;
            public int bottom;

            public RECT(int l, int t, int r, int b)
            {
                left = l;
                top = t;
                right = r;
                bottom = b;
            }
        }

        delegate IntPtr HookProc(int code, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll")]
        static extern bool RedrawWindow(IntPtr hWnd, ref RECT lprcUpdate, IntPtr hrgnUpdate, int flags);

        [DllImport("user32.dll")]
        static extern short GetKeyState(int key);

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

        [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
        static extern IntPtr GetParent(IntPtr hWnd);

        [DllImport("kernel32.dll")]
        static extern uint GetCurrentThreadId();

        [DllImport("user32.dll")]
        static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr SetWindowsHookEx(int hookType, HookProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool UnhookWindowsHookEx(IntPtr hhk);
        static Type tMOUSEHOOKSTRUCT = typeof(MOUSEHOOKSTRUCT);
        #endregion
        static RECT rect = new RECT(0, 0, 1, 1);

        static IntPtr MouseProc(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0 || nCode != HC_NOREMOVE)
            {
                if (nCode == HC_ACTION)
                {
                    MOUSEHOOKSTRUCT pmhs = (MOUSEHOOKSTRUCT)Marshal.PtrToStructure(lParam, tMOUSEHOOKSTRUCT);
                    int wparam = (int)wParam;
                    switch (wparam)
                    {
                        case WM_MOUSEMOVE:
                        if (GetKeyState(VK_LBUTTON) < 0 || GetKeyState(VK_RBUTTON) < 0)
                        {
                            if (0 != GetClassName(pmhs.hwnd, sz_class, MAX_CLASS_NAME))
                            {
                                string cname = sz_class.ToString().ToLower();
                                if (cname.Contains("listview"))
                                {
                                    RedrawWindow(GetParent(pmhs.hwnd), ref rect, IntPtr.Zero, RDW_NOERASE_INVALIDATE);
                                }
                            }
                        }
                        break;
                    }
                }
            }
            return CallNextHookEx(__hhook_mouse, nCode, wParam, lParam);
        }

        public static void StartFix()
        {
            if (__hhook_mouse == IntPtr.Zero)
            {
                __hhook_mouse = SetWindowsHookEx(WH_MOUSE, MouseProc, IntPtr.Zero, GetCurrentThreadId());
                if (null == __hhook_mouse) throw new ExternalException("Chyba SetWindowsHookEx");
            }
        }

        public static void StopFix()
        {
            if (__hhook_mouse != IntPtr.Zero)
            {
                UnhookWindowsHookEx(__hhook_mouse);
                __hhook_mouse = IntPtr.Zero;
            }
        }
    }
}
 
Nahoru Odpovědět
15.2.2018 10:21
Avatar
Odpovídá na HONZ4
Radek Chalupa:15.2.2018 11:25

zkoušel jsi to krokovat na kterém řádku to havaruje?

 
Nahoru Odpovědět
15.2.2018 11:25
Avatar
HONZ4
Člen
Avatar
Odpovídá na Radek Chalupa
HONZ4:15.2.2018 12:07

tady: Application.Run(new Form1());

projekt:
http://www74.zippyshare.com/…3v/file.html
heslo: w10bug

 
Nahoru Odpovědět
15.2.2018 12:07
Avatar
Radek Chalupa:15.2.2018 13:44

v tom Run je bv podstatě celá smyčka aplikace. Zkus dát breakpointry dovnitř kódu.
Trochu jsem to upravil, dal tu MouseProc jako metodu formu a to spuštění do události Load a funguje to.

 
Nahoru Odpovědět
15.2.2018 13:44
Avatar
HONZ4
Člen
Avatar
Odpovídá na Radek Chalupa
HONZ4:15.2.2018 14:01

Měl sem je tam, ale při té chybě to právě skončilo na řádku s .Run

Můžeš mi prosím sem dát ukázku? K večeru to zkusím.

 
Nahoru Odpovědět
15.2.2018 14:01
Avatar
Odpovídá na HONZ4
Radek Chalupa:15.2.2018 15:04

tohle je kod toho Formu:

public partial class Form1 : Form
{
        static StringBuilder sz_class = new StringBuilder(winapi.MAX_CLASS_NAME);
        static IntPtr __hhook_mouse = IntPtr.Zero;
        static winapi.RECT rect = new winapi.RECT(0, 0, 1, 1);

        public Form1()
        {
                InitializeComponent();
        }

        private void on_load(object sender, EventArgs e)
        {
                ListViewItem lvi;
                for (int i = 0; i < 100; i++)
                {
                        lvi = lv_test.Items.Add((100 + i).ToString());
                        lvi.SubItems.Add((200 + i).ToString());
                        lvi.SubItems.Add((300 + i).ToString());
                }
                if (__hhook_mouse == IntPtr.Zero)
                {
                        __hhook_mouse = winapi.SetWindowsHookEx(winapi.WH_MOUSE, MouseProc, IntPtr.Zero, winapi.GetCurrentThreadId());
                        if (null == __hhook_mouse) throw new Exception("Chyba SetWindowsHookEx");
                }
        }

        private void on_closing(object sender, FormClosingEventArgs e)
        {
                if (__hhook_mouse != IntPtr.Zero)
                {
                        winapi.UnhookWindowsHookEx(__hhook_mouse);
                        __hhook_mouse = IntPtr.Zero;
                }
        }

        static IntPtr MouseProc(int nCode, IntPtr wParam, IntPtr lParam)
        {
                if (nCode >= 0 || nCode != winapi.HC_NOREMOVE)
                {
                        if (nCode == winapi.HC_ACTION)
                        {
                                winapi.MOUSEHOOKSTRUCT pmhs = (winapi.MOUSEHOOKSTRUCT)Marshal.PtrToStructure(lParam, winapi.tMOUSEHOOKSTRUCT);
                                switch ((int)wParam)
                                {
                                        case winapi.WM_MOUSEMOVE:
                                                if (winapi.GetKeyState(winapi.VK_LBUTTON) < 0 || winapi.GetKeyState(winapi.VK_RBUTTON) < 0)
                                                {
                                                        if (0 != winapi.GetClassName(pmhs.hWnd, sz_class, winapi.MAX_CLASS_NAME))
                                                        {
                                                                string cname = sz_class.ToString().ToLower();
                                                                if (cname.Contains("listview"))
                                                                {
                                                                        winapi.RedrawWindow(winapi.GetParent(pmhs.hWnd), ref rect, IntPtr.Zero,
                                                                                winapi.RDW_NOERASE | winapi.RDW_INVALIDATE);
                                                                }
                                                        }
                                                }
                                                break;
                                }
                        }
                }
                return winapi.CallNextHookEx(__hhook_mouse, nCode, wParam, lParam);
        }
}

a deklarace těch api funkcí:

using System;
using System.Runtime.InteropServices;
using System.Text;

public static class winapi
{
        public const int MAX_CLASS_NAME = 256;
        public const int HC_NOREMOVE = 3;
        public const int HC_ACTION = 0;

        public const int WM_MOUSEMOVE = 0x0200;
        public const int VK_LBUTTON = 0x01;
        public const int VK_RBUTTON = 0x02;
        public const int RDW_NOERASE = 0x0020;
        public const int RDW_INVALIDATE = 0x0001;
        public const int WH_MOUSE = 7;


        public delegate IntPtr HookProc(int code, IntPtr wParam, IntPtr lParam);

        [StructLayout(LayoutKind.Sequential)]
        public class MOUSEHOOKSTRUCT
        {
                // pt was a by-value POINT structure
                public int pt_x = 0;
                public int pt_y = 0;
                public IntPtr hWnd = IntPtr.Zero;
                public int wHitTestCode = 0;
                public int dwExtraInfo = 0;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
                public int left;
                public int top;
                public int right;
                public int bottom;

                public RECT(int l, int t, int r, int b)
                {
                        left = l;
                        top = t;
                        right = r;
                        bottom = b;
                }
        }
        public static Type tMOUSEHOOKSTRUCT = typeof(MOUSEHOOKSTRUCT);
        [DllImport("kernel32.dll")]
        public static extern uint GetCurrentThreadId();

        [DllImport("user32.dll")]
        public static extern bool RedrawWindow(IntPtr hWnd, ref RECT lprcUpdate, IntPtr hrgnUpdate, int flags);

        [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
        public static extern IntPtr GetParent(IntPtr hWnd);

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr SetWindowsHookEx(int hookid, HookProc pfnhook, IntPtr hinst, uint threadid);

        [DllImport("user32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll")]
        public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll")]
        public static extern short GetKeyState(int key);
}
 
Nahoru Odpovědět
15.2.2018 15:04
Avatar
HONZ4
Člen
Avatar
Odpovídá na Radek Chalupa
HONZ4:15.2.2018 18:39

Tvůj kód funguje lépe, ale po několika (40 - 80) pokusech přeznačení řádků to skončí stejnou chybovou hláškou.
Zvláštní je, že pokud je ListView nastaven na VirtualMode a má víc řádků selže aplikace dřív.

(při testování jsem založil nový projekt a použil tvůj kompletní kód)

Editováno 15.2.2018 18:41
 
Nahoru Odpovědět
15.2.2018 18:39
Avatar
Odpovídá na HONZ4
Radek Chalupa:15.2.2018 19:46

Možná se te callback funkce musí nastavovat přes proměnnou typu delegate, viz. tenhle ukázkový příklad: https://gist.github.com/…onix/3181083
Upravil jsem to podle té ukázky takhle:

public partial class Form1 : Form
{
        static StringBuilder sz_class = new StringBuilder(winapi.MAX_CLASS_NAME);
        static IntPtr __hhook_mouse = IntPtr.Zero;
        static winapi.RECT rect = new winapi.RECT(0, 0, 1, 1);

        private winapi.HookProc _mouse_proc = Form1.MouseProc;

        public Form1()
        {
                InitializeComponent();
        }

        private void on_load(object sender, EventArgs e)
        {
                ListViewItem lvi;
                for (int i = 0; i < 100; i++)
                {
                        lvi = lv_test.Items.Add((100 + i).ToString());
                        lvi.SubItems.Add((200 + i).ToString());
                        lvi.SubItems.Add((300 + i).ToString());
                }
                if (__hhook_mouse == IntPtr.Zero)
                {
                        __hhook_mouse = winapi.SetWindowsHookEx(winapi.WH_MOUSE, _mouse_proc, IntPtr.Zero, winapi.GetCurrentThreadId());
                        if (null == __hhook_mouse) throw new Exception("Chyba SetWindowsHookEx");
                }
        }

        private void on_closing(object sender, FormClosingEventArgs e)
        {
                if (__hhook_mouse != IntPtr.Zero)
                {
                        winapi.UnhookWindowsHookEx(__hhook_mouse);
                        __hhook_mouse = IntPtr.Zero;
                }
        }

        static IntPtr MouseProc(int nCode, IntPtr wParam, IntPtr lParam)
        {
                if (nCode >= 0 || nCode != winapi.HC_NOREMOVE)
                {
                        if (nCode == winapi.HC_ACTION)
                        {
                                winapi.MOUSEHOOKSTRUCT pmhs = (winapi.MOUSEHOOKSTRUCT)Marshal.PtrToStructure(lParam, winapi.tMOUSEHOOKSTRUCT);
                                switch ((int)wParam)
                                {
                                        case winapi.WM_MOUSEMOVE:
                                                if (winapi.GetKeyState(winapi.VK_LBUTTON) < 0 || winapi.GetKeyState(winapi.VK_RBUTTON) < 0)
                                                {
                                                        if (0 != winapi.GetClassName(pmhs.hWnd, sz_class, winapi.MAX_CLASS_NAME))
                                                        {
                                                                string cname = sz_class.ToString().ToLower();
                                                                if (cname.Contains("listview"))
                                                                {
                                                                        winapi.RedrawWindow(winapi.GetParent(pmhs.hWnd), ref rect, IntPtr.Zero,
                                                                                winapi.RDW_NOERASE | winapi.RDW_INVALIDATE);
                                                                }
                                                        }
                                                }
                                                break;
                                }
                        }
                }
                return winapi.CallNextHookEx(__hhook_mouse, nCode, wParam, lParam);
        }
}

na pár pokusů to funguje, tak to vyzkoušej nějakým zátěžovým testem.

jj, zlaté céčko, tam se prostě zadá adresa funkce (napíše její název bez závorek) a je to:-)

 
Nahoru Odpovědět
15.2.2018 19:46
Avatar
HONZ4
Člen
Avatar
Odpovídá na Radek Chalupa
HONZ4:15.2.2018 20:20

Paráda zdá se že to funguje. Otestoval jsem to na listu s VirtualMode s 10 000 000 položek a asi 500 přeznačeními.
Zítra to ještě otestuji na jiných počítačích, i na W7, 32bit W10, + jak se to bude chovat po probuzení z režimu spánku apd.
Zatím díky moc za pomoc, sám bych to do hromady nedal.

ps, Budu doufat, že s jarním update to nepůjde do kytek..

 
Nahoru Odpovědět
15.2.2018 20:20
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 19 zpráv z 19.