Changes between Version 18 and Version 19 of libwdi/reuse


Ignore:
Timestamp:
04/19/11 11:59:53 (2 years ago)
Author:
pbatard
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • libwdi/reuse

    v18 v19  
    1 = Reusable parts of the project / solutions to common problems = 
    2  
    3 Libwdi implements reusable solutions to the following problems: 
    4  
    5 == Creating a Windows application that uses the exact same codebase for MSVC, WDK/DDK, MinGW and cygwin == 
    6    3 sets of files are being used for that: 
    7    * For MinGW/cygwin, autotools scripts, that automatically generate the {{{config.h}}} and Makefiles used during compilation 
    8    * For MSVC/Visual Studio, a regular set of project files, depending on the manually edited {{{/msvc/config.h}}} 
    9    * For DDK/WDK, a batch script, depending on the manually edited {{{/msvc/config.h}}} 
    10  
    11   ||=File(s): (MinGW/cygwin) =||[http://git.libusb.org/?p=libwdi.git;a=blob;f=autogen.sh /autogen.sh], [http://git.libusb.org/?p=libwdi.git;a=blob;f=configure.ac /configure.ac], [http://git.libusb.org/?p=libwdi.git;a=blob;f=Makefile.am /Makefile.am], [http://git.libusb.org/?p=libwdi.git;a=blob;f=libwdi/Makefile.am /libwdi/Makefile.am], [http://git.libusb.org/?p=libwdi.git;a=blob;f=examples/Makefile.am /examples/Makefile.am] || 
    12   ||=File(s): (MSVC) =||{{{*.sln}}}, {{{*.vcproj}}} || 
    13   ||=File(s): (DDK) =||[http://git.libusb.org/?p=libwdi.git;a=blob;f=ddk_build.cmd /ddk_build.cmd], {{{*_sources}}} || 
    14 == Creating a Windows application that is compatible with all versions of Windows from 2000 == 
    15   The trick is to use MinGW as the compiler along with the {{{-DWINVER=0x500}}} flag. 
    16   ||=File(s): =||[http://git.libusb.org/?p=libwdi.git;a=blob;f=configure.ac /configure.ac] || 
    17 == Creating a Windows GUI application that use the latest Windows visual enhancements (Aero Glass look on Vista or Windows 7), even if compiled from MinGW/cygwin == 
    18   The default from all compilers, including Microsoft ones, is NOT to use the default look and feel from each platform, but to force the XP/2k one.[[BR]] 
    19   To enable a more up to date look and feel in standard GUI applications, you need to manually embed the [http://git.libusb.org/?p=libwdi.git;a=blob;f=examples/common_controls.manifest common-controls manifest], as well as include {{{<commctrl.h>}}} in your source. 
    20   * For MSVC projects, just adding the manifest to your resources files in the project will do.[[BR]]  
    21   * For DDK/WDK, as documented [http://jpassing.com/2008/02/01/how-to-use-manifests-with-buildexe here], you need to add an {{{SXS_APPLICATION_MANIFEST}}} line with the name of your manifest 
    22   * For MinGW/cywgin, it's a bit more tricky. What you want to do is link to the manifest in your .rc file, with something like {{{CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "common_controls.manifest"}}}. The problem is that, this needs to appear at the end, else MinGW will ignore it, and you want to be able to edit your .rc in Visual Studio, without destroying the additional data you add to the .rc. The solution is to have the following at the beginning of your .rc 
    23   {{{ 
    24 3 TEXTINCLUDE  
    25 BEGIN 
    26     " 
    27 " 
    28     "// Must reference a manifest for visual styles 
    29 " 
    30     "// Oh, and it must happen at the end, or MinGW will ignore it! 
    31 " 
    32     "#if defined(__GNUC__) 
    33 " 
    34     "CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST ""common_controls.manifest"" 
    35 " 
    36     "#endif 
    37 " 
    38     "" 
    39 END 
    40 }}} 
    41   And of course, you need a matching section at the end. 
    42  
    43   ||=File(s): =||[http://git.libusb.org/?p=libwdi.git;a=blob;f=examples/common_controls.manifest common-controls manifest], [http://git.libusb.org/?p=libwdi.git;a=blob;f=examples/zadig_sources example DDK sources (Zadig)], [http://git.libusb.org/?p=libwdi.git;a=blob;f=examples/zadig.rc example MinGW manifest from .rc (Zadig)] || 
    44 == Creating Windows application from MSVC, WDK/DDK, MinGW and cygwin that require UAC elevation, even if compiled from MinGW/cygwin == 
    45   The solution to that is similar to the above one, in that you need to use [http://git.libusb.org/?p=libwdi.git;a=blob;f=examples/elevation.manifest a manifest for elevation].[[BR]] 
    46   In our project, you will see that we combine multiple manifests were needed (this is the case for the Zadig example above for instance), as DDK is not able to merge separate manifests files. Also, recent versions of Visual Studio don't require an explicit manifest file for elevation, as this can be taken care of in Linker -> Manifest File -> UAC Execution Level. 
    47  
    48  ||=File(s): =||[http://git.libusb.org/?p=libwdi.git;a=blob;f=examples/elevation.manifest /examples/elevation.manifest]|| 
    49 == Detecting if an application is running on a 32 or 64 bit Windows OS == 
    50   Depending on the OS being run, libwdi requires a 32 or 64 bit version of the driver installer to be run. The following section of code can be used to detect if a process is running as 32 or 64 bit code: 
    51 {{{ 
    52 #!C 
    53         BOOL is_x64 = FALSE; 
    54         // Detect whether if we should run the 64 bit installer, without 
    55         // relying on external libs 
    56         if (sizeof(uintptr_t) < 8) { 
    57                 // This application is not 64 bit, but it might be 32 bit 
    58                 // running in WOW64 
    59                 pIsWow64Process = (BOOL (__stdcall *)(HANDLE, PBOOL)) 
    60                         GetProcAddress(GetModuleHandle("KERNEL32"), "IsWow64Process"); 
    61                 if (pIsWow64Process != NULL) { 
    62                         (*pIsWow64Process)(GetCurrentProcess(), &is_x64); 
    63                 } 
    64         } else { 
    65                 is_x64 = TRUE; 
    66         } 
    67 }}} 
    68   ||=File(s): =||[http://git.libusb.org/?p=libwdi.git;a=blob;f=libwdi/libwdi.c /libwdi/libwdi.c] -> install_driver_internal() || 
    69 == Compiling an project for both 32 and 64 bit == 
    70   When possible, because of the need for an embedded driver installer that matches the bitsize of the Windows OS, we need to compile both 32 bit and a 64 bit installer at the same time. This is how we addressed that problem: 
    71   * Visual Studio is pretty straightforward, so we won't document it. 
    72   * For DDK, switching between 32 and 64 bit can be done on the fly in the batch file. The environment variables you need to modify to switch between 32 and 64 bit are: {{{_BUILDARCH}}}, {{{386}}}, {{{AMD64}}} and {{{BUILD_DEFAULT_TARGETS}}}, as well as the {{{PATH}}}. 
    73   * For MinGW, provided that you use a multilib MinGW-w64 for compilation, switching between 32 and 64 bit can be easily achieved on the fly as well with the {{{-m32}}}/{{{-m64}}} {{{CFLAGS}}}/{{{LDFLAGS}}} options. You can also do configure time 32/64 bit support detection or enabling/disabling through configure.ac, or to set the default to be 32 bit, with only the required files as 64. 
    74  
    75   ||=File(s): (MinGW) =||[http://git.libusb.org/?p=libwdi.git;a=blob;f=libwdi/Makefile.am /Makefile.am] [http://git.libusb.org/?p=libwdi.git;a=blob;f=configure.ac /configure.ac] || 
    76   ||=File(s): (DDK) =||[http://git.libusb.org/?p=libwdi.git;a=blob;f=ddk_build.cmd /ddk_build.cmd] || 
    77 == Folder selection / File open/save Windows dialogs that uses to new enhanced Vista or Windows 7 controls when available (and default to the regular version on older platforms) == 
    78   This is all done in the {{{file_dialog()}}} and {{{browse_for_folder()}}} calls from {{{zadig_stdlg.c}}}. 
    79   ||=File(s): (DDK) =||[http://git.libusb.org/?p=libwdi.git;a=blob;f=examples/zadig_stdlg.c /examples/zadig_stdlg.c] || 
    80 == USB hotplug detection == 
    81   1. When not using {{{RegisterDeviceNotification()}}}, Windows sends an undefined number of {{{WM_DEVICECHANGE}}} events in rapid sequence, all with the '''exact same''' {{{wParam}}}/{{{lParam}}} so that we cannot differentiate between them. Notifying on each of those would bother the user too much. 
    82   1. When using {{{RegisterDeviceNotification()}}}, it is possible to get unique {{{WM_DEVICECHANGE}}} events but only for devices that already have a driver, because there is no device interface class for unknown/driverless devices and Microsoft has not publicized any way of doing so, it is NOT possible to get a single notification event for insertion/removal of devices that don't have a driver.[[BR]]Our solution then is to initiate delayed notification thread on the first {{{WM_DEVICECHANGE}}} message we receive, and wait for this thread to send a user defined event back to our main callback. 
    83  
    84   ||=File(s): =||[http://git.libusb.org/?p=libwdi.git;a=blob;f=examples/zadig.c /examples/zadig.c] -> {{{main_callback()}}} & {{{notification_delay_thread()}}} || 
    85 == USB device listing, including driverless devices == 
    86   ||=File(s): =||[http://git.libusb.org/?p=libwdi.git;a=blob;f=libwdi/libwdi.c /libwdi/libwdi.c] -> {{{wdi_create_list()}}} || 
    87 == Bumping the executable/DLL version number automatically using git tags == 
    88    If you are using versioning in .rc files, it would obviously be nice to bump the version minor according to major commits that you push into your git repository.[[BR]] 
    89    In libwdi's case, we use incremental git tags to identify minor versions ("w123", "w124", ...) and we use the numeric part of that tag as the minor for the exe/DLL (eg. "1, 0, 0, 123"). The shell script linked below will: 
    90    1. retrieve and increment the current git tag 
    91    2. update the version in the .rc files using sed 
    92    3. commit the changes in git 
    93    Additionally, the script also updates the USB VID -> Vendor ID string source (see below). 
    94  
    95   ||=File(s): =||[http://git.libusb.org/?p=libwdi.git;a=blob;f=_bump.sh /_bump.sh] || 
    96 == Windows GUI !MouseOver/Hover Tooltip == 
    97    A simple call that creates and displays a tooltip when hovering over a dialog item (eg. text field) 
    98  
    99   ||=File(s): =||[http://git.libusb.org/?p=libwdi.git;a=blob;f=examples/zadig_stdlg.c /examples/zadig_stdlg.c] -> create_tooltip() || 
    100 == Sed script to convert the USB VIDs into a C source that will resolve then to Vendor ID strings == 
    101    In our applications, this is used to display the Vendor name of a specific USB device when hovering over the VID hex string.[[BR]] 
    102    http://www.linux-usb.org/usb.ids does a great job at maintaining known Vendor IDs, but the list still needs to be converted into something [http://git.libusb.org/?p=libwdi.git;a=blob;f=libwdi/vid_data.c a bit more C-friendly]. For that purpose we built a shell script that, when executed: 
    103    1. uses wget to retrieve the latest version of the list 
    104    2. uses sed to convert it to a C source with a function call that will take a VID and return the matching string. 
    105  
    106   ||=File(s): =||[http://git.libusb.org/?p=libwdi.git;a=blob;f=libwdi/vid_data.sh /libwdi/vid_data.sh] || 
    107 == UTF-8 wrappers to Wide Char (UTF-16) MS API == 
    108   This is what Microsoft should have done a long time ago. Along with the A (Ansi) and W (!WideChar/Unicode) versions of an API call, it should have implemented U (UTF-8) as well, as it usually makes more sense to use UTF-8 than UTF-16 in an application, especially one that is not localized but still wants to support localized user input. For instance, wouldn't it be nice if there existed a  [http://msdn.microsoft.com/en-us/library/aa363858.aspx CreateFile] version that accepted an UTF-8 char * for the file name?[[BR]] 
    109   Our UTF-8 wrapper API provides just that, for a selected subset of the Windows API calls, with: 
    110   * {{{FormatMessage}}} ({{{FormatMessageU}}}) 
    111   * {{{SendMessage}}} ({{{SendMessageLU}}}: {{{lParam}}} as UTF-8) 
    112   * {{{SHGetPathFromIDList}}} ({{{SHGetPathFromIDListU}}}) 
    113   * {{{CreateWindow}}} ({{{CreateWindowU}}}) 
    114   * {{{GetWindowText}}}/{{{SetWindowText}}} ({{{GetWindowTextU}}}/{{{SetWindowTextU}}}) 
    115   * {{{GetWindowTextLength}}} ({{{GetWindowTextLengthU}}}) 
    116   * {{{GetDlgItemText}}}/{{{SetDlgItemText}}} ({{{GetDlgItemTextU}}}/{{{SetDlgItemTextU}}}) 
    117   * {{{GetTextExtentPoint}}} ({{{GetTextExtentPointU}}}) 
    118   * {{{CreateFile}}} ({{{CreateFileU}}}) 
    119   * {{{GetCurrentDirectory}}}/{{{GetFullPathName}}}/{{{GetFileAttributes}}} ({{{GetCurrentDirectoryU}}}/{{{GetFullPathNameU}}}/{{{GetFileAttributesU}}}) 
    120   * {{{SHCreateDirectoryEx}}} ({{{SHCreateDirectoryExU}}}) 
    121   * {{{ShellExecuteEx}}}/{{{CreateProcess}}} ({{{ShellExecuteExU}}}/{{{CreateProcessU}}}) 
    122   * {{{GetOpenFileName}}}/{{{GetSaveFileName}}} ({{{GetOpenSaveFileNameU}}}) 
    123   * {{{UpdateDriverForPlugAndPlayDevices}}}/{{{SetupCopyOEMInf}}} ({{{UpdateDriverForPlugAndPlayDevicesU}}}/{{{SetupCopyOEMInfU}}}) 
    124  
    125   ||=File(s): =||[http://git.libusb.org/?p=libwdi.git;a=blob;f=libwdi/msapi_utf8.h /libwdi/msapi_utf8.h] || 
    126 == Installing a certificate into the Trusted Publisher repository == 
    127    If you want your signed drivers to be installed without security prompts, but can't go through WHQL, you will need to install your signed driver certificate in the Trusted Publisher repository. The following code does just that, through the use of the Crypt32.dll, which is available on Windows 2000 and later.[[BR]] 
    128    The code will also detect whether the certificate is about to be effectively written to the store, so as to let end-users with the possibility to refuse the certificate installation if they so choose.[[BR]] 
    129    The code must be executed from a process running in elevated mode. 
    130  
    131   ||=File(s): =||[http://git.libusb.org/?p=libwdi.git;a=blob;f=libwdi/libwdi.c /libwdi/libwdi.c] -> wdi_install_trusted_certificate() ||