/// <summary> /// Deletes a printer from the designated server. Must have administrator access to it. /// </summary> /// <param name="sServer"></param> /// <param name="sPrinter"></param> public static void DeletePrinter(CredentialEntry ce, string sServer, string sPrinter) { Session.EnsureNullSession(sServer, ce); // first, open the printer string s = Canon(sServer) + @"\" + sPrinter; int hPrinter; PRINTER_DEFAULTS pd = new PRINTER_DEFAULTS(); pd.pDatatype = IntPtr.Zero; pd.pDevMode = IntPtr.Zero; pd.DesiredAccess = PRINTER_ALL_ACCESS; IntPtr p = Marshal.AllocHGlobal(Marshal.SizeOf(pd)); Marshal.StructureToPtr(pd, p, false); if (!OpenPrinter(s, out hPrinter, p)) { // free memory Marshal.DestroyStructure(p, typeof(PRINTER_DEFAULTS)); Marshal.FreeHGlobal(p); int nError = Marshal.GetLastWin32Error(); Win32Exception we = new Win32Exception(nError); if (nError == nErrorAccessDenied) { throw new AuthException(we); } else { throw we; } } Marshal.DestroyStructure(p, typeof(PRINTER_DEFAULTS)); Marshal.FreeHGlobal(p); // now remove it from AD PRINTER_INFO_7 pi7 = new PRINTER_INFO_7(); pi7.pszObjectGUID = IntPtr.Zero; pi7.dwAction = (uint)DSPRINT_OPTIONS.DSPRINT_UNPUBLISH; p = Marshal.AllocHGlobal(Marshal.SizeOf(pi7)); Marshal.StructureToPtr(pi7, p, false); SetPrinter(hPrinter, 7, p, 0); // NOTE: we swallow any error since the operation may be left in a "pending" state rather // than returning success or failure right away. // free memory Marshal.DestroyStructure(p, typeof(PRINTER_INFO_7)); Marshal.FreeHGlobal(p); // finally, remove the printer if (!DeletePrinter(hPrinter)) { int nError = Marshal.GetLastWin32Error(); Win32Exception we = new Win32Exception(nError); if (nError == nErrorAccessDenied) { throw new AuthException(we); } else { throw we; } } }
/// <summary> /// Fetches data about the printers available on the designated server /// </summary> /// <param name="sServer"></param> /// <param name="dt">The DataTable into which the data should be placed. dt MUST have been created properly with CreateDataTable</param> public static Dictionary <int, string[]> FetchPrinterData(CredentialEntry ce, string sServer) { int dwFlags = (int)PEFlags.PRINTER_ENUM_NAME; string Name = Canon(sServer); int Level = 2; IntPtr pPrinterEnum = IntPtr.Zero; int cBufNeeded = 0; int cReturned = 0; if (!Session.EnsureNullSession(sServer, ce)) { return(null); } Dictionary <int, string[]> printInfoList = new Dictionary <int, string[]>(); /// /// TODO: revise. Samba 3.0.13 fails if we pass in a null buffer. To avoid this /// pass in a pointer to a zero length buffer! /// #if SAMBAFIXED if (EnumPrinters(dwFlags, Name, Level, pPrinterEnum, 0, ref cBufNeeded, ref cReturned)) { // Can only happen if no printers available! return; } #else { } pPrinterEnum = Marshal.AllocHGlobal(0); if (EnumPrinters(dwFlags, Name, Level, pPrinterEnum, 0, ref cBufNeeded, ref cReturned)) { // free the mem Marshal.FreeHGlobal(pPrinterEnum); // Can only happen if no printers available! return(null); } // free the mem Marshal.FreeHGlobal(pPrinterEnum); #endif // Normally, we fail because we need a bigger buffer. However, if we fail // with RPC_S_CALL_FAILED, this means that we "succeeded" but that the remote // machine has nothing to tell us int nError = Marshal.GetLastWin32Error(); if (nError == nErrorRPC_S_CALL_FAILED) { return(null); } if (nError != ERROR_INSUFFICIENT_BUFFER) { // Any other error results in an exception string sErr; if (nError == nErrorBadRPC) { sErr = sBadServerName; } else if (nError == nErrorAccessDenied) { throw new AuthException(new Win32Exception(nError)); } else { sErr = string.Format(sErrorMsg, sServer, nError); } throw new Win32Exception(sErr); } // allocate a big enough buffer pPrinterEnum = Marshal.AllocHGlobal(cBufNeeded); // retry if (!EnumPrinters(dwFlags, Name, Level, pPrinterEnum, cBufNeeded, ref cBufNeeded, ref cReturned)) { nError = Marshal.GetLastWin32Error(); Win32Exception we = new Win32Exception(nError); if (nError == nErrorAccessDenied) { throw new AuthException(we); } else { throw we; } } // iterate through the retrieved entries, copying printer entries // to the output table IntPtr pCur = pPrinterEnum; for (int i = 0; i < cReturned; i++) { // marshal the entry into PRINTER_INFO_2 pi2 = new PRINTER_INFO_2(); Marshal.PtrToStructure(pCur, pi2); // trim off server name string sName = Marshal.PtrToStringUni(pi2.pPrinterName); if (sName.StartsWith(@"\\")) { // yep, trim off prefix int ibackwhack = sName.LastIndexOf(@"\"); sName = sName.Substring(ibackwhack + 1); } string[] printInfo = { Marshal.PtrToStringUni(pi2.pShareName), Marshal.PtrToStringUni(pi2.pDriverName), pi2.cJobs.ToString(), Marshal.PtrToStringUni(pi2.pComment) }; // advance to the next entry pCur = (IntPtr)((int)pCur + Marshal.SizeOf(pi2)); printInfoList.Add(i, printInfo); } // free the mem Marshal.FreeHGlobal(pPrinterEnum); return(printInfoList); }