Search code examples
c#windowsprintingshareshared

How to un-share shared printer?


I'm developing 'Share Monitoring Application' via C# and it's monitoring the sharing activities and I'm using these APIs to implement enumerate shared items/un-sharing shared items.

Api used:

NetShareEnum
NetShareDel


NetShareEnum to enumerate all shared items and NetShareDel to delete shared items (=unshare).
I used SHChangeNotify to remove shared mark and directories working fine.
(Delete shared item using NetShareDel is not affected immediately.)

But printer state is not affected by SHChangeNotify. Which mean after deleting shared printer via NetShareDel and call SHChangeNotify with SHCNE_NETUNSHARE and SHCNF_PATHW. Also I used SHCNE_NETUNSHARE and SHCNF_PRINTERW too, but nothing happened.

Shared printer's state mark: https://i.sstatic.net/1ZGrI.png
In this picture, you can see the users the right side of check circle and that indicate printer is shared.
But after calling NetShareDel to unshared shared printer and it's succeed, but shared mark is disappear.

Anyone know how to implement this? I'm waiting for your help. :D
Sorry for my bad english.


Solution

  • I tried WMI and it works on my computer, but other computers throw an exception. And I think the reason of application throw an exception is the one of required library is missing on the computer. So I'm looking for the API that can be used instead of the WMI.

    Finally I found the GetPrinter and SetPrinter from the MSDN.

    And also I found PRINTER_INFO_5 structure. According to MSDN, Attributes field indicate the printer's attribute including printer is shared or not. And this can be checked Attributes field has PRINTER_ATTRIBUTE_SHARED value.

    Anyway, this problem can be solved only OpenPrinter, GetPrinter and SetPrinter.



    This image shows the before and after calling 'UnsharePrinter' method. Before and After the calling UnsharePrinter method

    This is the method I made to un-share the shared printer.
    (Un-sharing the shared printer can be performed via NetShareDel, but it cannot notify printer is un-shared to the system.)

    Boolean UnsharePrinter(String printerName) {
        // fill PRINTER_DEFAULTS structure
        // and set DesiredAccess to PRINTER_ACCESS_ADMINISTER to 
        // get rights to call SetPrinter
        PRINTER_DEFAULTS pd;
        pd.pDatatype = IntPtr.Zero;
        pd.pDevMode = IntPtr.Zero;
        pd.DesiredAccess = PRINTER_ACCESS_ADMINISTER;
    
        IntPtr pDefaults = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(PRINTER_DEFAULTS)));
        Marshal.StructureToPtr(pd, pDefaults, true);
    
        IntPtr hPrinter;
        // open the printer
        if ( !OpenPrinter(printerName, out hPrinter, pDefaults) ) {
            Marshal.FreeHGlobal(pDefaults);
            return false;
        }
    
        // first, call Zero pointer and 0 size to get minimum required space
        IntPtr pInfo = IntPtr.Zero;
        Int32 pcbNeeded;
        GetPrinter(hPrinter, 5, pInfo, 0, out pcbNeeded);
    
        // alloc reqiured space and call GetPrinter
        pInfo = Marshal.AllocHGlobal(pcbNeeded);
        if ( !GetPrinter(hPrinter, 5, pInfo, pcbNeeded, out pcbNeeded) ) {
            Marshal.FreeHGlobal(pInfo);
            ClosePrinter(hPrinter);
            return false;
        }
    
        // pointer to structure
        PRINTER_INFO_5 pi5 = (PRINTER_INFO_5) Marshal.PtrToStructure(pInfo, typeof(PRINTER_INFO_5));
        Marshal.FreeHGlobal(pInfo);
    
        // if printer is not shared, release the memory and exit
        if ( (pi5.Attributes & PRINTER_ATTRIBUTE_SHARED) == 0 ) {
            ClosePrinter(hPrinter);
            return false;
        }
    
        // remove the shared flag
        pi5.Attributes &= ~PRINTER_ATTRIBUTE_SHARED;
    
        // alloc pointer and make structure as pointer
        pInfo = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(PRINTER_INFO_5)));
        Marshal.StructureToPtr(pi5, pInfo, true);
    
        // set printer
        Boolean r = SetPrinter(hPrinter, 5, pInfo, 0);
        Marshal.FreeHGlobal(pInfo);
        ClosePrinter(hPrinter);
    
        return r;
    }