Mikael Jansson
asked on
winspool.drv calls to remote computer gives access denied. Need help how to authenticate
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 vb.net 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 vb.net 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
Try
iReturn = EnumPrinterDrivers(serverN ame, environment, 3, bufDriver, 0, pcbNeeded, pcReturned)
If pcbNeeded > 0 Then
bufDriver = Marshal.AllocHGlobal(pcbNe eded)
iReturn = EnumPrinterDrivers(serverN ame, environment, 3, bufDriver, pcbNeeded, pcbNeeded, pcReturned)
Dim lpNext As IntPtr
lpNext = bufDriver
For iCount = 1 To pcReturned
Marshal.PtrToStructure(lpN ext, diDriverInfo)
lpNext = New IntPtr(lpNext.ToInt32 + Marshal.SizeOf(diDriverInf o))
debug.print diDriverInfo.pName
Next
Marshal.FreeHGlobal(bufDri ver)
Else
Throw New Win32Exception(Marshal.Get LastWin32E rror())
End If
Catch ex As Win32Exception
MessageBox.Show(ex.Message )
End Try
------------------- End main code ---------------------
-------- Start Driver info declaration class -------------
'DRIVER_INFO_3 structure
<StructLayout(LayoutKind.S equential) > _
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
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 vb.net 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
Try
iReturn = EnumPrinterDrivers(serverN
If pcbNeeded > 0 Then
bufDriver = Marshal.AllocHGlobal(pcbNe
iReturn = EnumPrinterDrivers(serverN
Dim lpNext As IntPtr
lpNext = bufDriver
For iCount = 1 To pcReturned
Marshal.PtrToStructure(lpN
lpNext = New IntPtr(lpNext.ToInt32 + Marshal.SizeOf(diDriverInf
debug.print diDriverInfo.pName
Next
Marshal.FreeHGlobal(bufDri
Else
Throw New Win32Exception(Marshal.Get
End If
Catch ex As Win32Exception
MessageBox.Show(ex.Message
End Try
------------------- End main code ---------------------
-------- Start Driver info declaration class -------------
'DRIVER_INFO_3 structure
<StructLayout(LayoutKind.S
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
ASKER
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
/ Mikael
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
Unknown
Idle
Printing
Warmup
Stopped
Offline
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(q uery)
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(entryCurre nt("Printe rStatus"))
printer.WorkOffline = entryCurrent("WorkOffline" )
listPrinters.Add(printer)
Next entryCurrent
Return CType(listPrinters.ToArray (GetType(W in32_Print er)), Win32_Printer())
End Function 'GetList
End Class
' Add a reference to System.Management.dll to the project.
Imports System.Management
Public Enum PrinterStatus
Other = 1
Unknown
Idle
Printing
Warmup
Stopped
Offline
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("\")
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(q
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(entryCurre
printer.WorkOffline = entryCurrent("WorkOffline"
listPrinters.Add(printer)
Next entryCurrent
Return CType(listPrinters.ToArray
End Function 'GetList
End Class
Notice the DriverName property.
Bob
Bob
ASKER
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
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
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
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
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
Bob