需要在XPS打印机上设置端口。我在Stackoverflow上找到了一些例子,但它不起作用。 这是一个代码(很多垃圾):
LPTSTR pDeviceName = _T("Microsoft XPS Document Writer");
HANDLE phPrinter(nullptr);
PRINTER_DEFAULTS defaults;
defaults.DesiredAccess = PRINTER_ACCESS_USE;
defaults.pDatatype = 0;
PORT_INFO_3 pInfo3;;
DWORD needed;
DWORD XcvResult;
DWORD err = OpenPrinter(pDeviceName,&phPrinter,NULL);
//const BYTE* portValue = reinterpret_cast<const BYTE*>("TestPort");
PBYTE port = (PBYTE)_T("Test1");
if(err) {
int res = XcvData(phPrinter,_T("AddPort"),port,sizeof(port),NULL,0,&needed,&XcvResult);
}
else {
AfxMessageBox(_T("ERROR."),MB_OK);
}
ClosePrinter(phPrinter);
这个代码只运行一次最有趣的事情(XcvData func的第一次启动)!
另一个相同行为的例子:
BOOL AddPortX(void)
{
DWORD cbneed,cbstate;
PBYTE pOutputData;
HANDLE hXcv = INVALID_HANDLE_VALUE;
PRINTER_DEFAULTS Defaults = { NULL,NULL,SERVER_ACCESS_ADMINISTER };
WCHAR pszPortName[]=L"UTReportPDFPort:";
pOutputData=(PBYTE)malloc(MAX_PATH);
if(!OpenPrinter(_T("Microsoft XPS Document Writer"),&hXcv,NULL ))
{
LPVOID lpMsgBuf;
GetLastError();
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), NULL,(LPTSTR) &lpMsgBuf, 0, NULL );
::MessageBox(NULL,(LPCTSTR)lpMsgBuf,_T("ERROR"),MB_OK|MB_ICONINFORMATION);
free(pOutputData);
LocalFree( lpMsgBuf );
return FALSE;
}
// False
if(!XcvData(hXcv,L"AddPort",(PBYTE)pszPortName,sizeof(pszPortName),(PBYTE)pOutputData,MAX_PATH,&cbneed,&cbstate))
{
LPVOID lpMsgBuf;
SetLastError(cbstate);
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), NULL,(LPTSTR) &lpMsgBuf, 0, NULL );
::MessageBox(NULL,(LPCTSTR)lpMsgBuf,_T("ERROR"),MB_OK|MB_ICONINFORMATION);
LocalFree( lpMsgBuf );
free(pOutputData);
}
free(pOutputData);
ClosePrinter(hXcv);
return TRUE;
}
那么,如何设置添加打印机端口,并在添加后自动选择它? 也许,有人知道它为什么只运作一次?我的意思是 - XcvData函数。所有下一次它都会返回错误代码6。 .NET解决方案也会很好。
答案 0 :(得分:1)
public static class Winspool
{
[StructLayout(LayoutKind.Sequential)]
private class PRINTER_DEFAULTS
{
public string pDatatype;
public IntPtr pDevMode;
public int DesiredAccess;
}
[DllImport("winspool.drv", EntryPoint = "XcvDataW", SetLastError = true)]
private static extern bool XcvData(
IntPtr hXcv,
[MarshalAs(UnmanagedType.LPWStr)] string pszDataName,
IntPtr pInputData,
uint cbInputData,
IntPtr pOutputData,
uint cbOutputData,
out uint pcbOutputNeeded,
out uint pwdStatus);
[DllImport("winspool.drv", EntryPoint = "OpenPrinterA", SetLastError = true)]
private static extern int OpenPrinter(
string pPrinterName,
ref IntPtr phPrinter,
PRINTER_DEFAULTS pDefault);
[DllImport("winspool.drv", EntryPoint = "ClosePrinter")]
private static extern int ClosePrinter(IntPtr hPrinter);
public static int AddLocalPort(string portName)
{
PRINTER_DEFAULTS def = new PRINTER_DEFAULTS();
def.pDatatype = null;
def.pDevMode = IntPtr.Zero;
def.DesiredAccess = 1; //Server Access Administer
IntPtr hPrinter = IntPtr.Zero;
int n = OpenPrinter(",XcvMonitor Local Port", ref hPrinter, def);
if (n == 0)
return Marshal.GetLastWin32Error();
if (!portName.EndsWith("\0"))
portName += "\0"; // Must be a null terminated string
// Must get the size in bytes. Rememeber .NET strings are formed by 2-byte characters
uint size = (uint)(portName.Length * 2);
// Alloc memory in HGlobal to set the portName
IntPtr portPtr = Marshal.AllocHGlobal((int)size);
Marshal.Copy(portName.ToCharArray(), 0, portPtr, portName.Length);
uint needed; // Not that needed in fact...
uint xcvResult; // Will receive de result here
XcvData(hPrinter, "AddPort", portPtr, size, IntPtr.Zero, 0, out needed, out xcvResult);
ClosePrinter(hPrinter);
Marshal.FreeHGlobal(portPtr);
return (int)xcvResult;
}
}
OpenPrinter()中的第一个参数必须是 - XcvMonitor Local Port。 我们可以使用.NET管理对象来选择端口是默认的。