How to add a printer port on NT non-interactivly?

Hi everybody,

this is my first question here.

I have a problem on NT 4.0 :

I want to add a printer port without poping up the dialog box of AddPort and without a reboot. Just like the AddPort but without user interactions. The user should not realize that a port is installed.

I found a call AddPortEx in DDK, but not in the Win32 SDK. Nevertheless I tried but the call never returns. To be honest : as expected ...

Now my question : Does anybody know how to use this call (prerequesites) or maybe a better way to install a printer port non-interactivly ?

Any help is appreciated

Regards

Toni
LVL 1
moosachAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

moosachAuthor Commented:
Code Fragment from my unsuccessful trials :

Calling AddPortEx of the localmon.dll doesn’t work. The function doesn’t return after calling.
The same happens with AddPort of the localmon.dll. In this case the AddPort dialog box appears, but after entering the port name and leaving with OK, the function doesn’t return either.

How can this problem be solved?

Code fragment:

MultiByteToWideChar(CP_ACP, 0, "Local Port",-1,MonitorNameW,sizeof(MonitorNameW));
      
lstrcpy(PortName,"c:\\tmp\\testport.prn");

hLib=::LoadLibrary("localmon.dll");

if(!hLib)
{
      ::MessageBox(NULL,"LoadLibrary of localmon.dll failed","TEST",MB_OK);
}


lpfn=(LPFNDLLFUNC1)GetProcAddress(hLib,"InitializePrintMonitor");

MultiByteToWideChar(CP_ACP,
                  0,
                           
"HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Print\\Monitors\\Local Port",
                  -1,
                  RegRootPrMonitorW,
                  sizeof(RegRootPrMonitorW));

lpMonitorEx =lpfn((LPWSTR)RegRootPrMonitorW );

if(lpMonitorEx)
{
      if( (lpMonitorEx->Monitor.pfnAddPortEx)(NULL,1,(LPBYTE)PortName,(LPWSTR)MonitorNameW))      
      {
            ::MessageBox( NULL,"AddPortEx() passed","TEST",MB_OK );
      }
      else
      {
            ::MessageBox( NULL,"AddPortEx() failed","TEST",MB_OK );
      }
}
                        
::FreeLibrary(hLib);


0
NickRepinCommented:
You must pass pointer to PORT_INFO_1 structure as third parameter for AddPortEx.

Here is PORT_INFO_1 declaration:

typedef struct _PORT_INFO_1 { // pi1
    LPTSTR pName;
} PORT_INFO_1;

That is, you must pass pointer-to-pointer to port name.

Instead, you pass pointer to port name. Try to use (LPBYTE) &PortName.


0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
NickRepinCommented:
Also, I'm not sure you can pass non-wide-char PortName to AddPortEx. Try also to convert it wide char.
0
Build an E-Commerce Site with Angular 5

Learn how to build an E-Commerce site with Angular 5, a JavaScript framework used by developers to build web, desktop, and mobile applications.

moosachAuthor Commented:
Hi,

thanks a lot for answering my question !

Unfortunately your advice doesn't solve my problem. I changed
my code following your mail, but still the DDK function AddPortEx doesn't return. The same is true for the AddPort from DDK. This one comes with the popup for entering the port and then it doesn't return either.

The AddPort from SDK works as expected, but I don't want to have this popup. That is my problem ...

Do I miss something ? Is there a different way to solve my problem ?

Any help is appreciated.

Regards

Toni
0
NickRepinCommented:
You choosed a wrong way at all. You should not call to InitializePrintMonitor, because this function must reside in print monitor and must be called by spooler internally.

Instead, you should call to undocumented AddPortEx of winspool.exe.

Here is a test program which adds port "Nick Port".

If you will be satisfied with my answer, please give me grade 'A', because now I should write another program to delete this port from my PC. ;)

#include <windows.h>
#include <iostream.h>

extern "C" __import BOOL WINAPI AddPortExA(LPSTR pName, DWORD level,  LPBYTE buffer, LPSTR monitorName);

void main(void)
{
   BOOL r;

   // Print currently installed ports
   DWORD nNeed,nRet;
   PORT_INFO_1 pi[200];
   r=EnumPorts(NULL,1,LPBYTE(&pi[0]),sizeof(pi),&nNeed,&nRet);
   cout<<"EnumPorts()="<<r<<" nRet="<<nRet<<endl;
   if(!r || nRet<1)
      return;
   for(int i=0;i<nRet;i++)
      cout<<"Port name "<<i<<": "<<(pi[i].pName)<<endl;

   // Enum monitors to retrieve monitor name
   MONITOR_INFO_1 mi[100];
   r=EnumMonitors(NULL,1,LPBYTE(&mi[0]),sizeof(mi),&nNeed,&nRet);
   cout<<"EnumMonitors()="<<r<<" nRet="<<nRet<<endl;
   if(!r || nRet<1)
      return;
   cout<<"Monitor name 0: "<<(mi[0].pName)<<endl;

   // Create new port
   CHAR PortName[200]="Nick Port"; //"c:\\tmp\\testport.prn";
   pi[0].pName=&PortName[0];
   r=AddPortExA(NULL,1,LPBYTE(&pi[0]),mi[0].pName);
   cout<<"AddPortExA "<<(r ? "OK" : "failed")<<endl;

   // List port names again
   r=EnumPorts(NULL,1,LPBYTE(&pi[0]),sizeof(pi),&nNeed,&nRet);
   cout<<"EnumPorts()="<<r<<" nRet="<<nRet<<endl;
   if(!r || nRet<1)
      return;
   for(int i=0;i<nRet;i++)
      cout<<"Port name "<<i<<": "<<(pi[i].pName)<<endl;
}

0
moosachAuthor Commented:
You'll get an "A"++ :-) !

Thanks a lot for your help !! You are really an expert !!!

Regards

Toni
0
freterCommented:
Hi,

I am currently trying to add LPR ports using the technique depicted above (using the undocumented AdPortEx function), but I can't seem to succeed. I checked the lprmon.dll and found that it doesn't export a function AddPortEx. Might this be the cause for my problem?
OBTW: when adding local ports or PDF ports (I've got Acrobat installed), everything's fine...

TIA,
</freter>
0
NickRepinCommented:
AddPortEx is in WINSPOOL.DRV

#include <windows.h>
#include <iostream.h>

typedef BOOL (WINAPI *AddPortExAT)(LPSTR pName,DWORD level,
   LPBYTE buffer,LPSTR monitorName);

AddPortExAT pf;

void main(void)
{
   int i;
   BOOL r;

   HINSTANCE hLib=LoadLibrary("WINSPOOL.DRV");
   pf=(AddPortExAT)GetProcAddress(hLib,"AddPortExA");
   if(!pf) {
      cout<<"Unable to find AddPortExA"<<endl;
      return;
   }


   // Print currently installed ports
   DWORD nNeed,nRet;
   PORT_INFO_1 pi[200];
   r=EnumPorts(NULL,1,PBYTE(pi),sizeof(pi),&nNeed,&nRet);
   cout<<"EnumPorts()="<<r<<" nRet="<<nRet<<endl;
   if(!r || nRet<1) {
      cout<<"No ports found"<<endl;
      return;
   }
   for(i=0;i<nRet;i++)
      cout<<"Port name "<<i<<": "<<(pi[i].pName)<<endl;

   // Enum monitors to retrieve monitor name
   MONITOR_INFO_1 mi[100];
   r=EnumMonitors(NULL,1,PBYTE(mi),sizeof(mi),&nNeed,&nRet);
   cout<<"EnumMonitors()="<<r<<" nRet="<<nRet<<endl;
   if(!r || nRet<1) {
      cout<<"No monitors found"<<endl;
      return;
   }
   cout<<"Monitor #0: "<<(mi[0].pName)<<endl;

   // Create new port
   pi[0].pName="TestPort1:";
   r=pf(NULL,1,PBYTE(pi),/*mi[1].pName*/"Local Port");
   cout<<"AddPortExA "<<(r ? "OK" : "failed")<<endl;
   if(!r) cout<<"err="<<GetLastError()<<endl;

   // List port names again
   r=EnumPorts(NULL,1,PBYTE(pi),sizeof(pi),&nNeed,&nRet);
   cout<<"EnumPorts()="<<r<<" nRet="<<nRet<<endl;
   if(!r || nRet<1)
      return;
   for(i=0;i<nRet;i++)
      cout<<"Port name "<<i<<": "<<(pi[i].pName)<<endl;
}
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft Development

From novice to tech pro — start learning today.