• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 2465
  • Last Modified:

User permissions for "rundll32 printui.dll,PrintUIEntry /Sr

The following line:
rundll32 printui.dll,PrintUIEntry /Sr /n "OKIPAGE 10i" /a "\\Server1\E\My Documents\Databases\Contact Envelope Primary.ptr"
works fine as an administrator but gives a "cannot complete the operation" error as a user.   What permission needs to be set, where do I find it and can I set it from MSAccess VB to give the users permission to run the above line?
0
thenelson
Asked:
thenelson
  • 9
  • 6
1 Solution
 
Chuck WoodCommented:
Hi,

rundll32.exe is in C:\WINNT\system32 (assuming your Windows directory is WINNT) and Read and Execute permissions for Everyone (at least in my system, which has default permissions).

printui.dll is in C:\WINNT\system32 and has Read and Execute permissions for Everyone (same conditions).

It looks as though you have set the printer user interface options to:
  /Sr Restore printer settings from a file
  /n printer name: "OKIPAGE 10i"
  /a binary file name: "\\Server1\E\My Documents\Databases\Contact Envelope Primary.ptr"

I noticed that you did not include option flags that printui.dll seems to expect
   Store or restore printer settings option flags that must be placed at the end of command:
      2      PRINTER_INFO_2
      7      PRINTER_INFO_7
      c      Color Profile
      d      PrinterData
      s      Security descriptor
      g      Global DevMode
      m      Minimal settings
      u      User DevMode
      r      Resolve name conflicts
      f      Force name
      p      Resolve port

For examples:
Restore from a file printer global devmode and printer data:
rundll32 printui.dll,PrintUIEntry /Sr /n "printer" /a "file.dat" g d

Restore from a file minimum settings and resolve port name:
rundll32 printui.dll,PrintUIEntry /Sr /n "printer" /a "file.dat" m p

I recommend you use a computer with a user signed on,
  copy your rundll32 line,
  open a command prompt (Start => Run => type cmd => click Enter),
  set the command prompt properties to allow pasting (click the box in the upper right corner, select Properties at the bottom, click the options tab at the top, and check both of the edit option check boxes, click OK),
  paste the rundll32 line into the command prompt (click the box in the upper right corner, select Edit, then select Paste)
 
This will tell you if the problem is with the rundll32 command or with Access. If the problem is permissions, they can only be resolved by an administrator. If you find this is the case, let me know and I can suggest some approaches to resolve the permissions problem.

Chuck
0
 
thenelsonAuthor Commented:
Chuck,

I have run the nundll32 line from a command prompt with each of the different available option flags; all with the same error message.  You can look at http://www.experts-exchange.com/Operating_Systems/WinXP/Q_21354990.html (which I will request be deleted) for other things I have tried.

Thanks

Nelson
0
 
thenelsonAuthor Commented:
I had mistakenly created multiples of this question in different areas.  I am making the other questions pointers to this question.  Here is the thread from one of the other questions:

 Comment from chouproute
Date: 04/14/2005 06:16AM MST
      Comment       Accept

I think you had better to ask it into Programming tab.
But MS Access VB are not like VB. Something there is some difference. So maybe just check if there is other way to execute your line.

Did you tries this on many OS? Maybe just a sharing problem from Server1.

Good Luck

Marco

Comment from salvagbf
Date: 04/14/2005 06:21AM MST
      Comment       Accept

To install printers, a user needs to be at minimum, a member of the Power Users group.

I doubt you can set it from MSAccess, at least while the user is logged in as a normal User.  You'd have to log in as an administrator, or Right-Click, Run As, on the Computer Management console and run it as a local admin to add them to the Power Users group.  If you're on a domain, remember it's Power User rights on the local computer that they need, not on the domain.

-Bernie

Comment from thenelson
Date: 04/14/2005 07:32AM MST
      Your Comment       

It is not a sharing problem with server1.  rundll32 printui.dll,PrintUIEntry /Ss /n "OKIPAGE 10i" /a "\\Server1\E\My Documents\Databases\Contact Envelope Primary.ptr" which writes the printer settings to the folder works fine.  I can copy the file as a user.  

I am not installing a printer rundll32 printui.dll,PrintUIEntry /Sr /n "OKIPAGE 10i" /a "\\Server1\E\My Documents\Databases\Contact Envelope Primary.ptr" copies printer settings from the named file.

rundll32 printui.dll,PrintUIEntry /? will pop up a printer user interface listing all the available commands.
0
Ultimate Tool Kit for Technology Solution Provider

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy now.

 
Chuck WoodCommented:
Hi thenelson,

Hmmm...

Short of making all your users at least Power Users, I think you will have to consider another approach.

There is a good discussion of changing printer characteristics for a form or report in Access 2000 Developer's Handbook, Volume 1: Desktop Edition (Litwin, Getz, Gilbert--Sybex) on page 808.

If you don't have the book, I can post some sample code and the class they use to set printer charactistics. Just let me know if you are interested.

Chuck
0
 
thenelsonAuthor Commented:
Chuck,

I don't have the Access 2000 Developer's Handbook.  If it is refering to using PrtDevMode, PrtDevNames, and PrtMip, I have already tried that.  Those properties (and the new utilities in 2003 version) do not work for all printer drivers.  For example, they did not work for setting duplex/simplex in our Xerox Phaser 860 or Sharp 155N or setting margin settings in our Oki 10N.

But your guess is right on.  I am trying to create a work around for Access's poor handling of printer settings.  What I came up with works great for power users and administrators but I need it to work for users.   Users can change printer settings so I am not sure why users don't have permission to use the /Sr switch.

Nelson
0
 
Chuck WoodCommented:
Hi Nelson,

Have you tried adding the printer with a new name ("OKIPAGE 10i-Access") to the users' printers, with the properties set the way you want and then printing to that new name?

Chuck
0
 
thenelsonAuthor Commented:
Chuck,

An interesting suggestion but unfortunately I know it won;t work.  The Oki and Xerox are network printers so every time I load an upgrade to the front end, there settings will reset to defalt on all the satelite computers.  That was my original problem which I solved by openning the printer settings popup with RunCommand acCmdPageSetup and setting the printer with a sendkeys string -- very scary, I know.  Now that some of my computers are running Win and Access XP and some are running 2000, the sendkeys method gets very complicated.  Sometime this year, I plan to market the database and then the sendkeys method would be out of the question.
0
 
Chuck WoodCommented:
Hi Nelson,

I am going to post some (Excel) VBA code here in five posts. It uses some Windows API functions, using SendInput in user32.dll to send keystrokes to the active window. I had to use it to overcome the inability to send SendKeys to an Excel User Form. Based on what you have been doing so far, I think you can adapt it to your problem. I think it is much better than SendKeys.

POST-1

Option Explicit

'=== uses the SendInput api declarations described at:
'=== http://mech.math.msu.su/~vfnik/WinApi/s/sendinput.html
Type INPUT_TYPE
  dwType As Long
  xi(0 To 23) As Byte
End Type
Type KEYBDINPUT
  wVk As Integer
  wScan As Integer
  dwFlags As Long
  time As Long
  dwExtraInfo As Long
End Type
Declare Function SendInput Lib "user32.dll" (ByVal nInputs As Long, pInputs As INPUT_TYPE, ByVal cbSize As Long) As Long
Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Declare Function GetLastError Lib "kernel32.dll" () As Long
Const INPUT_KEYBOARD = 1
Const KEYEVENTF_KEYUP = &H2 ' key up
Const VK_SHIFT = &H10       ' shift key
Const VK_CONTROL = &H11     ' control key
Const VK_MENU = &H12        ' alt key

Public strUserName As String, strPassword As String
0
 
Chuck WoodCommented:
POST-2

Public Sub RunTest()
'=== uses the SendInput api function described at:
'=== http://mech.math.msu.su/~vfnik/WinApi/s/sendinput.html
    ' get the username and password
    Dim strFilePath As String
    strFilePath = Worksheets("Test").Range("E3")
    ' set the path to the test document
    Dim strPath As String
    strPath = strFilePath
    ' open the file
    Workbooks.Open strPath
    ' load the keyboard information
    Dim inputevents(0 To 3) As INPUT_TYPE ' holds information about each event
    Dim keyevent As KEYBDINPUT  ' temporarily hold keyboard input info
    Dim lngRetVal As Long
    ' load the user name
    Dim intCharacter As Integer, intLookup As Integer, strCharacter As String
    ' for each character in the user name,
    For intCharacter = 1 To Len(strUserName)
        ' get the character
        strCharacter = Mid$(strUserName, intCharacter, 1)
        ' get the virtual key for that character
        intLookup = LookupVk(strCharacter)
        ' if the character is upper case,
        If Asc(strCharacter) > 64 And Asc(strCharacter) < 91 Then
            ' write that virtual key to the buffer with a shift key
            WriteToBufferUCase keyevent, inputevents, intLookup
        Else
            ' write that virtual key to the buffer
            WriteToBuffer keyevent, inputevents, intLookup
        End If
         ' send the buffer into the input stream.
        lngRetVal = SendInput(4, inputevents(0), Len(inputevents(0)))
    Next intCharacter
    ' write a tab to the buffer
    intLookup = LookupVk("TAB")
    WriteToBuffer keyevent, inputevents, intLookup
     ' send the buffer into the input stream.
    lngRetVal = SendInput(4, inputevents(0), Len(inputevents(0)))
    ' for each character in the password,
    For intCharacter = 1 To Len(strPassword)
        ' get the character
        strCharacter = Mid$(strPassword, intCharacter, 1)
        ' get the virtual key for that character
        intLookup = LookupVk(strCharacter)
        ' if the character is upper case,
        If Asc(strCharacter) > 64 And Asc(strCharacter) < 91 Then
            ' write that virtual key to the buffer with a shift key
            WriteToBufferUCase keyevent, inputevents, intLookup
        Else
            ' write that virtual key to the buffer
            WriteToBuffer keyevent, inputevents, intLookup
        End If
         ' send the buffer into the input stream.
        lngRetVal = SendInput(4, inputevents(0), Len(inputevents(0)))
    Next intCharacter
    ' write a tab to the buffer
    intLookup = LookupVk("TAB")
    WriteToBuffer keyevent, inputevents, intLookup
    ' write an enter  to the buffer
    intLookup = LookupVk("RETURN")
    WriteToBuffer keyevent, inputevents, intLookup
     ' send the buffer into the input stream.
    Dim lngErrorCode As Long
    lngRetVal = SendInput(4, inputevents(0), Len(inputevents(0)))
    ' if there was an error,
    If lngRetVal = 0 Then
        '=== uses GetLastError described at:
        '=== http://mech.math.msu.su/~vfnik/WinApi/g/getlasterror.html
        lngErrorCode = GetLastError()
        MsgBox "An error with the number " & lngErrorCode & " occurred", vbExclamation
    End If
    ' run the auto open macros
    ActiveWorkbook.RunAutoMacros xlAutoOpen
    ' let other processes run
    Dim intEvents As Integer
    intEvents = DoEvents()
    ' purge the user name and password from memory
    strUserName = ""
    strPassword = ""
End Sub
0
 
Chuck WoodCommented:
POST-3

Private Sub WriteToBuffer(ByRef keyevent As KEYBDINPUT, ByRef inputevents() As INPUT_TYPE, ByVal VK As Integer)
'=== uses part of the SendInput api function described at:
'=== http://mech.math.msu.su/~vfnik/WinApi/s/sendinput.html
    ' Load the information needed to synthesize pressing the virtual key.
    keyevent.wVk = VK  ' the virtual key
    keyevent.wScan = 0  ' not needed
    keyevent.dwFlags = 0  ' press the key down
    keyevent.time = 0  ' use the default
    keyevent.dwExtraInfo = 0  ' not needed
    ' Copy the structure into the input array's buffer.
    inputevents(0).dwType = INPUT_KEYBOARD  ' keyboard input
    CopyMemory inputevents(0).xi(0), keyevent, Len(keyevent)
    ' Do the same as above, but for releasing the virtual key.
    keyevent.wVk = VK  ' the virtual key
    keyevent.wScan = 0  ' not needed
    keyevent.dwFlags = KEYEVENTF_KEYUP  ' release the key
    keyevent.time = 0  ' use the default
    keyevent.dwExtraInfo = 0  ' not needed
    inputevents(1).dwType = INPUT_KEYBOARD  ' keyboard input
    CopyMemory inputevents(1).xi(0), keyevent, Len(keyevent)
End Sub
0
 
Chuck WoodCommented:
POST-4

Private Sub WriteToBufferUCase(ByRef keyevent As KEYBDINPUT, ByRef inputevents() As INPUT_TYPE, ByVal VK As Integer)
'=== uses part of the SendInput api function described at:
'=== http://mech.math.msu.su/~vfnik/WinApi/s/sendinput.html
'=== adapted to include the shift key for upper case letters
    ' Load the information needed to synthesize pressing the SHIFT virtual key.
    keyevent.wVk = VK_SHIFT  ' the SHIFT virtual key
    keyevent.wScan = 0  ' not needed
    keyevent.dwFlags = 0  ' press the key down
    keyevent.time = 0  ' use the default
    keyevent.dwExtraInfo = 0  ' not needed
    ' Copy the structure into the input array's buffer.
    inputevents(0).dwType = INPUT_KEYBOARD  ' keyboard input
    CopyMemory inputevents(0).xi(0), keyevent, Len(keyevent)
    ' Load the information needed to synthesize pressing the virtual key.
    keyevent.wVk = VK  ' the virtual key
    keyevent.wScan = 0  ' not needed
    keyevent.dwFlags = 0  ' press the key down
    keyevent.time = 0  ' use the default
    keyevent.dwExtraInfo = 0  ' not needed
    ' Copy the structure into the input array's buffer.
    inputevents(1).dwType = INPUT_KEYBOARD  ' keyboard input
    CopyMemory inputevents(1).xi(0), keyevent, Len(keyevent)
    ' Do the same as above, but for releasing the virtual key.
    keyevent.wVk = VK  ' the virtual key
    keyevent.wScan = 0  ' not needed
    keyevent.dwFlags = KEYEVENTF_KEYUP  ' release the key
    keyevent.time = 0  ' use the default
    keyevent.dwExtraInfo = 0  ' not needed
    inputevents(2).dwType = INPUT_KEYBOARD  ' keyboard input
    CopyMemory inputevents(2).xi(0), keyevent, Len(keyevent)
    ' Do the same as above, but for releasing the SHIFT virtual key.
    keyevent.wVk = VK_SHIFT  ' the SHIFT  virtual key
    keyevent.wScan = 0  ' not needed
    keyevent.dwFlags = KEYEVENTF_KEYUP  ' release the key
    keyevent.time = 0  ' use the default
    keyevent.dwExtraInfo = 0  ' not needed
    inputevents(3).dwType = INPUT_KEYBOARD  ' keyboard input
    CopyMemory inputevents(3).xi(0), keyevent, Len(keyevent)
End Sub
0
 
Chuck WoodCommented:
POST-5

Private Function LookupVk(ByVal InputString As String) As Integer
'=== looks up the virtual key adapting the virtual key code constant definitions at:
'=== http://mech.math.msu.su/~vfnik/WinApi/other/virtualkeycodes.html
    ' convert the input string to upper case
    InputString = UCase(InputString)
    Select Case InputString
        Case "0"
            LookupVk = &H30
        Case "1"
            LookupVk = &H31
        Case "2"
            LookupVk = &H32
        Case "3"
            LookupVk = &H33
        Case "4"
            LookupVk = &H34
        Case "5"
            LookupVk = &H35
        Case "6"
            LookupVk = &H36
        Case "7"
            LookupVk = &H37
        Case "8"
            LookupVk = &H38
        Case "9"
            LookupVk = &H39
        Case "A"
            LookupVk = &H41
        Case "B"
            LookupVk = &H42
        Case "C"
            LookupVk = &H43
        Case "D"
            LookupVk = &H44
        Case "E"
            LookupVk = &H45
        Case "F"
            LookupVk = &H46
        Case "G"
            LookupVk = &H47
        Case "H"
            LookupVk = &H48
        Case "I"
            LookupVk = &H49
        Case "J"
            LookupVk = &H4A
        Case "K"
            LookupVk = &H4B
        Case "L"
            LookupVk = &H4C
        Case "M"
            LookupVk = &H4D
        Case "N"
            LookupVk = &H4E
        Case "O"
            LookupVk = &H4F
        Case "P"
            LookupVk = &H50
        Case "Q"
            LookupVk = &H51
        Case "R"
            LookupVk = &H52
        Case "S"
            LookupVk = &H53
        Case "T"
            LookupVk = &H54
        Case "U"
            LookupVk = &H55
        Case "V"
            LookupVk = &H56
        Case "W"
            LookupVk = &H57
        Case "X"
            LookupVk = &H58
        Case "Y"
            LookupVk = &H59
        Case "Z"
            LookupVk = &H5A
        Case "SHIFT"
            LookupVk = &H10
        Case "TAB"
            LookupVk = &H9
        Case "RETURN"
            LookupVk = &HD
    End Select
End Function


Please let me know if you have any questions.

Chuck
0
 
Chuck WoodCommented:
PS, in the last post (5), you can add two cases for ALT and CTRL

    Case "CTRL"
        LookupVk = &H11
    Case "ALT"
        LookupVk = &H12

Chuck
0
 
thenelsonAuthor Commented:
Chuck,

Thanks for that code but I don't think it would help me with my problem.  Using Sendkeys (or a better substitute) was just a stop gap to get the printer settings working.  I would still have to determin whether I'm on a W2k or WXP machine because the sequence of keystrokes would be different and every printer would have to be hard coded for that printer.  Not at all workable when I publish the database.

I came up with a universally usable routine:
save the original printer settings to a temporary file with rundll32 printui.dll,PrintUIEntry /Sr /n "tempfile"
open the printer setting dialogue with: rundll32 printui.dll,PrintUIEntry /e /n "printer name" and allow the user to make the settings he wishes
save the settings with: rundll32 printui.dll,PrintUIEntry /Ss /n "filename"
return to the original settings with: rundll32 printui.dll,PrintUIEntry /Sr /n "tempfile"

Then to print the form with the special settings:
save the original printer settings to a temporary file with: rundll32 printui.dll,PrintUIEntry /Sr /n "tempfile"
change the settings with: rundll32 printui.dll,PrintUIEntry /Sr /n "filename"
print
return to the original settings with: rundll32 printui.dll,PrintUIEntry /Sr /n "tempfile"

Except users do not have permission to run the /Sr switch.
0
 
thenelsonAuthor Commented:
WELL, I FIGURED OUT HOW TO SOLVE THE PROBLEM!  I just added the switch "u" at the end of the  rundll32 printui.dll,PrintUIEntry /Sr  and /Ss lines.  Not only does it solve the problem but it also makes the saved file smaller and the commands run faster!

Thanks to all for your responses.  I now have a system for Access (or any other VB project) that can store which printer and printer settings to use for a form, report or command.  Change the printer and settings, print then change it back.  If anyone would like the code for it let me know.  I guess I'll give Chuck the points for all his suggestions and useful code.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Cloud Class® Course: Python 3 Fundamentals

This course will teach participants about installing and configuring Python, syntax, importing, statements, types, strings, booleans, files, lists, tuples, comprehensions, functions, and classes.

  • 9
  • 6
Tackle projects and never again get stuck behind a technical roadblock.
Join Now