ERROR_INVALID_PRINTER_NAME returned by OpenPrinter() in Windows 8 when executed under "SYSTEM" account - windows-8

My application deletes virtual printer when user uninstalls the application.
Application's installation and Uninstallation can be done using user interaction(wizard) or by setting group policy in Windows server 2003(domain admin sets the policy in server and the domain user in client PC need to update the group policy and restart the Client PC for installation or uninstallation of the application).
The follwing code in the application deletes printer and printer driver when uninstalling the application.
void CPrinterDriver::DeletePrinterIfExists()
{
// Delete old printer driver if existing
ControlSpoolService(TRUE);
HANDLE hPrinter = NULL;
PRINTER_DEFAULTS pDefaults = { NULL, NULL, PRINTER_ALL_ACCESS };
// Ignore error codes
OpenPrinter(m_driverInfo.pName, &hPrinter, &pDefaults);
if (hPrinter)
{
// deleting jobs
SetPrinter(hPrinter, 0, NULL, PRINTER_CONTROL_PURGE);
// Delete printer
DeletePrinter(hPrinter);
// Get printer driver name and delete it
DWORD dwNeeded = 0;
GetPrinter(hPrinter, 2, NULL, 0, &dwNeeded);
if (dwNeeded)
{
PRINTER_INFO_2 *pi2 = (PRINTER_INFO_2 *)GlobalAlloc(GPTR, sizeof(PRINTER_INFO_2)*dwNeeded);
if (pi2)
{
GetPrinter(hPrinter, 2, (LPBYTE)pi2, dwNeeded, &dwNeeded);
DeletePrinterDriver(NULL, NULL, pi2->pDriverName);
GlobalFree(pi2);
}
}
ClosePrinter(hPrinter);
}
}
The above code works well in Windows 7 in both cases(user interactive installation and using group policy) of uninstallation. In Windows 8, it works well using user interactive installation and uninstallation.
But in Windows 8 the above OpenPrinter() is returing ERROR_INVALID_PRINTER_NAME.
We found that the OpenPrinter() is called using the "SYSTEM" account.
Kindly help.

We found that during system startup, group policy is trying to uninstall the printer before the available printers list in the PC is populated (list is populated under the below registry key.If the list is not populated the below key does not exists).
"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Printers"
Hence we added delay of 2 minutes(not less than 2 mins) before calling openPrinter().
After the delay the registry key exists and the OpenPrinter() succeeded.
Thus we are able to uninstall the printer.
Note: Microsoft claims that Windows 8 boot time is reduced to 7 secs for certain supported hardware. But inserting delay of 2 mins degrades the boot performance of the Windows 8 PC.
For more details regarding the improvement in the boot time of Windwos 8 OS please refer the below link.
http://blogs.msdn.com/b/b8/archive/2012/05/22/designing-for-pcs-that-boot-faster-than-ever-before.aspx
Hence delay of 2 mins can be terated as a workaround.
Need to check the behaviour in the Windows 8 OS release after 10/26.

If you suffer from the issue where:
the registry key for the shared (network) printer is missing and
the API gives you the invalid printer name error
Then you can try opening the printer by its full UNC path.
So when opening MYPRINTER does not work, then open it as \\MYSERVER\MYPRINTER .
Of course this still assumes that you can already print to this printer normally from other applications!

Related

UMDF PnP Driver creates no trace logs

Im trying to create trace log messages for this Idd Sample Driver. I am following this document.
I add WPP_INIT_TRACING(pDriverObject, pRegistryPath) to the DriverEntry, and WPP_CLEANUP(pDriverObject)to the EvtCleanupCallback.
_Use_decl_annotations_
void DriverContextCleanup(WDFOBJECT DriverObject)
{
UNREFERENCED_PARAMETER(DriverObject);
DoTraceMessage(MYDRIVER_ALL_INFO, "Tracing Fini Success");
WPP_CLEANUP(WdfDriverWdmGetDriverObject(DriverObject));
}
_Use_decl_annotations_
extern "C" NTSTATUS DriverEntry(
PDRIVER_OBJECT pDriverObject,
PUNICODE_STRING pRegistryPath
)
{
WDF_DRIVER_CONFIG Config;
NTSTATUS Status;
WDF_OBJECT_ATTRIBUTES Attributes;
WDF_OBJECT_ATTRIBUTES_INIT(&Attributes);
Attributes.EvtCleanupCallback = DriverContextCleanup;
WDF_DRIVER_CONFIG_INIT(&Config,
IddSampleDeviceAdd
);
WPP_INIT_TRACING(pDriverObject, pRegistryPath);
DoTraceMessage(MYDRIVER_ALL_INFO, "Tracing Init . . .");
Status = WdfDriverCreate(pDriverObject, pRegistryPath, &Attributes, &Config, WDF_NO_HANDLE);
if (!NT_SUCCESS(Status))
{
DoTraceMessage(MYDRIVER_ALL_INFO, "Tracing Init Failed");
WPP_CLEANUP(pDriverObject);
return Status;
}
DoTraceMessage(MYDRIVER_ALL_INFO, "Tracing Init Success");
return Status;
}
I add some DoTraceMessage() calls with a flag of MYDRIVER_ALL_INFO to the DriverEntry and DeviceEntry.
NTSTATUS IddSampleDeviceD0Entry(WDFDEVICE Device, WDF_POWER_DEVICE_STATE PreviousState)
{
UNREFERENCED_PARAMETER(PreviousState);
// This function is called by WDF to start the device in the fully-on power state.
DoTraceMessage(MYDRIVER_ALL_INFO, "Tracing Device Entry");
auto* pContext = WdfObjectGet_IndirectDeviceContextWrapper(Device);
pContext->pContext->InitAdapter();
return STATUS_SUCCESS;
}
I make sure WPP Tracing is set to YES in the properties of the project.
The project builds, I go into TraceView and open the IddSampleDriver.PDB file, I set the level to verbose, and check all of the flags. I verified that it has the trace stuff it needs. Since if I open the IddSampleApp.PDB file, it fails.
I install the driver after enabling TestSigning and installing with pnputil -a ./x64/Debug/IddSampleDriver/IddSampleDriver.inf, run the sample app, the driver spins up 3 virtual monitors in the Display Settings. I then exit the app, and the monitors disappear. Everything seems to be functional. The problem is there is no traces in TraceView.
I have tried using tracelog, following this. Still nothing.
I have tried using logman, following this. Still nothing.
I am at my wits end. I spent all last week on this, Trying every possible avenue to get my trace messages to appear.
Either I followed every one of these instructions with no success. Either I somehow messed up every single one of them, or I am missing something else that I need to do in order to view these traces.
Additional Info:
Trace.h was left untouched
Targeting x64, Debug. Running on build machine. Win10.
CTL file I used:
b254994f-46e6-4718-80a0-0a3aa50d6ce4 MyDriver1TraceGuid
Basic process I used (tracelog as example):
tracepdb -f .\x64\Debug\IddSampleDriver.pdb
tracelog -start TestTraceIDD -guid .\guid.ctl -f testTrace.etl -flag 0xff
pnputil -a .\x64\Debug\IddSampleDriver\IddSampleDriver.inf #install driver
.\x64\Debug\IddSampleApp.exe #create software device and attach driver to it
<exit app>
tracelog -stop TestTraceIDD
tracefmt.exe .\testTrace.etl -p . -o test.out```
pnputil -d oem20.inf -f #uninstall driver
Solved my problem. I wasnt actually installing my driver, since it was still installed from the first time I installed it, so it was always using that driver instead of my new one with WPP enabled. I was installing and uninstalling the driver with pnputil.
I was doing pnputil -d oem20.inf -f for example to uninstall the driver. This is BAD. I have learned now that force deleting a driver does nothing. The reason I was force deleting was because it wouldnt delete when i still had a device, even though i would exit the sample app.
So what you have to do in order to properly delete the driver is enumerate the devices with pnputil, remove the ones that use your driver, then delete the driver. This allows a proper fresh driver installation.

How to get correct GPU device id for Microsoft.ML.OnnxRuntime.DirectML (.net core 3.1)?

I am using Microsoft.ML.OnnxRuntime.DirectML nuget package for image classification like this:
var options = new SessionOptions();
options.AppendExecutionProvider_DML( 1 ); // deviceId goes here
var session = new InferenceSession( _modelPath, options );
And I have one big problem: in IIS integrated video card has deviceId 0 and discrete has deviceId 1. But when my app is running under Kestrel, integrated has deviceId 1 and discrete has deviceId 0, and this is opposite to what Task Manager shows in "GPU engine" column when scoring is in progress.
And right now my integrated card can not be used with this package as it throws this exception (and this is pointless anyway):
Exception Info: Microsoft.ML.OnnxRuntime.OnnxRuntimeException: [ErrorCode:RuntimeException] D:\5\s\onnxruntime\core\providers\dml\dml_provider_factory.cc(110)\onnxruntime.DLL!00007FF8C074118F: (caller: 00007FF8C07411C7) Exception(941) tid(35b8) 887A0020 An internal issue prevented the driver from carrying out the specified operation. The driver's state is probably suspect, and the application should not continue.
So I need a reliable way to detect deviceId for discrete video card.
Ok, I have found a workaround for now.
I can check witch video card is integrated/discrete using this method
How get GPU information in C#?
and then I can use Vortice.DXGI nuget package to find out which deviceId each video card has - it is basically index
DXGI.CreateDXGIFactory1( out IDXGIFactory1 factory );
factory.EnumAdapters1( 0, out var adapter0 );
factory.EnumAdapters1( 1, out var adapter1 );
factory.EnumAdapters1( 2, out var adapter2 );

Calling shell script from PL/SQL, but shell gets executed as grid user, not oracle

I am trying to execute a shell script from inside the Oracle database using Runtime.getRuntime().exec.
Oracle 11.2.0.4 EE running on Red Hat 5.5
CREATE OR REPLACE procedure pr_executa_host(p_cmd varchar2)
as language java name 'Util.RunThis(java.lang.String)';
/
public class Util extends Object
{
public static int RunThis(java.lang.String args)
{
Runtime rt = Runtime.getRuntime();
int rc = -1;
try
{
Process p = rt.exec(args);
int bufSize = 4096;
BufferedInputStream bis =
new BufferedInputStream(p.getInputStream(), bufSize);
int len;
byte buffer[] = new byte[bufSize];
// Echo back what the program spit out
while ((len = bis.read(buffer, 0, bufSize)) != -1)
System.out.write(buffer, 0, len);
rc = p.waitFor();
}
catch (Exception e)
{
e.printStackTrace();
rc = -1;
}
finally
{
return rc;
}
}
}
/
The permissions granted on java to db user SCOTT:
kind grantee type name action
GRANT SCOTT java.io.FilePermission /webstart/mn500/* readFileDescriptor
GRANT SCOTT java.io.FilePermission /webstart/mn500/* read,write,execute
GRANT SCOTT java.io.FilePermission /webstart/mn500/* writeFileDescriptor
GRANT SCOTT java.io.FilePermission /webstart/mn500/CONCLUIDO/MN457560/executa.sh execute
GRANT SCOTT java.lang.RuntimePermission * writeFileDescriptor
GRANT SCOTT java.lang.RuntimePermission /webstart/mn500/CONCLUIDO/MN457560/executa.sh execute
The shell script executa.sh, which is the one I'm trying to execute:
#!/bin/sh
echo i am `/usr/bin/whoami`
echo environment `/bin/env`
/bin/date>>/webstart/mn500/CONCLUIDO/MN457560/test.txt
The permissions on the directory:
p08[oracle] $ ls -larth /webstart/mn500/CONCLUIDO/MN457560
-rw-r--r-- 1 oracle oinstall 1 Jul 29 12:03 test.txt
-rwxr-xr-x 1 oracle orafiles 430 Jul 29 12:04 executa.sh
drwxr-xr-x 2 oracle orafiles 4.0K Jul 29 12:04 .
The thing is, when I execute the procedure pr_executa_host, it runs the shell script as grid os
user, not oracle! (although it keeps oracle environment variables, like it did a 'su grid -m'
before executing the shell script)
Since grid doesn't have write privileges on neither the directory, nor the file, the script doesn't
do anything, the test file stays unaltered. Take a look:
begin
dbms_java.set_output(1000000);
pr_executa_host('/webstart/mn500/CONCLUIDO/MN457560/executa.sh');
dbms_lock.sleep(2);
end;
/
i am grid
environment HOSTNAME=p08.XXXXXXXXXXXX.com.br SHELL=/bin/bash TERM=xterm HISTSIZE=1000
SSH_CLIENT=10.141.112.28 56029 22 NLS_LANG=AMERICAN_AMERICA.WE8MSWIN1252 QTDIR=/usr/lib64/qt-3.3
QTINC=/usr/lib64/qt-3.3/include SSH_TTY=/dev/pts/0 USER=oracle
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;0
1:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01
;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*
.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.tbz=01;31:*.tbz2=01;31:*.bz=01;31
:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7
z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01
;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;3
5:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*
.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=
01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35
:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.a
ac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=
01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36: ORACLE_SID=sigepshm
ORACLE_BASE=/oracle ORACLE_HOSTNAME=P08 PATH= MAIL=/var/spool/mail/oracle
TNS_ADMIN=/grid/product/11.2.0/grid/network/admin PWD=/oracle/product/11.2.0/db/dbs
KDE_IS_PRELINKED=1 LANG=en_US.UTF-8 ORA_NET2_DESC=27,30 KDEDIRS=/usr ORACLE_TERM=xterm
ORACLE_SPAWNED_PROCESS=1 HISTCONTROL=ignoredups SSH_ASKPASS=/usr/libexec/openssh/gnome-ssh-askpass
HOME=/home/oracle SHLVL=2 GRID_HOME=/oracle/product/11.2.0/grid LOGNAME=oracle CVS_RSH=ssh
QTLIB=/usr/lib64/qt-3.3/lib SSH_CONNECTION=10.141.112.28 56029 10.147.0.8 22
CLASSPATH=/oracle/product/11.2.0/db/JRE:/oracle/product/11.2.0/db/jlib:/oracle/product/11.2.0/db/rdb
ms/jlib LESSOPEN=|/usr/bin/lesspipe.sh %s DISPLAY=localhost:10.0
ORACLE_HOME=/oracle/product/11.2.0/db G_BROKEN_FILENAMES=1 _=/bin/env
Why is the java inside the database calling unix commands as grid user, not oracle?
Thanks a lot for your help,
Stolf
The issue, as pointed out in the comments, is that Runtime.getRuntime().exec runs throught EXTPROC, and thus through the Grid Listener. Since we have OS user isolation between DB and GRID on our new configuration, this raised a permission problem on the FS.
The solution to this is one of the bellow:
Fix FS permission to let grid user write the files and change umask to something like 774 or 664, so both grid and oracle users will be able to modify the files later;
change sudoers file and allow grid to execute the commands needed as oracle without password and change shell script to include sudo;
create a new listener on DB Home on another port and change TNSNAMES.ORA entry to point to the new port. Then extproc will be executed as OS user oracle. You will have to manually edit LISTENER.ORA on $OH and start it with lsnrctl, because listeners registered with srvctl will always be started by grid ;
change main listener to the db home. I don't recommend that (see item above).
[EDIT]
As pointed out by #AlexPoole and #jonearles, there are two other options that weren't fit for my case, but might be for others:
if you run the script locally on sqlplus, setting ORACLE_SID, the FS access will be made by the OS user running sqlplus. So you can run as oracle, or some other user and fix the FS permissions;
if you schedule a job on dbms_job scheduler as SYS, the task will be executed by oracle (this behavior may be version dependent, so further testing is needed).
Regards,
Daniel Stolf
On further investigation it runs the script as the OS user that started the session; but the server user, not the client osuser seen in v$session.
If you connect locally through SQL*Plus, without going through SQL*Net, the shell script runs as your own OS user, not grid or oracle, unless you're logged into the box as one of those. So when I execute the procedure as myself, the script reports i am apoole.
When you run remotely though, the OS user for the session is the listener owner, which by default in a Grid environment is going to be grid. And you see the environment of the grid user when the listener was started.
So if you're going to be executing this manually, remotely through a SQL*Net-connected client then the options in your own answer are valid. You can move the DB listener to run under the oracle account, or create a new listener under that account, and connect via that. Then the script will execute as oracle when invoked from any session connected via that listener. Or make the OS permissions/sudo work for you.
If you will or might execute it from a local session without going through SQL*Net then you'd need to make the OS permissions valid for any user that might invoke it - assuming you won't be running it from SQL*Plus launched from the oracle account. The listener isn't part of the picture, so the grid user isn't a factor.
This is when it's run as an anonymous block; as #jonearles pointed out in a comment on the question, the behaviour for scheduled jobs is different. By default it would execute the script as nobody, which would mean you'd have to relax the OS permissions even more.

RegOpenKeyEx in VBA returns Err 5 (Error_NoAccess) because of UAC high

I am trying to read a registry entry in under Local machine from a xla. If UAC is high the funcion RegOpenKeyEx fails to read registry. Is there any way to get the permission(via code).
rc = RegOpenKeyEx(KeyRoot, KeyName, 0, KEY_ALL_ACCESS, hKey)
KeyRoot is HKEY_LOCAL_MACHINE
KeyName is "SOFTWARE\XYZ"
Note: My code works without any issue - When UAC is low.
OS : Win 7,
Office : Tested in 2007 and 2010 - both had teh same issue.
Thanks chris neilsen,
I used KEY_READ access prievilage as mentioned in this site.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724878%28v=vs.85%29.aspx

Can you prevent SndVol from displaying empty audio session?

I've been playing around with Vista's CoreAudio stuff, in particular IAudionSessionEvents, with the goal of monitoring the default audio session for changes to volume caused by loaded code.
However, it looks like as soon as you install an IAudioSessionEvents listener SndVol lists the program with all associated volume controls. As a good portion of the time no code has been loaded that will actually play anything, this is less than ideal.
Basically, is there some way to monitor the default audio session without causing SndVol to list it?
A solution for Vista is preferred, but something depending on new apis provided in Windows 7 is better than nothing.
Larry Osterman pointed out the ISessionManager2 and IAudioSessionNotification interfaces added in Windows 7. However, I never receive notice of new session. Is anyone aware of gotchas or problems with this API under Windows 7 build 7000?
Code registering IAudioSessionNotifications, omitting lots of error checking code*:
BOOL success = false;
HRESULT hr;
IMMDeviceEnumerator *pEnumerator = NULL;
IMMDevice *pDevice = NULL;
IAudioSessionManager2* pManager = NULL;
IClassFactory* pFactory = NULL;
hr = CoInitialize(NULL);
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator);
hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice);
pDevice->Activate(__uuidof(IAudioSessionManager2), CLSCTX_ALL, NULL, (void**)&pManager);
listener = NULL;
hr = CoGetClassObject(CLSID_CustomFactory, CLSCTX_ALL, NULL, __uuidof(IClassFactory), (void**)&pFactory);
hr = pFactory->CreateInstance(NULL, __uuidof(IAudioSessionNotification), (void**)&listener);
hr = pManager->RegisterSessionNotification(listener);
*While not the purpose of this question, constructive critic of my COM code is welcome.
If you want to monitor the audio session stuff, you should use the IAudioSessionManager interface to retrieve your IAudioSessionControl object. A session only shows up in SndVol when it transitions from the inactive to the active state - that happens when when someone calls IAudioClient::Start() - as long as you don't call IAudioClient::Start you shouldn't get a session slider.
In Windows 7, there are a new set of APIs (IAudioSessionManager2) that allow you to listen for session creation and destruction.
Also for Windows 7, there is the AUDCLNT_SESSIONFLAGS_HIDE flag (the documentation for this hasn't been updated yet but it's in the headers)