pbatard / libwdi

Windows Driver Installer library for USB devices
GNU General Public License v3.0
1.87k stars 466 forks source link

WDI_ERROR_EXISTS when calling wdi_install_driver #82

Closed ghost closed 7 years ago

ghost commented 7 years ago

Hello

I am trying to replace a driver from a specific USB device with libwdi. So i followed your instructions from the wiki -> Basic usage and wrote the following code:

for (device = list; device != NULL; device = device->next)
{
     if(device->pid == 0x003F)
     {
           wdi_options_prepare_driver prepareOptions;
           prepareOptions.driver_type= WDI_WINUSB;
           int errorCode = wdi_prepare_driver(device,"driver","driver.inf",&prepareOptions);
           int errorcode2 = wdi_install_driver(device,"driver","driver.inf",NULL);
     }
}
wdi_destroy_list(list);

My problem is that when i am debugging errorCode is 0 like it should be. But errorCode2 is -13 wich says "Entity already exists" and i don't quite understand why i get this error here. Is there something i miss ?

Thank you for your help

pbatard commented 7 years ago
  1. Be careful about replacing a driver by checking the PID only. How do you know you don't have another USB device with PID 0x003F? You should ALWAYS make sure both the VID and PID match, else you are asking for trouble.

  2. Hard to tell what's going on without a log. Please set a log going, with debug output, with wdi_set_log_level(...). Or at the very least, have a look at what your C:\Windows\INF\setupapi.dev.log says.

  3. Do you know that libwdi also provides comprehensive examples, such as wdi-simple.c? I would encourage you to start from wdi-simple and see what you get there (with option -l 0 to get debug output).

ghost commented 7 years ago

Ok thank you for your tips im gonna check the logs and the wdi-simple example. I will comment again then i have more information for you or fixed the error.

ghost commented 7 years ago

I changed my code to the following :

for (device = list; device != NULL; device = device->next)
       {
             if(device->pid == 0x003F && device->vid == 0x04D8)
             {
                    wdi_set_log_level(WDI_LOG_LEVEL_DEBUG);
                    wdi_options_prepare_driver prepareOptions;
                    prepareOptions.driver_type= WDI_WINUSB;
                    prepareOptions.device_guid= "{745a17a0-74d3-11d0-b6fe-00a0c90f57da}";
                    qDebug() << "prepare the driver for later installation";
                    errorCode = wdi_prepare_driver(device,"driver","driver.inf",&prepareOptions);
                    qDebug() << QString::number(errorCode);
                    qDebug() << "install driver";
                    int errorcode2 = wdi_install_driver(device,"driver","driver.inf",NULL);
                    qDebug() << QString::number(errorcode2);

              }
        }
wdi_destroy_list(list);

And the console gives me the following Output:

image

"Force option required" I dont really know what to do with this message. I already tried to set the guid: prepareOptions.device_guid= "{745a17a0-74d3-11d0-b6fe-00a0c90f57da}"; But otherwise i dont know how to set the "Force option".

Edit : wdi-simple installs the driver successfully.

pbatard commented 7 years ago

Please don't set device_guid. It's only meant to be used if you embed your own custom drive in libwdi.

I think your issue is that you are treating the call to wdi_create_list(...) as optional, which it isn't. Please don't remove important parts from the sample code, and then wonder why your doesn't work.

You must pick your device from wdi_create_list(...). Creating a device manually will not work.

pbatard commented 7 years ago

Update: Or maybe you just didn't copy/paste the wdi_create_list(...) call? At any rate, I would suggest you start from wdi_simple.c and the modify the code there to find out what is wrong with your sample.

ghost commented 7 years ago

Ok i am sorry i didnt show you the whole code. Of course i call wdi_create_list and i dont create my own device i pick the device i get from the list. I get that i should not set the GUID. I did actually copied the code from your wiki and added my own code. I think the code really should work thats why i created the issue. I will come back to my workplace at monday so i can show you the whole code and that its really how it should be.

Just one question : Do you know anything about the force option mentioned by the logger?

Thank you for your patience

pbatard commented 7 years ago

Do you know anything about the force option mentioned by the logger?

Yes, but it's not gonna help. The message you got is a result of the UpdateDriverForPlugAndPlayDevices() Windows API call returning ERROR_NO_MORE_ITEMS (which libwdi then translates to the message you got).

As per Microsoft's documentation ERROR_NO_MORE_ITEMS means:

The function found a match for the HardwareId value, but the specified driver was not a better match than the current driver and the caller did not specify the INSTALLFLAG_FORCE flag.

However, libwdi does use the INSTALLFLAG_FORCE flag when invoking UpdateDriverForPlugAndPlayDevices(), so I'm not sure why your call seems to return ERROR_NO_MORE_ITEMS....

ghost commented 7 years ago

Ok so here is my entire code:

   wdi_device_info * device, *list;
   wdi_options_create_list listOptions;
   listOptions.list_all= true;

   int errorCode = wdi_create_list(&list, &listOptions);
   if (errorCode == WDI_SUCCESS)
   {
          for (device = list; device != NULL; device = device->next)
          {
                   if(device->pid == 0x003F && device->vid == 0x04D8)
                   {
                            wdi_set_log_level(WDI_LOG_LEVEL_DEBUG);

                            wdi_options_prepare_driver prepareOptions;
                            prepareOptions.driver_type= WDI_WINUSB;
                            prepareOptions.device_guid= "{745a17a0-74d3-11d0-b6fe-00a0c90f57da}";
                            errorCode = wdi_prepare_driver(device,"driver","driver.inf",&prepareOptions);

                            int errorcode2 = wdi_install_driver(device,"driver","driver.inf",NULL);
                   }
           }
           wdi_destroy_list(list);
   }

wich generates the following output: image

I think my code and the wdi-simple example does more or less the same. The biggest difference is that it installs a certificate wich i dont need in my case. I really think there is some kind of problem with the library.

I already tried to debug the library with some breakpoints inside the install_driver_internal method. The result of this debugging is really akward sometimes the install_driver_internal returns 0 but the driver does not get installed sometimes it returns 99 and sometimes it returns -11. However if i dont debug my application and just run it i always get the return value -13.

Here is and example of the console output when i am debugging : image I used zadig to show that the driver has not been replaced. I already replugged the device and refreshed zadig with f5.

Something wich is kinda strange is that in the case of the return value being -13 the hardware_id can be read. But if the return value is 0 the applications fails to read the hardware_id. Since the line of code you link in your comment : b = UpdateDriverForPlugAndPlayDevicesU(NULL, hardware_id, path, INSTALLFLAG_FORCE, NULL); is using the hardware_id and is related to the INSTALL_FORCE flag. I think my error is somewhere releated to the hardware_id.

Edit: Ok i just found out why the results differentiate whether i am debugging or not: The request for the hardware_id times out if i wait to long between the breakpoints. So i am still trying to find out why the function returns 0 if the request times out and why it returns -13 of the request actually works as it should.

Update : The installer seems to run successfully as the following screenshot shows: image So i assume the installer passes the follwing line and sets the INSTALLFLAG_FORCE. b = UpdateDriverForPlugAndPlayDevicesU(NULL, hardware_id, path, INSTALLFLAG_FORCE, NULL); Wich makes me wonder why i get my error message.

Update : I just checked the setupapi log: setupapi.dev.txt I also checked this log file using zadip and there seems to be a critical error wich only appears when i am using my project :

DIF_SELECTBESTCOMPATDRV} 11:07:52.026
     dvi:      No class installer for 'USB Input Device'
     dvi:      No CoInstallers found
     dvi:      Default installer: Enter 11:07:52.028
     dvi:           {Select Best Driver}
!    dvi:                Selecting driver failed(0xe0000228)
     dvi:           {Select Best Driver - exit(0xe0000228)}
!    dvi:      Default installer: failed!
!    dvi:      Error 0xe0000228: There are no compatible drivers for this device.
     dvi: {DIF_SELECTBESTCOMPATDRV - exit(0xe0000228)} 11:07:52.030

Now i dont really now how to resolve this error.

By the way:

The prepare function seems to run successfully: Folder structure: image image

And this is the content of the inf file :

; driver.inf
; Copyright (c) 2010-2016 Pete Batard <pete@akeo.ie(GNU LGPL)
[Strings]
DeviceName = "Common_USB_Controller"
VendorName = "Microchip Technology, Inc."
SourceName = "Common_USB_Controller Install Disk"
DeviceID   = "MS_COMP_WINUSB"
DeviceGUID = "UNUSED"

[Version]
Signature   = "$Windows NT$"
Class       = "USBDevice"
ClassGuid   = {88bae032-5a81-49f0-bc3d-a4ff138216d6}
Provider    = "libwdi"
CatalogFile = driver.cat
DriverVer   = 05/25/2016, 6.1.7600.16385

[ClassInstall32]
Addreg = WinUSBDeviceClassReg

[WinUSBDeviceClassReg]
HKR,,,0,"Universal Serial Bus devices"
HKR,,Icon,,-20

[Manufacturer]
%VendorName% = libusbDevice_WinUSB,NTx86,NTamd64,NTarm

[libusbDevice_WinUSB.NTx86]
%DeviceName% = USB_Install, USB\%DeviceID%

[libusbDevice_WinUSB.NTamd64]
%DeviceName% = USB_Install, USB\%DeviceID%

[libusbDevice_WinUSB.NTarm]
%DeviceName% = USB_Install, USB\%DeviceID%

[USB_Install]
Include = winusb.inf
Needs   = WINUSB.NT

[USB_Install.Services]
Include    = winusb.inf
AddService = WinUSB,0x00000002,WinUSB_ServiceInstall

[WinUSB_ServiceInstall]
DisplayName   = "WinUSB - Kernel Driver 05/25/2016 6.1.7600.16385"
ServiceType   = 1
StartType     = 3
ErrorControl  = 1
ServiceBinary = %12%\WinUSB.sys

[USB_Install.Wdf]
KmdfService = WINUSB, WinUsb_Install

[WinUSB_Install]
KmdfLibraryVersion = 1.11

[USB_Install.HW]
AddReg = NoDeviceInterfaceGUID

[NoDeviceInterfaceGUID]
; Avoids adding a DeviceInterfaceGUID for generic driver

[AddDeviceInterfaceGUID]
HKR,,DeviceInterfaceGUIDs,0x10000,%DeviceGUID%

[USB_Install.CoInstallers]
AddReg    = CoInstallers_AddReg
CopyFiles = CoInstallers_CopyFiles

[CoInstallers_AddReg]
HKR,,CoInstallers32,0x00010000,"WdfCoInstaller01011.dll,WdfCoInstaller","WinUSBCoInstaller2.dll"

[CoInstallers_CopyFiles]
WinUSBCoInstaller2.dll
WdfCoInstaller01011.dll

[DestinationDirs]
CoInstallers_CopyFiles = 11

[SourceDisksNames]
1 = %SourceName%

[SourceDisksFiles.x86]
WinUSBCoInstaller2.dll = 1,x86
WdfCoInstaller01011.dll = 1,x86

[SourceDisksFiles.amd64]
WinUSBCoInstaller2.dll = 1,amd64
WdfCoInstaller01011.dll = 1,amd64

[SourceDisksFiles.arm]
WinUSBCoInstaller2.dll = 1,arm
WdfCoInstaller01011.dll = 1,arm

Here you have the exact build of the library i use, in case you want to reproduce this error : built_library.txt (You have to change to file extension from txt to zip because i couldnt uplaod a zip file)

Just for your info : -> The "driver installation failed" output is from my code it checks if the driver is actually exchanged its not from the libwdi.

pbatard commented 7 years ago

I used zadig to show that the driver has not been replaced.

Huh? Your device is HID??

In that case, that could very well explain your issue. Windows will install a driver automatically for HID, so you are going to have to tell it to replace and existing driver, in which case Windows has a set of rules to determine whether it believes the drive you are trying to install is "better" than the existing one, and whether to allow that or not.

The biggest difference is that it installs a certificate wich i dont need in my case.

I very much believe you do. The certificate that is installed is the one that signs the driver package, and which comes into consideration by Windows to determine the eligibility of the new driver to replace the old one.

As you may expect, Windows tends to prefer driver packages that are signed over ones that aren't, so my guess is that the eligibility rules for replacing an HID driver require the driver package to be signed.

The sample code provide in the libwdi assumes that you are going to install a driver for a device that doesn't already have one. If you are replacing a driver, and especially a Windows native one, then all bets are off.

If you have control over your device firmware, I would strongly suggest that you don't make it HID (coz I really don't see what's the point, if you're not going to be using it in HID mode anyway). Then you may be able to install an unsigned driver package. Otherwise, I strongly suggest that you let libwdi sign the driver package for you.

FYI, you can get some background information on these certificates here.

I also hope that you can appreciate that my time is limited, and that there's only so much support I can provide. As I suggested previously, since you have found that wdi_simple works, but not your code, I suggest that you simply start from wdi_simple and remove the parts you don't need.

ghost commented 7 years ago

Thank you for your help. I will try to sign the driver and if that does not work i contact the person who worte the firmware of the device. The reason why i want to use the WinUsb driver is that the libusb(c++ version) library only supports some functions using the WinUsb driver. I will come back to you if the problem is solved

ghost commented 7 years ago

Ok seems like i need to discuss this issue with the developer of the software on the HID device. I close this issue for now, i really appreciate your work / support.