System.AccessViolationException: Attempted to read or write protected memory  
Author Message
Jessica Alba





PostPosted: Visual C# General, System.AccessViolationException: Attempted to read or write protected memory Top

I am using .NET 2.0 VS2005. I am writing a network application to allow users from other PC to talk to my application (running at my PC) to print through my printer driver.

I got this runtime exception:

System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

at PrintGateway.PrintEngine.OpenPrinter(String szPrinter, IntPtr& hPrinter, IntPtr pd)

at PrintGateway.PrintEngine.SendBytesToPrinter(Int32 flag, String szPrinterName, String docname, IntPtr pBytes, Int32 dwCount) in E:\PrintGateway\PrintEngine.cs:line 70

at PrintGateway.PrintEngine.SendStringToPrinter(String szPrinterName, String docname, String szString) in E:\PrintGateway\PrintEngine.cs:line 167

Below is my code where this exception happens. Please help me. Thanks and best regards.

public static bool SendStringToPrinter(string szPrinterName,

string docname,

string szString)

{

IntPtr pBytes = new IntPtr();

try

{

// Assume that the printer is expecting ANSI text, and then convert

// the string to ANSI text

pBytes = Marshal.StringToCoTaskMemAnsi(szString);

Byte[] encodedBytes = Encoding.UTF8.GetBytes(szString);

Marshal.Copy(encodedBytes, 0, pBytes, encodedBytes.Length);

// Send the converted ANSI string to the printer.

SendBytesToPrinter(0, szPrinterName, docname, pBytes, encodedBytes.Length);

}

catch (Exception ex)

{

log.Error("Printing Exception : " + ex);

}

finally

{

Marshal.FreeCoTaskMem(pBytes);

}

return true;

}

// SendBytesToPrinter()

// When the function is given a printer name and an unmanaged array

// of bytes, the function sends those bytes to the print queue.

// Returns true on success, false on failure.

public static bool SendBytesToPrinter(string szPrinterName,

string docname, IntPtr pBytes, Int32 dwCount)

{

Int32 dwError = 0, dwWritten = 0;

IntPtr hPrinter = new IntPtr(0);

DOCINFOA di = new DOCINFOA();

bool bSuccess = false; // Assume failure unless you specifically succeed.

di.pDocName = docname;

di.pDataType = "RAW";

// Open the printer.

if (OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero))

{

if ( StartDocPrinter(hPrinter, 1, di))

{

if ( StartPagePrinter(hPrinter))

{

bSuccess = WritePrinter(hPrinter, pBytes, dwCount, out dwWritten);

EndPagePrinter(hPrinter);

}

EndDocPrinter(hPrinter);

}

ClosePrinter(hPrinter);

}

// If you did not succeed, GetLastError may give more information

// about why not.

if (bSuccess == false)

{

dwError = Marshal.GetLastWin32Error();

}

return bSuccess;

}



Visual C#3  
 
 
TaylorMichaelL





PostPosted: Visual C# General, System.AccessViolationException: Attempted to read or write protected memory Top

The error is occuring at OpenPrinter. Try checking the printer string name before invoking the method to ensure it is valid. Also you should verify what the parameters are suppose to be because right now the second parameter is pointing to nothing and it might need to be point to something. You could also try changing it from an out parameter to a ref parameter. Finally you need to look at the implementation of OpenPrinter to see what it might be doing. Maybe it doesn't like your print document being null.

Michael Taylor - 12/4/06


 
 
cl408e





PostPosted: Visual C# General, System.AccessViolationException: Attempted to read or write protected memory Top

Hi Michael,

I tried your methods but it doesn't work. In fact, after the changes, I got StackOverFlow Exception. I got a feeling it is a problem due to the unmanaged code...or maybe the use of IntPtr.

Some more information for you. This problem occurs only when I send large amount of data (e.g., more than 1000 characters).

And I am actually sending a printer language command to the printer (of course I am dead sure my command is perfect). So I don't think I can use System.Drawing method, which is meant for printing of file or documet

Please give me your insight.

Thanks and best regards,


 
 
TaylorMichaelL





PostPosted: Visual C# General, System.AccessViolationException: Attempted to read or write protected memory Top

I'm somewhat confused now. The original exception and stack you posted identified OpenPrinter as the problem. That functio n didn't seem to pass any of the data so I'd be surprised if the length of the data caused problems. However...

I noticed in your SendStringToPrinter method that you call Marshal.StringToCoTaskMemAnsi. You then proceed to overwrite the newly copied string with another value. This may cause problems. Marshal.StringToCoTaskMemAnsi will allocate and copy the managed string to unmanaged COM memory. Therefore you don't/shouldn't need to manipulate it any more other than getting the length.

public static bool SendStringToPrinter(string szPrinterName, string docname, string szString)
{
IntPtr pBytes = IntPtr.Zero;

try
{
pBytes = Marshal.StringToCoTaskMemAnsi(szString);
int nLen = szString.Length; //Assumes no DBCS values

SendBytesToPrinter(0, szPrinterName, docname, pBytes, nLen);
} catch (Exception ex)
{
log.Error("Printing Exception : " + ex);
} finally
{
Marshal.FreeCoTaskMem(pBytes);
}

return true;
}

You didn't specify what PrintGateway.PrintEngine is. Is it a COM object Is it a managed class wrapper If it is COM then the code should work. If it is not COM then you shouldn't be copying it into COM memory. You should instead use Marshal.StringToHGlobalAnsi. However to confirm that everything is working I'd recommend that you first get the SendBytesToPrinter method working correctly. You can then isolate whether it is a string formatting issue. If you get another exception then please be sure to post the callstack as well as it'll give us a better idea of what is going on. Also if you can provide any additional information about the printer stuff you are working with that'd be good.

Finally note that in most cases you need to pin managed reference objects in memory prior to making a P/Invoke or COM call unless the operation will return only after the memory values are used. For example if your SendBytesToPrinter method will return before the data is actually sent to the printer then you'll have a problem because you'll end up freeing the memory before it is used by the underlying print driver. In most situations like this the print driver will raise some sort of event or call some method to notify you when printing is complete. This is where you should free the resources. This actually would explain the original exception you saw and why it occurs only for larger data blocks (perhaps blocks that are too large to be pooled by the driver). You might want to look into this.

Michael Taylor - 12/5/06


 
 
cl408e





PostPosted: Visual C# General, System.AccessViolationException: Attempted to read or write protected memory Top

Hi Michael,

Thanks for the helpful reply. Really appreciate it.

The reason why I overwrote the pBytes is because my szString could contain some UTF8 data such as Chinese or Japanese characters. So I have the following

Byte[] encodedBytes = Encoding.UTF8.GetBytes(szString);

Marshal.Copy(encodedBytes, 0, pBytes, encodedBytes.Length);

Without this, the data of my foreign characters will become in the final output. I guess this is not the proper way of doing such things, so please let me know the proper method. I tried Marshal.StringToCoTaskMemUni already but it didn't work because my data is UTF8.

Please enlighten me.

Thanks and best regards


 
 
TaylorMichaelL





PostPosted: Visual C# General, System.AccessViolationException: Attempted to read or write protected memory Top

I'm not sure about the DBCS conversion but I'd recommend that you first do the conversion using Encoding to a temporary string and then use Marshal.AllocCoTaskMem to allocate the memory needed to hold it. Still, like I said earlier, it might have nothing to do with the string itself. You should verify raw bytes work first and then add in the string conversion just to cut down on the possible problems.

Michael Taylor - 12/5/06


 
 
cl408e





PostPosted: Visual C# General, System.AccessViolationException: Attempted to read or write protected memory Top

hi Michael,

Thanks for your patient and great help.

This is my code now:

Byte[] encodedBytes = Encoding.UTF8.GetBytes(szString);

pBytes = Marshal.AllocCoTaskMem(encodedBytes.Length);

Marshal.Copy(encodedBytes, 0, pBytes, encodedBytes.Length);

My text is finally able to be printed from my printer.

Have a nice day.