I have been fighting a battle with a sharing violation for about 3 days now and I finally solved the problem so I thought I'd document my solution here in case it is in any way helpful to others.
I'm using GPG2.1 on Windows 7 with two other card readers in addition to the Yubikey Neo. After a lot of searching the common consensus was that this is caused by another program blocking scdaemon's access. But which one? Through the process of elimination I found that, at least for me, the process is the service "Certificate Propagation Service".
I cobbled together a script from snippets I found online and set it to run (with highest privileges) on login using Task Scheduler. It still isn't perfect, for example, I'd like for it to mount my flash drive if it's not already mounted, but I haven't figured out how to do that yet. However, it will wait until I get around to doing it manually. My GPG keyring is on a bitlocker encrypted flash drive, so it's important that it wait until the drive is accessible. You may not need this part so you can of course modify it to suit your needs. I'm sure there are different ways to accomplish this and most likely even better ways, and I'd appreciate any improvements, but it works for me as is, at least well enough.
The script basically just stop the problem service, restarts the smart card service, runs gpg --card-status, then starts the certificate propagation service up again.
Sources:
http://www.motobit.com/tips/detpg_vbs-w ... t-service/http://www.tek-tips.com/viewthread.cfm?qid=1619385viewtopic.php?f=26&t=1718* Some others I don't remember
Code:
Set fso = CreateObject("Scripting.FileSystemObject")
Set WshShell = CreateObject("WScript.Shell" )
' Make sure that the USB flash drive containing my GnuPG keyring is mounted.
' It's encrypted so we need to wait, since we don't want to do anything else until it is mounted.
Do
If fso.FolderExists("D:\private\gpg") Then
'safe to continue
Exit Do
Else
WScript.Sleep 10000
End If
Loop
StopService ".", "CertPropSvc", True
RestartServices ".", "SCardSvr"
gpgagent = Quotes("C:\Program Files (x86)\GnuPG\bin\gpg.exe") & _
" --card-status "
WshShell.Run gpgagent, 0
' Give it a chance to start the daemon and read from the smart card
WScript.Sleep 10000
StartService ".", "CertPropSvc", True
Set WshShell = Nothing
Sub RestartServices(Computer, ServiceNames)
Dim ServiceName, Counter, aServiceNames
'Get the array of service names
aServiceNames = split(ServiceNames,",")
'loop services from beginning, stop them
For Each ServiceName In aServiceNames
StopService Computer, ServiceName, True
Next
'loop services from end, start them
For Counter = ubound(aServiceNames) To 0 Step -1
StartService Computer, aServiceNames(Counter), True
Next
End Sub
Function Quotes(ByVal strValue)
Quotes = Chr(34) & strValue & Chr(34)
End Function
Sub StopService(Computer, ServiceName, Wait)
Dim cimv2, oService, Result
'Get the WMI administration object
Set cimv2 = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
Computer & "\root\cimv2")
'Get the service object
Set oService = cimv2.Get("Win32_Service.Name='" & ServiceName & "'")
'Check base properties
If Not oService.Started Then
' the service is Not started
'wscript.echo "The service " & ServiceName & " is Not started"
exit Sub
End If
If Not oService.AcceptStop Then
' the service does Not accept stop command
'wscript.echo "The service " & ServiceName & " does Not accept stop command"
exit Sub
End If
'wscript.echo oService.getobjecttext_
'Stop the service
Result = oService.StopService
If 0 <> Result Then
'wscript.echo "Stop " & ServiceName & " error: " & Result
exit Sub
End If
Do While oService.Started And Wait
'get the current service state
Set oService = cimv2.Get("Win32_Service.Name='" & ServiceName & "'")
'wscript.echo now, "StopService", ServiceName, oService.Started, _
'oService.State, oService.Status
Wscript.Sleep 200
Loop
End Sub
Sub StartService(Computer, ServiceName, Wait)
Dim cimv2, oService, Result
'Get the WMI administration object
Set cimv2 = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
Computer & "\root\cimv2")
'Get the service object
Set oService = cimv2.Get("Win32_Service.Name='" & ServiceName & "'")
'Path = "winmgmts:{impersonationLevel=impersonate}!\\" & Computer & _
' "\root\cimv2:Win32_Service.Name='" & ServiceName & "'"
'Get the WMI administration object of the service
'Set oService = GetObject(Path)
'Check base properties
If oService.Started Then
' the service is Not started
'wscript.echo "The service " & ServiceName & " is started."
exit Sub
End If
'Start the service
Result = oService.StartService
If 0 <> Result Then
'wscript.echo "Start " & ServiceName & " error:" & Result
exit Sub
End If
Do While InStr(1,oService.State,"running",1) = 0 And Wait
'get the current service state
Set oService = cimv2.Get("Win32_Service.Name='" & ServiceName & "'")
'wscript.echo now, "StartService", ServiceName, oService.Started, _
'oService.State, oService.Status
Wscript.Sleep 200
Loop
End Sub
I hope this saves someone a little time and stress.