winspool.drv calls to remote computer gives access denied. Need help how to authenticate

Posted on 2006-03-20
Last Modified: 2008-01-09
I am getting printer drivers enumeration from a computer by calling EnumPrinterDrivers in winspool.drv and it works just great using the code below, but when I try to get it from a computer outside my domain or where my credentials are not right i get "access denied" (that is of course a obvious behaviour). My question is how can I create a connection "authenticate" to the computer prior to calling EnumPrinterDrivers with correct username and password. It has to be done in code.

are there some .net functionallity that solves this for me or are there any dll-functions that I can do to authenticate to the remote system.

I am using 2005

here is the code that works just fine except for connecting to computers with other credentials.

------------------- Start Dll-function declaration  --------------------
  ' Declaration
  Private Overloads Declare Function EnumPrinterDrivers Lib "winspool.drv" Alias "EnumPrinterDriversA" ( _
    ByVal pName As String, _
    ByVal pEnvironment As String, _
    ByVal Level As Int32, _
    ByVal pDriverInfo As IntPtr, _
    ByVal cpBuf As Int32, _
    ByRef pcbNeeded As Int32, _
    ByRef pcReturned As Int32 _
  ) As Int32

------------------- End Dll-function declaration  --------------------

------------------- Start main code --------------------

    Dim iReturn As Int32
    Dim pcbNeeded As Int32
    Dim pcReturned As Int32
    Dim bufDriver As IntPtr
    Dim iCount As Int32
    Dim diDriverInfo As DRIVER_INFO_3 = New DRIVER_INFO_3
    Dim serverName As String = ""      ' empty for local computer
    Dim environment As String = ""     ' empty for all

      iReturn = EnumPrinterDrivers(serverName, environment, 3, bufDriver, 0, pcbNeeded, pcReturned)
      If pcbNeeded > 0 Then
        bufDriver = Marshal.AllocHGlobal(pcbNeeded)
        iReturn = EnumPrinterDrivers(serverName, environment, 3, bufDriver, pcbNeeded, pcbNeeded, pcReturned)

        Dim lpNext As IntPtr
        lpNext = bufDriver
        For iCount = 1 To pcReturned
          Marshal.PtrToStructure(lpNext, diDriverInfo)
          lpNext = New IntPtr(lpNext.ToInt32 + Marshal.SizeOf(diDriverInfo))
              debug.print diDriverInfo.pName
        Throw New Win32Exception(Marshal.GetLastWin32Error())

      End If
    Catch ex As Win32Exception
    End Try

------------------- End main code ---------------------

-------- Start Driver info declaration class -------------

'DRIVER_INFO_3 structure
<StructLayout(LayoutKind.Sequential)> _
    Public Class DRIVER_INFO_3
  Public cVersion As Int32
  Public pName As String
  Public pEnvironment As String
  Public pDriverPath As String
  Public pDataFile As String
  Public pConfigFile As String
  Public pHelpFile As String
  Public pDependentFiles As String
  Public pMonitorName As String
  Public pDefaultDataType As String
End Class

-------- End Driver info declaration class -------------

/ Mikael
Question by:activephoto
    LVL 96

    Expert Comment

    by:Bob Learned
    What information are you using with EnumPrinterDrivers?  You can get a lot of information easily with WMI, using the Win32_Printer class.

    LVL 6

    Author Comment

    It is actually only a little part of the system I am building. I am using a lot of WMI already but I need to delete single jobs from a print queue, delete drivers (incl. files) from a computer (even remote). In WMI I know that I can do remote connect quite easy but it seams that WMI has some limitations when for example need to remove a single job from a queue etc.

    / Mikael
    LVL 96

    Expert Comment

    by:Bob Learned
    This is what I was talking about with the Win32_Printer class:

    ' Add a reference to System.Management.dll to the project.

    Imports System.Management

    Public Enum PrinterStatus
      Other = 1
    End Enum 'PrinterStatus

    Public Class Win32_Printer

      Public DriverName As String
      Public IsNetwork As Boolean
      Public IsShared As Boolean
      Public PortName As String
      Public PrinterLocation As String
      Public PrinterName As String
      Public ServerName As String
      Public ShareName As String
      Public Status As PrinterStatus
      Public WorkOffline As Boolean

      Public Overloads Shared Function GetList() As Win32_Printer()
        Return GetList(Nothing)
      End Function  'GetList

      Public Overloads Shared Function GetList(ByVal machineName As String, ByVal userName As String, ByVal userPassword As String) As Win32_Printer()

        Dim options As New ConnectionOptions
        options.Username = userName
        options.Password = userPassword

        Dim path As New ManagementPath
        path.Server = "\\" & machineName.TrimStart("\") & "\root\cimv2"

        Dim scope As New ManagementScope(path)
        scope.Options = options

        ' Remote machine
        Return GetList(scope)

      End Function   'GetList(machine, user, password)

      Public Overloads Shared Function GetList(ByVal scope As ManagementScope) As Win32_Printer()

        Dim query As String = "Select * From Win32_Printer"

        Dim searcher As New ManagementObjectSearcher(query)

        If Not scope Is Nothing Then
          searcher.Scope = scope
        End If

        Dim listPrinters As New ArrayList

        For Each entryCurrent As ManagementObject In searcher.Get()

          Dim printer As New Win32_Printer

          printer.DriverName = entryCurrent("DriverName")
          printer.IsNetwork = entryCurrent("Network")
          printer.IsShared = entryCurrent("Shared")
          printer.PortName = entryCurrent("PortName")
          printer.PrinterLocation = entryCurrent("Location")
          printer.PrinterName = entryCurrent("Name")
          printer.ServerName = entryCurrent("ServerName")
          printer.ShareName = entryCurrent("ShareName")
          printer.Status = Convert.ToInt32(entryCurrent("PrinterStatus"))
          printer.WorkOffline = entryCurrent("WorkOffline")


        Next entryCurrent

        Return CType(listPrinters.ToArray(GetType(Win32_Printer)), Win32_Printer())

      End Function  'GetList

    End Class
    LVL 96

    Expert Comment

    by:Bob Learned
    Notice the DriverName property.

    LVL 6

    Author Comment

    I am using similar code already for enumeration of printers but as far as I know WMI can not handle delete of printer drivers including all depending files, thats the main reason why I am using winspool.drv functions. But if you know a simpler way with WMI to do that I all ears. This also for cancel a specific job in a queue, all I could find in WMI is to "CancelAllJobs" and thats not what I am looking for.

    I also noticed a performance difference between WMI and winspool.drv calls when enumerating e.g. printers or drivers, winspool.drv calls was faster

    / Mikael
    LVL 96

    Accepted Solution

    LVL 6

    Author Comment

    Hi TheLearnedOne,
    I might have been digging to deep to test things so I forgot to answer back here, sorry for that. Your last answer is probably solving my issue but I still have some things that is still not working but of course you earned your points so I will accept the answer.

    Thanks for your help and sorry that I forgot to get back to finish the question

    / Mikael

    Featured Post

    How to improve team productivity

    Quip adds documents, spreadsheets, and tasklists to your Slack experience
    - Elevate ideas to Quip docs
    - Share Quip docs in Slack
    - Get notified of changes to your docs
    - Available on iOS/Android/Desktop/Web
    - Online/Offline

    Join & Write a Comment

    Introduction As chip makers focus on adding processor cores over increasing clock speed, developers need to utilize the features of modern CPUs.  One of the ways we can do this is by implementing parallel algorithms in our software.   One recent…
    Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
    Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…
    Polish reports in Access so they look terrific. Take yourself to another level. Equations, Back Color, Alternate Back Color. Write easy VBA Code. Tighten space to use less pages. Launch report from a menu, considering criteria only when it is filled…

    733 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    22 Experts available now in Live!

    Get 1:1 Help Now