Reputation: 16413
We have a virtual printer (provided by a 3rd party) that is getting assigned to an invalid local printer port. The printer is always local (we aren't dealing with a remote print server or anything like that). I'd like to create a new local port (specific for our application), then configure the printer to be assigned to that port instead of the random (and often incorrect) port that the print driver installer chooses.
I believe that I need to use the XcvData and/or XcvDataPort functions to do this, but I'm at a bit of a loss as to how.
Does anyone have any examples or pointers on how to proceed?
I'd imagine that I need to do the following:
and for uninstall:
Upvotes: 3
Views: 6669
Reputation: 1
I guess your code merely worked by chance. According to https://learn.microsoft.com/en-us/windows-hardware/drivers/print/tcpmon-xcv-commands (and to my own experience) the real solution is:
PORT_DATA_1 pdPortData;
wcscpy_s(pdPortData.sztPortName, MAX_PORTNAME_LEN, lpPortName);
[...]
if (!XcvData(hXcv, L"AddPort", (BYTE*) &pdPortData, sizeof(PORT_DATA_1), NULL, 0, &dwNeeded, &dwStatus))
[...]
By chance sztPortName is the first element in PORT_DATA_1 structure. Maybe that's why your code did not fail, although it is wrong.
Upvotes: 0
Reputation: 16413
Wow, looks like that one stumped everyone... After much digging, here's how to do it:
DWORD CreatePort(LPWSTR portName)
{
HANDLE hPrinter;
PRINTER_DEFAULTS PrinterDefaults;
memset(&PrinterDefaults, 0, sizeof(PrinterDefaults));
PrinterDefaults.pDatatype = NULL;
PrinterDefaults.pDevMode = NULL;
PrinterDefaults.DesiredAccess = SERVER_ACCESS_ADMINISTER;
DWORD needed;
DWORD rslt;
if (!OpenPrinter(",XcvMonitor Local Port", &hPrinter, &PrinterDefaults))
return -1;
DWORD xcvresult= 0;
if (!XcvData(hPrinter, L"AddPort", (BYTE *)portName, (lstrlenW(portName) + 1)*2, NULL, 0, &needed, &xcvresult))
rslt= GetLastError();
if (!ClosePrinter(hPrinter))
rslt= GetLastError();
return rslt;
}
Setting the port on a given printer is relatively straight forward - OpenPrinter(), GetPrinter() with PRINTER_INFO_2, SetPrinter(), ClosePrinter()
Cheerio.
Upvotes: 3