Microchip HID_PnP_Demo, WinForm to WPF

1

I've been trying to learn about WPF since I've been using VB.NET and WindowsForm for the past 10 years in a very few small projects.

I'm planning a simple interface to control my house with a PIC18F97J94.

Microchip provides an example (That's part of the MLA solution, it's in C# and WinForm) which I could workaround and finish my project but I want to learn WPF and C#.

The problem I'm encountering is with the .Handle:

RegisterDeviceNotification(this.Handle, pDeviceBroadcastHeader, DEVICE_NOTIFY_WINDOW_HANDLE);

Error CS1061 'MainWindow' does not contain a definition for 'Handle' and no extension method 'Handle' accepting a first argument of type 'MainWindow' could be found.

The full code block is the next one:

public MainWindow()
    {

        InitializeComponent();

        ProgressBar1.ToolTip = ("If using a board/PIM without a potentiometer, apply an adjustable voltage to the I/O pin.");
        ANxVoltage_lbl.ToolTip = ("If using a board/PIM without a potentiometer, apply an adjustable voltage to the I/O pin.");
        ToggleLEDs_btn.ToolTip = ("Sends a packet of data to the USB device.");
        PushbuttonState_lbl.ToolTip = ("Try pressing pushbuttons on the USB demo board/PIM.");

        //Register for WM_DEVICECHANGE notifications.  This code uses these messages to detect plug and play connection/disconnection events for USB devices
        DEV_BROADCAST_DEVICEINTERFACE DeviceBroadcastHeader = new DEV_BROADCAST_DEVICEINTERFACE();
        DeviceBroadcastHeader.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
        DeviceBroadcastHeader.dbcc_size = (uint)Marshal.SizeOf(DeviceBroadcastHeader);
        DeviceBroadcastHeader.dbcc_reserved = 0;    //Reserved says not to use...
        DeviceBroadcastHeader.dbcc_classguid = InterfaceClassGuid;

        //Need to get the address of the DeviceBroadcastHeader to call RegisterDeviceNotification(), but
        //can't use "&DeviceBroadcastHeader".  Instead, using a roundabout means to get the address by 
        //making a duplicate copy using Marshal.StructureToPtr().
        IntPtr pDeviceBroadcastHeader = IntPtr.Zero;  //Make a pointer.
        pDeviceBroadcastHeader = Marshal.AllocHGlobal(Marshal.SizeOf(DeviceBroadcastHeader)); //allocate memory for a new DEV_BROADCAST_DEVICEINTERFACE structure, and return the address 
        Marshal.StructureToPtr(DeviceBroadcastHeader, pDeviceBroadcastHeader, false);  //Copies the DeviceBroadcastHeader structure into the memory already allocated at DeviceBroadcastHeaderWithPointer
        RegisterDeviceNotification(this.Handle, pDeviceBroadcastHeader, DEVICE_NOTIFY_WINDOW_HANDLE);


        //Now make an initial attempt to find the USB device, if it was already connected to the PC and enumerated prior to launching the application.
        //If it is connected and present, we should open read and write handles to the device so we can communicate with it later.
        //If it was not connected, we will have to wait until the user plugs the device in, and the WM_DEVICECHANGE callback function can process
        //the message and again search for the device.
        if (CheckIfPresentAndGetUSBDevicePath())    //Check and make sure at least one device with matching VID/PID is attached
        {
            uint ErrorStatusWrite;
            uint ErrorStatusRead;


            //We now have the proper device path, and we can finally open read and write handles to the device.
            WriteHandleToUSBDevice = CreateFile(DevicePath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
            ErrorStatusWrite = (uint)Marshal.GetLastWin32Error();
            ReadHandleToUSBDevice = CreateFile(DevicePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
            ErrorStatusRead = (uint)Marshal.GetLastWin32Error();

            if ((ErrorStatusWrite == ERROR_SUCCESS) && (ErrorStatusRead == ERROR_SUCCESS))
            {
                AttachedState = true;       //Let the rest of the PC application know the USB device is connected, and it is safe to read/write to it
                AttachedButBroken = false;
                StatusBox_txtbx.Text = "Device Found, AttachedState = TRUE";
            }
            else //for some reason the device was physically plugged in, but one or both of the read/write handles didn't open successfully...
            {
                AttachedState = false;      //Let the rest of this application known not to read/write to the device.
                AttachedButBroken = true;   //Flag so that next time a WM_DEVICECHANGE message occurs, can retry to re-open read/write pipes
                if (ErrorStatusWrite == ERROR_SUCCESS)
                    WriteHandleToUSBDevice.Close();
                if (ErrorStatusRead == ERROR_SUCCESS)
                    ReadHandleToUSBDevice.Close();
            }
        }
        else    //Device must not be connected (or not programmed with correct firmware)
        {
            AttachedState = false;
            AttachedButBroken = false;
        }

        if (AttachedState == true)
        {
            StatusBox_txtbx.Text = "Device Found, AttachedState = TRUE";
        }
        else
        {
            StatusBox_txtbx.Text = "Device not found, verify connect/correct firmware";
        }

        ReadWriteThread.RunWorkerAsync();
    }

Added info: The next code block is what I transferred from the WinForm example, however I get the warning CS0649 in the line:

internal char[] DevicePath;         //TCHAR array of any size

and

internal char[] dbcc_name;          //TCHAR array

Code:

public partial class MainWindow : Window
{
    //-------------------------------------------------------------------------------------------------------------------------------------------------------------------
    //-------------------------------------------------------BEGIN CUT AND PASTE BLOCK-----------------------------------------------------------------------------------

    //Constant definitions from setupapi.h, which we aren't allowed to include directly since this is C#
    internal const uint DIGCF_PRESENT = 0x02;
    internal const uint DIGCF_DEVICEINTERFACE = 0x10;
    //Constants for CreateFile() and other file I/O functions
    internal const short FILE_ATTRIBUTE_NORMAL = 0x80;
    internal const short INVALID_HANDLE_VALUE = -1;
    internal const uint GENERIC_READ = 0x80000000;
    internal const uint GENERIC_WRITE = 0x40000000;
    internal const uint CREATE_NEW = 1;
    internal const uint CREATE_ALWAYS = 2;
    internal const uint OPEN_EXISTING = 3;
    internal const uint FILE_SHARE_READ = 0x00000001;
    internal const uint FILE_SHARE_WRITE = 0x00000002;
    //Constant definitions for certain WM_DEVICECHANGE messages
    internal const uint WM_DEVICECHANGE = 0x0219;
    internal const uint DBT_DEVICEARRIVAL = 0x8000;
    internal const uint DBT_DEVICEREMOVEPENDING = 0x8003;
    internal const uint DBT_DEVICEREMOVECOMPLETE = 0x8004;
    internal const uint DBT_CONFIGCHANGED = 0x0018;
    //Other constant definitions
    internal const uint DBT_DEVTYP_DEVICEINTERFACE = 0x05;
    internal const uint DEVICE_NOTIFY_WINDOW_HANDLE = 0x00;
    internal const uint ERROR_SUCCESS = 0x00;
    internal const uint ERROR_NO_MORE_ITEMS = 0x00000103;
    internal const uint SPDRP_HARDWAREID = 0x00000001;

    enum WM_DEVICECHANGE_ENUM : int//Public Enum WM_DEVICECHANGE As Integer
    {
        DBT_CONFIGCHANGECANCELED = 0x19,
        DBT_CONFIGCHANGED = 0x18,
        DBT_CUSTOMEVENT = 0x8006,
        DBT_DEVICEARRIVAL = 0x8000,
        DBT_DEVICEQUERYREMOVE = 0x8001,
        DBT_DEVICEQUERYREMOVEFAILED = 0x8002,
        DBT_DEVICEREMOVECOMPLETE = 0x8004,
        DBT_DEVICEREMOVEPENDING = 0x8003,
        DBT_DEVICETYPESPECIFIC = 0x8005,
        DBT_DEVNODES_CHANGED = 0x7,
        DBT_QUERYCHANGECONFIG = 0x17,
        DBT_USERDEFINED = 0xFFFF
    }//End Enum


    //Various structure definitions for structures that this code will be using
    internal struct SP_DEVICE_INTERFACE_DATA
    {
        internal uint cbSize;               //DWORD
        internal Guid InterfaceClassGuid;   //GUID
        internal uint Flags;                //DWORD
        internal uint Reserved;             //ULONG_PTR MSDN says ULONG_PTR is "typedef unsigned __int3264 ULONG_PTR;"  
    }

    internal struct SP_DEVICE_INTERFACE_DETAIL_DATA
    {
        internal uint cbSize;               //DWORD
        internal char[] DevicePath;         //TCHAR array of any size
    }

    internal struct SP_DEVINFO_DATA
    {
        internal uint cbSize;       //DWORD
        internal Guid ClassGuid;    //GUID
        internal uint DevInst;      //DWORD
        internal uint Reserved;     //ULONG_PTR  MSDN says ULONG_PTR is "typedef unsigned __int3264 ULONG_PTR;"  
    }

    internal struct DEV_BROADCAST_DEVICEINTERFACE
    {
        internal uint dbcc_size;            //DWORD
        internal uint dbcc_devicetype;      //DWORD
        internal uint dbcc_reserved;        //DWORD
        internal Guid dbcc_classguid;       //GUID
        internal char[] dbcc_name;          //TCHAR array
    }

    //DLL Imports.  Need these to access various C style unmanaged functions contained in their respective DLL files.
    //--------------------------------------------------------------------------------------------------------------
    //Returns a HDEVINFO type for a device information set.  We will need the 
    //HDEVINFO as in input parameter for calling many of the other SetupDixxx() functions.
    [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    internal static extern IntPtr SetupDiGetClassDevs(
        ref Guid ClassGuid,     //LPGUID    Input: Need to supply the class GUID. 
        IntPtr Enumerator,      //PCTSTR    Input: Use NULL here, not important for our purposes
        IntPtr hwndParent,      //HWND      Input: Use NULL here, not important for our purposes
        uint Flags);            //DWORD     Input: Flags describing what kind of filtering to use.

    //Gives us "PSP_DEVICE_INTERFACE_DATA" which contains the Interface specific GUID (different
    //from class GUID).  We need the interface GUID to get the device path.
    [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    internal static extern bool SetupDiEnumDeviceInterfaces(
        IntPtr DeviceInfoSet,           //Input: Give it the HDEVINFO we got from SetupDiGetClassDevs()
        IntPtr DeviceInfoData,          //Input (optional)
        ref Guid InterfaceClassGuid,    //Input 
        uint MemberIndex,               //Input: "Index" of the device you are interested in getting the path for.
        ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData);    //Output: This function fills in an "SP_DEVICE_INTERFACE_DATA" structure.

    //SetupDiDestroyDeviceInfoList() frees up memory by destroying a DeviceInfoList
    [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    internal static extern bool SetupDiDestroyDeviceInfoList(
        IntPtr DeviceInfoSet);          //Input: Give it a handle to a device info list to deallocate from RAM.

    //SetupDiEnumDeviceInfo() fills in an "SP_DEVINFO_DATA" structure, which we need for SetupDiGetDeviceRegistryProperty()
    [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    internal static extern bool SetupDiEnumDeviceInfo(
        IntPtr DeviceInfoSet,
        uint MemberIndex,
        ref SP_DEVINFO_DATA DeviceInterfaceData);

    //SetupDiGetDeviceRegistryProperty() gives us the hardware ID, which we use to check to see if it has matching VID/PID
    [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    internal static extern bool SetupDiGetDeviceRegistryProperty(
        IntPtr DeviceInfoSet,
        ref SP_DEVINFO_DATA DeviceInfoData,
        uint Property,
        ref uint PropertyRegDataType,
        IntPtr PropertyBuffer,
        uint PropertyBufferSize,
        ref uint RequiredSize);

    //SetupDiGetDeviceInterfaceDetail() gives us a device path, which is needed before CreateFile() can be used.
    [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    internal static extern bool SetupDiGetDeviceInterfaceDetail(
        IntPtr DeviceInfoSet,                   //Input: Wants HDEVINFO which can be obtained from SetupDiGetClassDevs()
        ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData,                    //Input: Pointer to an structure which defines the device interface.  
        IntPtr DeviceInterfaceDetailData,      //Output: Pointer to a SP_DEVICE_INTERFACE_DETAIL_DATA structure, which will receive the device path.
        uint DeviceInterfaceDetailDataSize,     //Input: Number of bytes to retrieve.
        ref uint RequiredSize,                  //Output (optional): The number of bytes needed to hold the entire struct 
        IntPtr DeviceInfoData);                 //Output (optional): Pointer to a SP_DEVINFO_DATA structure

    //Overload for SetupDiGetDeviceInterfaceDetail().  Need this one since we can't pass NULL pointers directly in C#.
    [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    internal static extern bool SetupDiGetDeviceInterfaceDetail(
        IntPtr DeviceInfoSet,                   //Input: Wants HDEVINFO which can be obtained from SetupDiGetClassDevs()
        ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData,               //Input: Pointer to an structure which defines the device interface.  
        IntPtr DeviceInterfaceDetailData,       //Output: Pointer to a SP_DEVICE_INTERFACE_DETAIL_DATA structure, which will contain the device path.
        uint DeviceInterfaceDetailDataSize,     //Input: Number of bytes to retrieve.
        IntPtr RequiredSize,                    //Output (optional): Pointer to a DWORD to tell you the number of bytes needed to hold the entire struct 
        IntPtr DeviceInfoData);                 //Output (optional): Pointer to a SP_DEVINFO_DATA structure

    //Need this function for receiving all of the WM_DEVICECHANGE messages.  See MSDN documentation for
    //description of what this function does/how to use it. Note: name is remapped "RegisterDeviceNotificationUM" to
    //avoid possible build error conflicts.
    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    internal static extern IntPtr RegisterDeviceNotification(
        IntPtr hRecipient,
        IntPtr NotificationFilter,
        uint Flags);

    //Takes in a device path and opens a handle to the device.
    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    static extern SafeFileHandle CreateFile(
        string lpFileName,
        uint dwDesiredAccess,
        uint dwShareMode,
        IntPtr lpSecurityAttributes,
        uint dwCreationDisposition,
        uint dwFlagsAndAttributes,
        IntPtr hTemplateFile);

    //Uses a handle (created with CreateFile()), and lets us write USB data to the device.
    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    static extern bool WriteFile(
        SafeFileHandle hFile,
        byte[] lpBuffer,
        uint nNumberOfBytesToWrite,
        ref uint lpNumberOfBytesWritten,
        IntPtr lpOverlapped);

    //Uses a handle (created with CreateFile()), and lets us read USB data from the device.
    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    static extern bool ReadFile(
        SafeFileHandle hFile,
        IntPtr lpBuffer,
        uint nNumberOfBytesToRead,
        ref uint lpNumberOfBytesRead,
        IntPtr lpOverlapped);



    //--------------- Global Varibles Section ------------------
    //USB related variables that need to have wide scope.
    bool AttachedState = false;                     //Need to keep track of the USB device attachment status for proper plug and play operation.
    bool AttachedButBroken = false;
    SafeFileHandle WriteHandleToUSBDevice = null;
    SafeFileHandle ReadHandleToUSBDevice = null;
    String DevicePath = null;   //Need the find the proper device path before you can open file handles.


    //Variables used by the application/form updates.
    bool PushbuttonPressed = false;     //Updated by ReadWriteThread, read by FormUpdateTimer tick handler (needs to be atomic)
    bool ToggleLEDsPending = false;     //Updated by ToggleLED(s) button click event handler, used by ReadWriteThread (needs to be atomic)
    uint ADCValue = 0;          //Updated by ReadWriteThread, read by FormUpdateTimer tick handler (needs to be atomic)
    uint ADCDiff = 0;
    //Globally Unique Identifier (GUID) for HID class devices.  Windows uses GUIDs to identify things.
    Guid InterfaceClassGuid = new Guid(0x4d1e55b2, 0xf16f, 0x11cf, 0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30);
    //--------------- End of Global Varibles ------------------

    //-------------------------------------------------------END CUT AND PASTE BLOCK-------------------------------------------------------------------------------------
    //-------------------------------------------------------------------------------------------------------------------------------------------------------------------

    WindowInteropHelper interopHelper;
    private BackgroundWorker ReadWriteThread = new BackgroundWorker();
    private DispatcherTimer timer;
    private Int32 BytesControl = 0;//Convert.ToInt32("000000000000000000000001", 2);
c#
.net
wpf
vb.net
winforms
asked on Stack Overflow Feb 5, 2016 by Suspeso • edited Feb 16, 2016 by Suspeso

2 Answers

0

Replace this.Handle with the following:

new WindowInteropHelper(myWindow).Handle

WindowInteropHelper class is in the System.Windows.Interop namespace. And myWindow is the name of your Window.

answered on Stack Overflow Feb 5, 2016 by stratever
0

Nevermind. The Window_Loaded event wasn't related to the function:

Here's my fix:

MainWindow_Loaded isn't triggered on my WPF Application

answered on Stack Overflow Feb 16, 2016 by Suspeso • edited May 23, 2017 by Community

User contributions licensed under CC BY-SA 3.0