peter
peter

Reputation: 1049

DeviceCapabilities generates error: data is invalid

I want to get a printer's list of paper source, paper size, etc. I slightly modified the codes from http://www.pinvoke.net/default.aspx/Enums/DeviceCapabilities.html?diff=y The codes sometimes work, sometimes not. The proplem is DeviceCapabilities(DeviceName, strPort, DeviceCapabilitiesFlags.DC_BINNAMES, (IntPtr)null, (IntPtr)null) returns -1. the last error is "data is invalid" Restart computer may not solve the problem. Once getting the problem, next time maybe OK maybe not.

So what is the problem here?

ArrayList arrBinName;
string sError = "";
GetBins("\\Lindy-PC.MyCpmpany.local\HP LaserJet 4000 Series PCL 5", "LPT1", out arrBinName, out sError);

    public static bool GetBins(string DeviceName, string strPort, out ArrayList BinName, out string strError)
    {
        strError = "";
        BinName = new ArrayList();

        IntPtr pAddr = default(IntPtr);
        int offset = 0;

        int nRes = DeviceCapabilities(DeviceName, strPort, DeviceCapabilitiesFlags.DC_BINNAMES, (IntPtr)null, (IntPtr)null);  //Returns -1
        if (nRes >= 0)
        {
            try
            {
                pAddr = Marshal.AllocHGlobal((int)nRes * 24);
                nRes = DeviceCapabilities(DeviceName, strPort, DeviceCapabilitiesFlags.DC_BINNAMES, pAddr, (IntPtr)null);
                if (nRes < 0)
                {
                    strError = new Win32Exception(Marshal.GetLastWin32Error()).Message + "[" + DeviceName + ": " + strPort + ".DC_BINNAMES]";
                    return false;
                }

                offset = pAddr.ToInt32();
                for (int i = 0; i < nRes; i++)
                {
                    BinName.Add(Marshal.PtrToStringAnsi(new IntPtr(offset + i * 24)));
                }
            }
            finally
            {
                Marshal.FreeHGlobal(pAddr);
            }
        }
        else
            strError = new Win32Exception(Marshal.GetLastWin32Error()).Message + "[" + DeviceName + ": " + strPort + ".DC_BINNAMES]";

        return true;
    }

Upvotes: 1

Views: 629

Answers (1)

Carey Gregory
Carey Gregory

Reputation: 6846

As aggaton mentioned in his or her comment, DeviceCapabilities requires two calls in certain circumstances and retrieving bin names is one of them. You should first read the documentation for DeviceCapabilities.

Then go back and look at the sample code you used. You omitted a key step:

// BinNames
nRes = DeviceCapabilities(strDeviceName, strPort, DeviceCapabilitiesFlags.DC_BINNAMES, (IntPtr)null, (IntPtr)null);
pAddr = Marshal.AllocHGlobal((int)nRes * 24);
nRes = DeviceCapabilities(strDeviceName, strPort, DeviceCapabilitiesFlags.DC_BINNAMES, pAddr, (IntPtr)null);
if(nRes < 0)
{
    strError = new Win32Exception(Marshal.GetLastWin32Error()).Message + "["+ strDeviceName +": "+ strPort +"]";
    return false;
}

Notice that there are three calls to DeviceCapabilities in that code. You need all three. (I think the code would be clearer by making each call a separate line of code but that's a style issue.) The doc for DeviceCapabilities plus the sample code above should get you back on track.

Upvotes: 1

Related Questions