Debugging Credential Providers

Q:  How do I debug a Credential Provider?
A:  Follow these instructions.  As of Visual Studio 2019 and Windows 10, it is necessary to disable all debuggers except the NET v4.6 and Native.  This is due to changes in both Visual Studio 2019 and Windows 10.  The WIndows 10 LogonUI now uses elements of the NET framework, as can be discerned from a module list.  In addition, Visual Studio now includes many separate .NET framework debuggers instead of just one.  The default Automatic debugger selection will pick the wrong NET framework debugger, resulting in only one breakpoint ever being hit.  After that, the code will run correctly, it just can't be debugged.

Before doing this, it's a good idea to make sure remote registry access is enabled and know how to disable the CP via registry edits as well in case you make a mistake so you are not locked out.

Setup Instructions
0.  Configure your build to define DEBUG, disable optimizations, and enable full debugging.  If you do not do all of these, breakpoints may work but single step will fail.
1.  Setup a Windows Environment with Visual Studio, the Credential Provider to debug, and verify it works.  A single machine environment is sufficient.
2.  Stop any other processes or services that use files that are a part of the Credential Provider fileset.  For example, a service or per-user process that runs in the tray may use some of the same support assemblies.
3.  Download the Windows SysInternals Suite, currently available here, and install it.  Only the psexec command is needed, but it is easier to get the whole thing.
4.  At the start menu, enter notepad, then right-click the Notepad application and select Run as Administrator.
5.  Paste the following text into notePad.  If your Visual Studio is a different version than 2019 or if you selected a non-default directory, you must modify this accordingly.
cd \Program Files (x86)\Microsoft Visual Studio\2019\Professional\Common7\Tools
call vsdevcmd.bat
devenv
6.  Select File|Save As, then enter c:\cpcd.cmd
7.  Close NotePad.
8.  Start an elevated command prompt.
9.  Change to the directory where psexec is installed
10.  Enter psexec -dsxi cmd.exe
11.  Press <Ctrl-Alt-del>
12.  At the Lock screen menu, hit <Alt-Tab>.  You will now be in the command prompt started in step 12.
13.  Enter cd\
14.  Enter cpcd
15.  Wait for Visual Studio to initialize.  Click Sign-In if requested and sign in if needed.  This process will take 1-2 minutes as Visual Studio is performing first-time-run setup under the SYSTEM profile.
16.  Close the Toolbar and Server Explorer windows.
17.  Minimize Visual Studio.
18.  Minimize the command prompt.
19.  At the lock screen menu, click Cancel.

Debug Instructions
1. If you need to debug before the GetSerialization call, you must edit the code to add a MessageBox to pause processing as the debugger must attached after the module is loaded.  For example, add a System.Windows.MessageBox call to the top of SetUsageScenario.
2.  Build the Credential Provider, making sure to enable symbols.  As of 2021 February 2, do NOT use the Debug build.  Instead, edit the Release build to include full debug symbols and build it.
3.  Copy all files from the Credential Provider module's bin\<configuration> directory to the install directory, such as c:\Program Files\My Credential Provider.  If the file source is a network drive, such as a VMWare share, you must copy to an intermediate directory on the local drive, then to the install directory.
4.  Press <Ctrl-Alt-Del>
5.  At the lock screen, press <Alt-Tab> until Visual Studio is displayed.
6.  Click Attach.
7.  In the middle of the window across from Attach To, click Select.
8.  At the Select Code Type window, click Debug these code types, then check Managed (v4.6, v4.5, v4.0) and Native ONLY, then click OK.  If you miss this step, the debugger may fail to single step or otherwise proceed from one breakpoint to the next.  Instead, it will behave as if you hit F5 Run.
9.  In the Available processes list, select LogonUI.exe and click Attach.  The first time this is done it may take several minutes depending on the symbol load settings.
10.  Select Debug|Windows|Modules to display the module list window.
12. Press <Alt-Tab> until you return to the lock screen menu.
13. Click Lock.
13. Press <Ctrl-Alt-Del>.  This is the point where the credential provider is loaded by LogonUI.
14.  The first time this is done after Visual Studio starts, it will will probably display an "Exception Thrown" dialog indicating C++ exception winrt::hresult_error.  If this happens, uncheck Break when this exception type is thrown, close the Exception window, then hit F5 to continue running.  This merely indicates something returned a COM error code, which does not indicate a problem.
15.  Press <Alt-Tab> until Visual Studio is displayed again.
16.  In the Modules window, find the first Credential Provider listing with the same filename as your CP's main assembly, then right-click it and select Load Symbols.  There are two listings, one for each debugger active in Visual Studio, and only one can load symbols.  Often the NET 4.6 debugger needs to be manually told to load symbols the first few times.  A continual need to manually load symbols indicates that code generation is incorrect - check Setup step 0.
17.  Open a code file and set a breakpoint.
18.  Minimize Visual Studio to return to the Logon UI GUI window and proceed with your test.

Notes
1. If debugging works intermittently, make sure that optimizations are disabled in ADDITION to debug information being enabled.
2. If debugging still fails, trying unregistering the CP, then re-registering it.  When multiple versions of a .NET assembly are registered for COM, each is registered under a separate version identifier.  This can result in the wrong binary being chosen in some circumstances.  To fix this, find the CLSID key for the CP and manually delete it, then re-register the CP.
3. Visual Studio may have trouble locating source files if they are opened on a UNC path, such as "\\vmware-host\shared folders\Documents\gitHub\credential-provider\...".  To resolve this, map a drive to the path in the command prompt running on the secure desktop.  For example, net use z: "\\vmware-host\shared folders".
Comments