UWP application use "CustomDevice.FromIdAsync" access KMDF driver is denied - c#

I found a similar question, but it probably didn't help me much.
I'm learning to access drive devices via UWP, in the first two days, the program was working fine, but today, UWP error close when open device, the error message is "Access is denied. Exception from HRESULT: 0x80070005"
I don't know if something was modified during the update process that caused this problem. I only have a snapshot of the virtual machine that can open the drive device. On this snapshot, when I update the UWP application, I can also open the drive device, but after update the driver, the UWP application can no longer open the driver device.
Does this mean the problem is with the driver?
After that, I created a new KMDF project and a UWP project, only printed some information, and the same error occurred after installing to the virtual machine.
It is worth noting that when I saw the UWP access to the drive device in DbgView, the EvtDeviceFileCreate event callback was triggered, but the EvtDeviceClose event callback was triggered immediately, I think, there should be no problem with the device interface.
Also, in the beginning, I used the device manager to "Add legacy hardware" to load the driver, then I tried to install the driver using devcon, both can install the driver, but it seems to be slightly different, I am not sure if this also It will have an impact, although both installation methods currently do not solve the problem I am encountering.
Below are some settings for UWP app and drivers.
Register device interface and add custom capability:
In this part, I refer to Microsoft's official sample kmdf_fx2.
WDFSTRING symbolicLinkString = NULL;
UNICODE_STRING symbolicLinkName = SymbolicName;
DEVPROP_BOOLEAN isRestricted;
status = WdfDeviceCreateDeviceInterface(
hDevice,
(LPGUID)&GUID_INTERFACE_HSADRVSAMPLE1,
NULL); // Reference String
if (!NT_SUCCESS(status)) {
KdPrint(("WdfDeviceCreateDeviceInterface Fail\n"));
goto Error;
}
if (g_pIoSetDeviceInterfacePropertyData != NULL) {
status = WdfStringCreate(NULL,
WDF_NO_OBJECT_ATTRIBUTES,
&symbolicLinkString);
if (!NT_SUCCESS(status)) {
KdPrint(("WdfStringCreate Fail\n"));
goto Error;
}
status = WdfDeviceRetrieveDeviceInterfaceString(
hDevice,
(LPGUID)&GUID_INTERFACE_HSADRVSAMPLE1,
NULL,
symbolicLinkString);
if (!NT_SUCCESS(status)) {
KdPrint(("WdfDeviceRetrieveDeviceInterfaceString Fail\n"));
goto Error;
}
WdfStringGetUnicodeString(symbolicLinkString, &symbolicLinkName);
isRestricted = DEVPROP_TRUE;
status = g_pIoSetDeviceInterfacePropertyData(
&symbolicLinkName,
&DEVPKEY_DeviceInterface_Restricted,
0,
0,
DEVPROP_TYPE_BOOLEAN,
sizeof(isRestricted),
&isRestricted);
if (!NT_SUCCESS(status)) {
KdPrint(("g_pIoSetDeviceInterfacePropertyData Fail\n"));
goto Error;
}
#if defined(NTDDI_WIN10_RS2) && (NTDDI_VERSION >= NTDDI_WIN10_RS2)
static const wchar_t customCapabilities[] = L"ColinTest.HSADrvSample_2022051717171\0";
status = g_pIoSetDeviceInterfacePropertyData(
&symbolicLinkName,
&DEVPKEY_DeviceInterface_UnrestrictedAppCapabilities,
0,
0,
DEVPROP_TYPE_STRING_LIST,
sizeof(customCapabilities),
(PVOID)&customCapabilities);
if (!NT_SUCCESS(status)) {
KdPrint(("g_pIoSetDeviceInterfacePropertyData Fail\n"));
goto Error;
}
#endif
WdfObjectDelete(symbolicLinkString);
}
Error:
if (symbolicLinkString != NULL) {
WdfObjectDelete(symbolicLinkString);
}
Driver INF:
;
; HSADrvSample1.inf
;
[Version]
Signature="$WINDOWS NT$"
Class=Test ; TODO: edit Class
ClassGuid={160303BD-D84C-4819-B962-9B1BDBB52310} ; TODO: edit ClassGuid
Provider=%ManufacturerName%
CatalogFile=HSADrvSample1.cat
DriverVer = 05/19/2022,9.21.50.151
PnpLockDown=1
[DestinationDirs]
DefaultDestDir = 12
HSADrvSample1_Device_CoInstaller_CopyFiles = 11
; ================= Class section =====================
[ClassInstall32]
Addreg=SampleClassReg
[SampleClassReg]
HKR,,,0,%ClassName%
HKR,,Icon,,-5
[SourceDisksNames]
1 = %DiskName%,,,""
[SourceDisksFiles]
HSADrvSample1.sys = 1,,
WdfCoInstaller01011.dll=1 ; make sure the number matches with SourceDisksNames
;*****************************************
; Install Section
;*****************************************
[Manufacturer]
%ManufacturerName%=Standard,NTamd64
[Standard.NTamd64]
%HSADrvSample1.DeviceDesc%=HSADrvSample1_Device, Root\HSADrvSample1 ; TODO: edit hw-id
[HSADrvSample1_Device.NT]
CopyFiles=Drivers_Dir
[Drivers_Dir]
HSADrvSample1.sys
;-------------- Service installation
[HSADrvSample1_Device.NT.Services]
AddService = HSADrvSample1,%SPSVCINST_ASSOCSERVICE%, HSADrvSample1_Service_Inst
; -------------- HSADrvSample1 driver install sections
[HSADrvSample1_Service_Inst]
DisplayName = %HSADrvSample1.SVCDESC%
ServiceType = 1 ; SERVICE_KERNEL_DRIVER
StartType = 3 ; SERVICE_DEMAND_START
ErrorControl = 1 ; SERVICE_ERROR_NORMAL
ServiceBinary = %12%\HSADrvSample1.sys
;
;--- HSADrvSample1_Device Coinstaller installation ------
;
[HSADrvSample1_Device.NT.CoInstallers]
AddReg=HSADrvSample1_Device_CoInstaller_AddReg
CopyFiles=HSADrvSample1_Device_CoInstaller_CopyFiles
[HSADrvSample1_Device_CoInstaller_AddReg]
HKR,,CoInstallers32,0x00010000, "WdfCoInstaller01011.dll,WdfCoInstaller"
[HSADrvSample1_Device_CoInstaller_CopyFiles]
WdfCoInstaller01011.dll
[HSADrvSample1_Device.NT.Wdf]
KmdfService = HSADrvSample1, HSADrvSample1_wdfsect
[HSADrvSample1_wdfsect]
KmdfLibraryVersion = 1.11
[Strings]
SPSVCINST_ASSOCSERVICE= 0x00000002
ManufacturerName="Colin" ;TODO: Replace with your manufacturer name
ClassName="Test" ; TODO: edit ClassName
DiskName = "HSADrvSample1 Installation Disk"
HSADrvSample1.DeviceDesc = "HSADrvSample1 Device"
HSADrvSample1.SVCDESC = "HSADrvSample1 Service"
SCCD File:
The file is configured as per the official documentationHardware Support App (HSA): Steps for App Developers, the file is already set to content.
<?xml version="1.0" encoding="utf-8"?>
<CustomCapabilityDescriptor xmlns="http://schemas.microsoft.com/appx/2018/sccd" xmlns:s="http://schemas.microsoft.com/appx/2018/sccd">
<CustomCapabilities>
<CustomCapability Name="ColinTest.HSADrvSample_2022051717171"></CustomCapability>
<AuthorizedEntities>
<AuthorizedEntity AppPackageFamilyName="Colin.HSA.APP_4a8dxf1xdwf12" CertificateSignatureHash="2d6e4f1418bc13447bb8c10067d0af418cb8a2f9e14c014e03a1e0ec811735af"></AuthorizedEntity>
</AuthorizedEntities>
<Catalog>FFFF</Catalog>
</CustomCapabilityDescriptor>
Part of Package.appxmanifest:
<Capabilities>
<Capability Name="internetClient" />
<uap4:CustomCapability Name="ColinTest.HSADrvSample_2022051717171"/>
</Capabilities>
Part of UWP Code:
string selector = CustomDevice.GetDeviceSelector(DeviceInterfaceGuid);
DeviceInformationCollection enumDevice = await DeviceInformation.FindAllAsync(selector);
string DeviceID = enumDevice[0].Id;
try
{
CustomDevice Device = await CustomDevice.FromIdAsync(DeviceID, DeviceAccessMode.ReadWrite, DeviceSharingMode.Shared);
if (null != Device)
{
Note.Text = "Open successfully";
}
}
catch (Exception ex)
{
Note.Text = "Failed to open!" + ex.Message;
}
I would like to know at which step am I getting the error? How to solve?
At the suggestion of #Nico Zhu - MSFT, I checked the CustomCapabilityName again.
There are three places in my code related to CustomCapabilityName, but they are all the same.
To test if the problem lies here, I reset the name.
Driver Code
static const wchar_t customCapabilities[] = L"Test.hsaTestCustomCapability_1653011401000\0";
CustomCapability.SCCD
<?xml version="1.0" encoding="utf-8"?>
<CustomCapabilityDescriptor xmlns="http://schemas.microsoft.com/appx/2018/sccd" xmlns:s="http://schemas.microsoft.com/appx/2018/sccd">
<CustomCapabilities>
<CustomCapability Name="Test.hsaTestCustomCapability_1653011401000"></CustomCapability>
</CustomCapabilities>
<AuthorizedEntities AllowAny="true"/>
<Catalog>0000</Catalog>
</CustomCapabilityDescriptor>
Package.appxmanifest
<Capabilities>
<Capability Name="internetClient" />
<uap4:CustomCapability Name="Test.hsaTestCustomCapability_1653011401000"/>
</Capabilities>
After that, I uninstalled the previously installed apps and drivers, restarted and installed the latest version of the program, but I still can't access it.
My SDK and WDK version is 10.0.19041.0, test machine OS version is Windows 10 Pro Build 19041.vb_release.191206-1406

I think I made a low-level mistake, the function g_pIoSetDeviceInterfacePropertyData that sets the device interface properties needs to be set in the DriverEntry.
But I didn't, which caused the CustomCapabilityName I set to not take effect.
UNICODE_STRING funcName;
RtlInitUnicodeString(&funcName, L"IoSetDeviceInterfacePropertyData");
g_pIoSetDeviceInterfacePropertyData = (PFN_IO_SET_DEVICE_INTERFACE_PROPERTY_DATA)(ULONG_PTR)
MmGetSystemRoutineAddress(&funcName);
However, it is still an unsolved mystery why the driver works properly in the most initial version...

Related

Find out if a package was installed successfully

I'm trying to add an auto update functionality to a Xamarin Android app.
When it starts, the app checks whether the current version is allowed and if not retrieves all the packages to update (one or more) from the database.
Then it downloads all the packages and saves them to disk. Once all packages have been downloaded, I prompt android to install them in sequence as such:
foreach (UpdatedApp app in apps)
{
InstallPackage(app);
}
private void InstallPackage(UpdatedApp app)
{
Java.IO.File file = new Java.IO.File(app.Path);
if (Build.VERSION.SdkInt >= BuildVersionCodes.N)
{
Intent intent = new Intent(Intent.ActionInstallPackage);
intent.SetData(FileProvider.GetUriForFile(this, $"{PackageName}.fileprovider", file));
intent.SetFlags(ActivityFlags.GrantReadUriPermission);
StartActivity(intent);
}
else
{
Intent intent = new Intent(Intent.ActionView);
intent.SetDataAndType(Android.Net.Uri.FromFile(file), "application/vnd.android.package-archive");
intent.AddFlags(ActivityFlags.NewTask);
StartActivity(intent);
}
It works great when there is only one package to install, but when there are at least two, I basically prompt android to install the packages simultaneously and only the first package will be installed.
I added a small bit of logic to circumvent this issue:
Get the current version of the Nth package.
Prompt install
Every x seconds for y seconds, get the package version again and compare it to the original
If different it means the package has successfully been installed and repeat the process for the N+1st package
Otherwise cancel any further installation
Here's the updated code:
foreach (UpdatedApp app in apps)
{
string versionName = GetPackageVersion(app);
InstallPackage(app);
bool installed = await HasPackageBeenInstalled(app, versionName);
if (!installed)
break;
}
private async Task<bool> HasPackageBeenInstalled(UpdatedApp app, string oldVersion)
{
int count = 0;
do
{
await Task.Delay(1000);
string newVersion = GetPackageVersion(app);
if (newVersion != oldVersion)
return true;
count++;
}
while (count < 20);
return false;
}
private string GetPackageVersion(UpdatedApp app)
{
try
{
PackageInfo packageInfo = PackageManager.GetPackageInfo(app.PackageName, 0);
return packageInfo.VersionName;
}
catch (PackageManager.NameNotFoundException e)
{
return null;
}
}
It ensures I only prompt to install a package after the previous one has been installed.
I was wondering if there was a better way to do that? I had two things in mind:
Use StartActivityForResult instead of StartActivity. This assumes Android natively returns a result, which is not clear to me.
Use a BroadcastReceiver. This assumes Android natively sends a broadcast message when any app is successfully installed.
Could any of my ideas work? Or anything else?
You can use BroadcastReceiver to detect the PACKAGE_ADDED, PACKAGE_REMOVED message::
In your manifest:
<receiver android:name=".AppStatusReceiver" >
<intent-filter>
<action android:name="android.intent.action.PACKAGE_ADDED" />
<action android:name="android.intent.action.PACKAGE_REMOVED" />
</intent-filter>
</receiver>
And Ccreate a Broadcast Receiver:
[BroadcastReceiver(Enabled = true, Exported = false)]
public class SampleReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
// Do stuff here.
}
}
Please Note that the newly installed package does not receive this broadcast.

How can I get my Windows service to see objects in ROT?

EDIT: Though tangentially related, the tagged "duplicate" is not a true duplicate of this question, and more importantly does not answer this question (because the problem is different). I am working with a Window Service, not a standalone userspace app.
Here is what I'm working with:
I've written a Windows service (running in Windows Server 2019) in C# that interacts with other software via COM. This other software is not software that I have access to the source for, so I cannot make changes to the COM registration flags or anything like that, but it does register itself and has an API.
I'd like to use the running object table (ROT) from my service to grab an instance of the other software via moniker display name, however the ROT is always empty from the perspective of my service, even after the service itself starts an instance of the other software via Process.Start() which returns a valid PID. To be clear, this runs fine from a standalone Windows console or Windows form application, but not as a service.
The service is configured to log in as a user who is in the administrators group on this machine. Why can't it see anything in the ROT, even after starting a process itself?
Here is a sample code snippet. When run in a console app it counts many monikers, when run in my service, counter is always 0, even after it starts a process.
[DllImport("ole32.dll")]
private static extern int CreateBindCtx(uint reserved, out IBindCtx ppbc);
private static void TestRot()
{
IBindCtx context = null;
IRunningObjectTable rot = null;
IEnumMoniker monikers = null;
log.Debug("About to start moniker check");
CreateBindCtx(0, out context);
context.GetRunningObjectTable(out rot);
rot.EnumRunning(out monikers);
var moniker = new IMoniker[1];
log.Debug("Beginning moniker loop");
var counter = 0;
while (monikers.Next(1, moniker, IntPtr.Zero) == 0)
{
counter++;
var curMoniker = moniker.First();
string name = null;
if (curMoniker != null)
{
try
{
curMoniker.GetDisplayName(context, null, out name);
}
catch (UnauthorizedAccessException)
{
log.Debug($"UnauthorizedAccessException when getting display name for curMoniker");
}
}
log.Debug($"curMoniker: {name}");
}
log.Debug("Counted monikers: " + counter);
}
Thanks in advance.

PosExplorer().getDevices returning null in .Net applications

I am developing billing app using .Net. I need to print receipt using EPSON TM-T81. I have installed all required drivers and MS POS v1.12. I can successfully print sample content through CheckHealth Utility. So looks there is no issue in PosPrinter configuration. But still PosExplorer().getDevices returning null value. I tried both in windows and ASP.Net application but still the same issue.
Code:
PosPrinter m_Printer = null;
//<<<step1>>>--Start
//Use a Logical Device Name which has been set on the SetupPOS.
string strLogicalName = "PosPrinter";
try
{
//Create PosExplorer
PosExplorer posExplorer = new PosExplorer();
DeviceInfo deviceInfo = null;
try
{
deviceInfo = posExplorer.GetDevice(DeviceType.PosPrinter,strLogicalName);
m_Printer =(PosPrinter)posExplorer.CreateInstance(deviceInfo);
}
catch(Exception)
{
ChangeButtonStatus();
return;
}
//Open the device
m_Printer.Open();
//Get the exclusive control right for the opened device.
//Then the device is disable from other application.
m_Printer.Claim(1000);
//Enable the device.
m_Printer.DeviceEnabled = true;
}
catch(PosControlException)
{
ChangeButtonStatus();
}
//<<<step1>>>--End
If this is exactly the code you're trying to run, then the problem is that strLogicalName does not contain a valid SO or logical device name. That "PosPrinter" is simply a placehoder in the code sample (unless you explicitly set up such a logical name, of course).
In order to find out SO names/logical device names available in your system use these commands:
"C:\Program Files (x86)\Microsoft Point Of Service\posdm.exe" listdevices /type:PosPrinter
"C:\Program Files (x86)\Microsoft Point Of Service\posdm.exe" listnames /type:PosPrinter

Accessviolationexception attempted to read or write protected memory

I create one Windows Form App on my friends machine. It works fine on his machine. But when I tried to run same App on my own machine then from _dialog.ShowDialog() line an exception thrown like "accessviolationexception attempted to read or write protected memory. this is often an indication that other memory is corrupt...". I check for this error on net and I found following solutions:
1) Tools menu ->Options -> Debugging -> General -> Uncheck this option "Suppress JIT optimization on module load" link : http://social.msdn.microsoft.com/Forums/en-US/8789ea67-fbc5-4a7b-a4eb-d4a8a050d5c1/attempt-to-read-or-write-protected-memory-this-is-often-an-indicating-that-other-memory-is-corrupt. Done on my machine but wasnt work.
2) Attempted to read or write protected memory, Install http://support.microsoft.com/kb/971030 for framework 2.0,..3.5, but I dont find any of download product from mention link.
My machine configuration: VS 2010(SP1), Framework used 4.0, DB used MS-Access.
Block of code:
private void SetAttachmentInfo()
{
Dictionary<string, object> _fileInfo = new Dictionary<string, object>();
OpenFileDialog _dialog = new OpenFileDialog();
var _fileName = (object)(null);
var _fileData = (object)(null);
var _fileDataLength = (object)(null);
_dialog.Multiselect = false;
_dialog.Filter = "Office Files (*.doc;*.xls;*.ppt;*pdf;*txt) |*.doc;*xlsx;*.xls*.ppt;*pdf;*.txt;|Image Files (*.jpeg;*.png;*.jpg;*.gif) |*.jpeg;*.png;*.jpg;*.gif |All File|*.*";
if (_dialog.ShowDialog() != DialogResult.Cancel)
{
_fileInfo = GetAttachmentFileInformation(_dialog.FileName);
_fileInfo.TryGetValue("FileName", out _fileName);
_fileInfo.TryGetValue("FileData", out _fileData);
_fileInfo.TryGetValue("Lenght", out _fileDataLength);
FileName = Convert.ToString(_fileName);
FileData = (_fileData != null && (_fileDataLength as int?) > 0) ? (byte[])_fileData : (byte[])null;
AttachmentLength = _fileDataLength as int?;
}
}
Any useful help?
Turning off the DEP settings may solve your problem. Turn off DEP via an elevated Command Prompt by clicking the Windows (Start) > All Programs > Accessories and right-click Command Prompt, then ‘Run as Administrator’. Type bcdedit.exe /set {current} nx AlwaysOff (note the four spaces) and press Enter. To turn it back on, change AlwaysOff to AlwaysOn. You need to restart the system after the changes have been made.

C# SAPI in a web service

var speechEngine = new SpVoiceClass();
SetVoice(speechEngine, job.Voice);
var fileMode = SpeechStreamFileMode.SSFMCreateForWrite;
var fileStream = new SpFileStream();
try
{
fileStream.Open(filePath, fileMode, false);
speechEngine.AudioOutputStream = fileStream;
speechEngine.Speak(job.Script, SpeechVoiceSpeakFlags.SVSFPurgeBeforeSpeak | SpeechVoiceSpeakFlags.SVSFDefault); //TODO: Change to XML
//Wait for 15 minutes only
speechEngine.WaitUntilDone((uint)new TimeSpan(0, 15, 0).TotalMilliseconds);
}
finally
{
fileStream.Close();
}
This exact code works in a WinForm app, but when I run it inside a webservice I get the following
System.Runtime.InteropServices.COMException was unhandled
Message="Exception from HRESULT: 0x80045003"
Source="Interop.SpeechLib"
ErrorCode=-2147201021
Does anyone have any ideas what might be causing this error? The error code means
SPERR_UNSUPPORTED_FORMAT
For completeness here is the SetVoice method
void SetVoice(SpVoiceClass speechEngine, string voiceName)
{
var voices = speechEngine.GetVoices(null, null);
for (int index = 0; index < voices.Count; index++)
{
var currentToken = (SpObjectToken)voices.Item(index);
if (currentToken.GetDescription(0) == voiceName)
{
speechEngine.SetVoice((ISpObjectToken)currentToken);
return;
}
}
throw new Exception("Voice not found: " + voiceName);
}
I have given full access to USERS on the folder C:\Temp where the file is to be written. Any help would be appreciated!
I don't think the System.Speech works in windows service. It looks like there is a dependency to Shell, which isn't available to services. Try interop with SAPI's C++ interfaces. Some class in System.Runtime.InteropServices may help on that.
Our naming convention requires us to use a non-standard file extension. This works fine in a Winforms app, but failed on our web server. Changing the file extension back to .wav solved this error for us.
Make sure you explicitly set the format on the SPFileStream object. ISpAudio::SetState (which gets called in a lower layer from speechEngine.Speak) will return SPERR_UNSUPPORTED_FORMAT if the format isn't supported.
I just got the webservice to spawn a console app to do the processing. PITA :-)

Categories

Resources