-->

How I can get printer name from device and printer

2019-04-15 12:02发布

问题:

I'm getting system printers icons using code (only way I found - is to use IShellFolder ), now I want to connect them with InstalledPrinters, but problem is - I can`t find way to find real printer name (such as "\ServerName\PrinterName" ), with is different to display name of content of "Devices and printers" shell folder and only correct to use with PrinterSettings.

The code I have use to retrive printer icons and printer captions in "Devices and printers" shell folder:

    Shell32.IShellFolder iDesktopFolder = Shell32.GetDesktopFolder();
    try
    {
        IntPtr pidlPrintersFolder;
        if (Shell32.SHGetFolderLocation(_hwndOwner, (int)Shell32.CSIDL.CSIDL_PRINTERS, IntPtr.Zero, 0, out pidlPrintersFolder) == 0)
            try
            {
                StringBuilder strDisplay = new StringBuilder(260);
                Guid guidIShellFolder = Shell32.IID_IShellFolder;
                IntPtr ptrPrintersShellFolder;
                iDesktopFolder.BindToObject(pidlPrintersFolder, IntPtr.Zero, ref guidIShellFolder, out ptrPrintersShellFolder);
                Object objPrintersShellFolder = Marshal.GetTypedObjectForIUnknown(ptrPrintersShellFolder, Shell32.ShellFolderType);
                try
                {
                    Shell32.IShellFolder printersShellFolder = (Shell32.IShellFolder)objPrintersShellFolder;

                    IntPtr ptrObjectsList;

                    printersShellFolder.EnumObjects(_hwndOwner, Shell32.ESHCONTF.SHCONTF_NONFOLDERS, out ptrObjectsList);
                    Object objEnumIDList = Marshal.GetTypedObjectForIUnknown(ptrObjectsList, Shell32.EnumIDListType);
                    try
                    {
                        Shell32.IEnumIDList iEnumIDList = (Shell32.IEnumIDList)objEnumIDList;
                        IntPtr[] rgelt = new IntPtr[1];
                        IntPtr pidlPrinter;
                        int pceltFetched;
                        Shell32.STRRET ptrString;
                        while (iEnumIDList.Next(1, rgelt, out pceltFetched) == 0 && pceltFetched == 1)
                        {
                            printersShellFolder.GetDisplayNameOf(rgelt[0],                                        
                                Shell32.ESHGDN.SHGDN_NORMAL, out ptrString);                                        
                            if (Shell32.StrRetToBuf(ref ptrString, rgelt[0], strDisplay,
                                (uint)strDisplay.Capacity) == 0)
                            {
                                pidlPrinter = Shell32.ILCombine(pidlPrintersFolder, rgelt[0]);
                                string printerDisplayName = strDisplay.ToString();

                                Shell32.SHFILEINFO shinfo = new Shell32.SHFILEINFO();
                                Shell32.SHGetFileInfo(this._pidl, 0, out shinfo, (uint)Marshal.SizeOf(shinfo), Shell32.SHGFI.PIDL | Shell32.SHGFI.AddOverlays | Shell32.SHGFI.Icon);
                                Icon printerIcon = (Icon)Icon.FromHandle(shinfo.hIcon).Clone();
                                Shell32.DestroyIcon(shinfo.hIcon);

                                // HOW TO GET PRINTER NAME (\\ServerName\printername) WITH IS DIFFERENT FROM A PRINTER NAME IN "DEVICES AND PRINTERS" SYSTEM FOLDER
                            }
                        }
                    }
                    finally
                    {
                        Marshal.ReleaseComObject(objEnumIDList);
                    }
                }
                finally
                {
                    Marshal.ReleaseComObject(objPrintersShellFolder);
                }
            }
            finally
            {
                Shell32.ILFree(pidlPrintersFolder);
            }
    }
    finally
    {
        Marshal.ReleaseComObject(iDesktopFolder);
    }

thanks for any help.

回答1:

Find the answer by myself.

To enumerate printers in IShellFolder we must use IShellFolder.ParseDisplayName method, not EnumObjects, and send printer name from PrinterSettings.IntalledPrinters (such as "\ServerName\PrinterName" for network printers) to IShellFolder.ParseDisplayName param pszDisplayName, IShellFolder "Devices and printers" work with this well.

So, after this we can enumerate real printer names ("\ServerName\PrinterName"), printer display names ("PrinterName on ServerName" as printers listed in "Devices and printers") and printer icons.

I will post full code here for father search after some edits.



回答2:

In the loop you can use printersShellFolder.GetUIObjectOf for IID_IDataObject on current rgelt[0] and call IDataObject::GetData with "PrinterFriendlyName" as clipboard format to get the real printer name (encoded in STGMEDIUM).

You can use printersShellFolder.GetUIObjectOf for IID_IQueryInfo on the current pidl to get the printer status too.