Solved

Problem with AddPortEx API call in VBA (Access) vs. VB

Posted on 2007-04-05
15
840 Views
Last Modified: 2012-06-27
I have a weird problem. I use the following code to change the port to which a particular printer is attached:

    Private Type PORT_INFO_1
      pPortName As String
    End Type
   
    Private Type PRINTER_DEFAULTS
      pDatatype     As String
      pDevMode      As Long
      DesiredAccess As Long
    End Type
   
    Private Const STANDARD_RIGHTS_REQUIRED = &HF0000
    Private Const PRINTER_ACCESS_USE = &H8
    Private Const PRINTER_ACCESS_ADMINISTER = &H4
    Private Const PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED Or _
                                        PRINTER_ACCESS_ADMINISTER Or _
                                        PRINTER_ACCESS_USE)
    Private Const ERROR_INSUFFICIENT_BUFFER = 122
   
    Private Declare Function AddPortEx _
      Lib "winspool.drv" _
      Alias "AddPortExA" ( _
      ByVal pName As String, _
      ByVal pLevel As Long, _
      lpBuffer As Any, _
      ByVal pMonitorName As String) As Long
    Private Declare Function ClosePrinter _
      Lib "winspool.drv" ( _
      ByVal hPrinter As Long) As Long
    Private Declare Function GetPrinter _
      Lib "winspool.drv" _
      Alias "GetPrinterA" ( _
      ByVal hPrinter As Long, _
      ByVal Level As Long, _
      pPrinter As Long, _
      ByVal cbBuf As Long, _
      pcbNeeded As Long) As Long
    Private Declare Function lstrcpy _
      Lib "kernel32" _
      Alias "lstrcpyA" ( _
      ByVal lpString1 As Long, _
      ByVal lpString2 As String) As Long
    Private Declare Function OpenPrinter _
      Lib "winspool.drv" _
      Alias "OpenPrinterA" ( _
      ByVal pPrinterName As String, _
      phPrinter As Long, _
      pDefault As PRINTER_DEFAULTS) As Long
    Private Declare Function SetPrinter _
      Lib "winspool.drv" _
      Alias "SetPrinterA" ( _
      ByVal hPrinter As Long, _
      ByVal Level As Long, _
      pPrinter As Long, _
      ByVal Command As Long) As Long
   
    Public Function SetPrinterPort(pstrPrinterName As String, _
                                   pstrPortName As String) As Boolean
   
      Dim pi1        As PORT_INFO_1
      Dim fRet       As Boolean
      Dim alngBuf()  As Long
      Dim pdDefaults As PRINTER_DEFAULTS
      Dim lngHPrntr  As Long
      Dim lngNeeded  As Long
     
      pi1.pPortName = pstrPortName
      fRet = AddPortEx(vbNullString, 1, pi1, "Local Port")
     
      ReDim alngBuf(1)
     
      pdDefaults.DesiredAccess = PRINTER_ALL_ACCESS
      pdDefaults.pDatatype = "RAW"
      pdDefaults.pDevMode = 0
     
      If OpenPrinter(pstrPrinterName, lngHPrntr, pdDefaults) = 0 Then
        Exit Function
      End If
     
      GetPrinter lngHPrntr, 2, alngBuf(0), 0, lngNeeded
      If Err.LastDllError <> ERROR_INSUFFICIENT_BUFFER Then
        ClosePrinter lngHPrntr
        Exit Function
      End If
     
      ReDim alngBuf((lngNeeded \ 4) + (Len(pstrPortName) \ 2) + 2)
      If GetPrinter(lngHPrntr, 2, alngBuf(0), lngNeeded, lngNeeded) = 0 Then
        ClosePrinter lngHPrntr
        Exit Function
      End If
     
      lstrcpy VarPtr(alngBuf((lngNeeded \ 4) + 1)), pstrPortName
      alngBuf(3) = VarPtr(alngBuf((lngNeeded \ 4) + 1))
     
      If SetPrinter(lngHPrntr, 2, alngBuf(0), 0) = 0 Then
        ClosePrinter lngHPrntr
        Exit Function
      End If
     
      ClosePrinter lngHPrntr
     
      SetPrinterPort = True
   
    End Function

When that exact code is in a standard module in a VB6 project, it works perfectly. When I put that exact code into a standard module in Access 2002 (XP) on the very same machine, it does not work. The AddPortEx() call does not add the port, so the call to SetPrinter() fails. I am completely stumped. I know that there are some differences between VB and VBA, but I didn't think it would affect API calls. Is there something that has to be different about the Declare in VB vs. VBA? Any tips you can give me would be most appreciated!

TIA,

Jeff
0
Comment
Question by:JTennessen
  • 7
  • 6
  • 2
15 Comments
 
LVL 57
ID: 18861275
Jeff,

  The declare for  AddPortEx is incorrect.  Access/VBA does not have an "any" type.

JimD
0
 
LVL 7

Author Comment

by:JTennessen
ID: 18861348
Jim,

Thanks for the input. That's strange, though, because the Access 2002 VBA Help file specifically mentions it in the "Declare Statement" topic:

"Within arglist, you can use an As clause to specify the data type of any of the arguments passed to the procedure. In addition to specifying any of the standard data types, you can specify As Any in arglist to inhibit type checking and allow any data type to be passed to the procedure."

Wouldn't be the first time the documentation was incorrect, of course. What do you suggest as an alternative? I tried PORT_INFO_1 as the type, and though it did not cause new problems, AddPortEx() still didn't work. Do I need to create a pointer to the PORT_INFO_1 variable and pass that?

Thanks!

Jeff
0
 
LVL 57
ID: 18861366
Scratch that last comment.  VBA does suport he any datatype.  But I would try this:

    Private Declare Function AddPortEx _
      Lib "winspool.drv" _
      Alias "AddPortExA" ( _
      ByVal pName As String, _
      ByVal pLevel As Long, _
      ByRef lpBuffer As PORT_INFO_1,
      ByVal pMonitorName As String) As Long

 See if that makes a difference.  Also, is anything supposed to be returned in lbBuffer?

JimD
 
0
 
LVL 7

Author Comment

by:JTennessen
ID: 18861404
Gave it a shot, but no dice. Same thing -- AddPortEx() does not work, but doesn't blow up, either. lpBuffer doesn't return anything, but it has to be passed ByRef because you can't pass a UDT ByVal. Let me know if you can think of anything else I should try.

Thanks man!

Jeff
0
 
LVL 7

Author Comment

by:JTennessen
ID: 18861646
Well, this just gets weirder and weirder. I thought I'd try to compile the code that works in VB 6 into an ActiveX DLL, then call that from Access. But even then, the same thing happens -- AddPortEx() fails. If I reference the DLL in a VB 6 project and call it from there, it works fine. I can only conclude that something in Access' implementation of VBA doesn't like the AddPrinterEx() function. I'm going to leave the question open a few more days to see if there are any other suggestions, but as it looks right now, I'm just not going to be able to make this work. :-(

Jeff
0
 
LVL 57
ID: 18863380

  You are using A2002 then?  I want to try it here.

JimD
0
 
LVL 7

Author Comment

by:JTennessen
ID: 18870894
Yep. Let me know how it goes for you.

Jeff
0
Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

 
LVL 7

Author Comment

by:JTennessen
ID: 18917810
Well, looks like I struck out on this one. Jim, you deserve points for your efforts to help. I appreciate it!

Jeff
0
 
LVL 57
ID: 18917911
Jeff,

  Naw, you gave up to soon<g>.  I still plan on trying this, but have gotten busy.  In the meantime, I'll have some other Experts look at this.  I'll also re-open the question if you don't mind.

JimD
0
 
LVL 38

Expert Comment

by:puppydogbuddy
ID: 18920008
Jeff/Jim,
Don't know if this link will help, but it discusses various API's governing print spooling, some of which may be relevant to what Jeff is trying to accomplish.
                     (start with page 12)
http://aolsearch.aol.com/aol/redir?src=websearch&requestId=f88992b493dcc569&clickedItemRank

A port monitor is an intergral part of the Windows NT printing architecture. Every port monitor supports a standard set of APIs. The functions that need to be supported by the port monitor are as follows:
• InitializePrintMonitor
• DllEntryPoint
• OpenPort
• OpenPortEx
• ClosePort
• StartDocPort
• WritePort
• ReadPort
• EndDocPort
• AddPort or AddPortEx
• DeletePort
• EnumPorts
• ConfigurePort
• SetPortTimeOuts
• GetPrinterDataFromPort
0
 
LVL 57
ID: 18920048

 pdb,

  We've already got the right call, it's just that it won't work in Access VBA and it does in VB.  And I didn't get anywhere when I clicked on your link other then a blank AOL search page.

JimD
0
 
LVL 38

Expert Comment

by:puppydogbuddy
ID: 18920139
Jim,
Here is the link:   www.cswl.com/downloads/w_bitmap.pdf

My thought was that maybe several API's together (API Set) was required.

PDB
0
 
LVL 7

Author Comment

by:JTennessen
ID: 18921046
Heh, OK. I'm certainly willing to keep plugging along at this one if you are. :-) I just didn't want to leave the Q hanging open for too long without resolution. I'm going to take a look at the link that PDB posted. Jim, let me know once you've had a chance to try it in Access 2002. I certainly understand being busy, so no worries there!

If it would be the best thing to do, I can repost this to reopen it. If we can get this resolved in some sort of workable fashion, it's worth almost any amount of points to me.

Thanks guys!

Jeff
0
 
LVL 57

Accepted Solution

by:
Jim Dettman (Microsoft MVP/ EE MVE) earned 500 total points
ID: 19033397
Jeff,

  Sorry it's taken so long to get back to this.  I hope you've found a solution/workaround by now.  However I wanted to let you know that I tried this and the code that you posted works fine here.   Doing the following:

debug.? SetPrinterPort("TEST","TEST PORT")

  Does indeed create a port called "TEST PORT".

 JimD
0
 
LVL 7

Author Comment

by:JTennessen
ID: 19035461
Hey Jim,

Well, I now know part of them problem. Your most recent comment got me to thinking why it would work for you, but not for me. I'd been testing this on Windows Vista, but it hadn't occurred to me that this could be part of the problem because it worked correctly from VB. However, I just tried it from Access 2002 under Windows XP, and guess what? It works just fine! Looks like Vista *is* part of the problem. That doesn't explain why it works in VB on Vista, of course, but it certainly does make the situation somewhat clearer.

Anyway, I did find another approach to solving the problem for which this code was intended that works in both Vista and XP. I thank you very much for your comments and suggestions -- and especially for your persistence! It definitely helps to bring a sense of closure to a mystery that was pretty baffling.

Best regards,

Jeff
0

Featured Post

Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

Join & Write a Comment

Overview: This article:       (a) explains one principle method to cross-reference invoice items in Quickbooks®       (b) explores the reasons one might need to cross-reference invoice items       (c) provides a sample process for creating a M…
You can of course define an array to hold data that is of a particular type like an array of Strings to hold customer names or an array of Doubles to hold customer sales, but what do you do if you want to coordinate that data? This article describes…
Familiarize people with the process of utilizing SQL Server functions from within Microsoft Access. Microsoft Access is a very powerful client/server development tool. One of the SQL Server objects that you can interact with from within Microsoft Ac…
In Microsoft Access, learn the trick to repeating sub-report headings at the top of each page. The problem with sub-reports and headings: Add a dummy group to the sub report using the expression =1: Set the “Repeat Section” property of the dummy…

707 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

13 Experts available now in Live!

Get 1:1 Help Now