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);
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.
Nevermind. The Window_Loaded event wasn't related to the function:
Here's my fix:
User contributions licensed under CC BY-SA 3.0