cancel
Showing results for 
Search instead for 
Did you mean: 

Impersonating NETWORK SERVICE as a domain user failed

Former Member
0 Kudos

Hi.

Please help on this, coz our development team has absolutely NO clue on how to solve this, and yet it is an issue that MUST be solved.

We want to do server printing on the IIS server, one or many printers are attached to it.

We are not letting all users to print thru it (via our ASP.NET app), but we will see if the user's domain account has access right to this printer.

Let's say there will be a page to print report, there is a drop-down combo box to let users choose a printer

if the AD user account has no right to use the printer, the drop down list will not contain that printer's name

What we are doing is to impersonate the current process (i.e. w3wp) to the user's AD account,

and after the impersonation, enumerate the user a/c's printers. We have no problems on this, it's working.

Let's say user USER1 has access right to printer PRINTER1. So he can see PRINTER1 in the dropdown, and click "print".

After that, we execute:

rptDoc1.PrintOptions.PrinterName = "PRINTER1";

A COMexception is thrown "printername is invalid crRpt {047E0C9D-57F3-4007-9713-8BBB24D942C6}.rpt"

(Errorcode: -2147483135)

We are almost 100% certain that it is caused by crystal reports instead of a general printing/access rights issue,

coz we add the following code to find that out:

PrintDocument pdoc = new PrintDocument();
pdoc.PrintPage += new PrintPageEventHandler(pdoc_PrintPage);
pdoc.PrinterSettings.PrinterName = strPrinterName;
pdoc.Print();       //  <------------------- Print (A)


this.RptDoc.PrintOptions.PrinterName = strPrinterName == "" ? GetServerPrinter() : strPrinterName;

this.RptDoc.PrintToPrinter(1, false, 0, 0);  //  <------------------- Print (B)

The line Print (A) WORKS, but not Print (B)

So, the same printer name is valid on the printdoc, but not on rptdoc.

Here are the specs:

IIS version: 7.5
.NET CLR: 4
w3wp identity: NETWORK SERVICE
Windows Server version: 2008 standard
Browser: IE8

Please help, I will provide more information if you need them

Accepted Solutions (1)

Accepted Solutions (1)

0 Kudos

Hi David,

I believe the problem is with the PrintToPrinter method. It's a CR Basic for VS simplified method for printing and has problems and most times that method does not get updated/patched.

You did not say what version of CR or Vs you are using so if you have RAS available the use this PrintController routine, modify of course to fit your code:


        private void button1_Click(object sender, System.EventArgs e) // Print To P button
		{
			System.Drawing.Printing.PrintDocument pDoc = new System.Drawing.Printing.PrintDocument();			
			CrystalDecisions.ReportAppServer.Controllers.PrintReportOptions rasPROpts = new CrystalDecisions.ReportAppServer.Controllers.PrintReportOptions();
            CrystalDecisions.ReportAppServer.ReportDefModel.PrintOptions newOpts = new CrystalDecisions.ReportAppServer.ReportDefModel.PrintOptions();

			pDoc.PrinterSettings.PrinterName = cboCurrentPrinters.Text;
            pDoc.PrinterSettings.SupportsColor.ToString();

            if (pDoc.PrinterSettings.SupportsColor)
            {
                MessageBox.Show("Printer Supports Color", pDoc.PrinterSettings.SupportsColor.ToString());
            }

		rasPROpts.PrinterName = cboCurrentPrinters.Text;			
		rasPROpts.PaperSize = (CrPaperSizeEnum) pDoc.PrinterSettings.PaperSizes[cboCurrentPaperSizes.SelectedIndex].Kind; 
		rasPROpts.PaperSource = (CrPaperSourceEnum) pDoc.PrinterSettings.PaperSources[cboDefaultPaperTrays.SelectedIndex].Kind; 

                newOpts.PrinterName = cboCurrentPrinters.Text;
                newOpts.PaperSize = (CrPaperSizeEnum) pDoc.PrinterSettings.PaperSizes[cboDefaultPaperSizes.SelectedIndex].Kind;
                newOpts.PaperSource = (CrPaperSourceEnum) pDoc.PrinterSettings.PaperSources[cboDefaultPaperTrays.SelectedIndex].Kind; 
                newOpts.DissociatePageSizeAndPrinterPaperSize = true;
                newOpts.PaperOrientation = CrPaperOrientationEnum.crPaperOrientationLandscape;

		rptClientDoc.PrintOutputController.PrintReport(rasPROpts);
		MessageBox.Show("Printing report.", "RAS", MessageBoxButtons.OK,MessageBoxIcon.Information ); 
		}

It's for a windows app but same functionality for a WEB app.

Oh and the cboCurentPrinter is a dialog box that simply populates the printer options.

Thank you

Don

Edited by: Don Williams on Apr 21, 2011 8:15 AM

Former Member
0 Kudos

One more thing, the PrintDocument printing is printing in the impersonated identity (USER1),

but for the crystal report printing, it is still NETWORK SERVICE

also, the line of code throwing the exception is not Print (B),

it crashes on the rptdoc.printoptions.printername line

Edited by: david.hc.chan on Apr 21, 2011 7:56 PM

0 Kudos

Hi David,

I'm using RAS, client Doc is the report defined for RAS.


You can use both in your app:

	public class frmMain : System.Windows.Forms.Form
	{
        CrystalDecisions.CrystalReports.Engine.ReportDocument rpt = new CrystalDecisions.CrystalReports.Engine.ReportDocument();
        CrystalDecisions.ReportAppServer.ClientDoc.ISCDReportClientDocument rptClientDoc;

.....

// this code is to load the printers as defined in the registry.

private void frmMain_Load(object sender, System.EventArgs e)
{
	if (System.Drawing.Printing.PrinterSettings.InstalledPrinters.Count > 0) 
	{
		foreach(String myPrinter in System.Drawing.Printing.PrinterSettings.InstalledPrinters ) 
		{
			cboCurrentPrinters.Items.Add(myPrinter);					
		}
		cboCurrentPrinters.SelectedIndex = 0;
	} 
	else
	{
		rdoCurrent.Enabled = false;
		EnableDisableCurrentControls(false);
	}
	//For printers exposed to System account as per MS Kbase 
	//http://support.microsoft.com/default.aspx?scid=kb;en-us;184291

	//Look to HKEY_USERS\.Default\Software\Microsoft\Windows NT\CurrentVersion\Devices
	Microsoft.Win32.RegistryKey mySystemPrinters = 
		Microsoft.Win32.Registry.Users.OpenSubKey(@".DEFAULT\Software\Microsoft\Windows NT\CurrentVersion\Devices");
	foreach (String defaultPrinters in mySystemPrinters.GetValueNames()) 
	{
		cboDefaultPrinters.Items.Add(defaultPrinters); 
	}
	if (cboDefaultPrinters.Items.Count > 0) 
	{
		cboDefaultPrinters.SelectedIndex = 0;
	} 
	else 
	{
		rdoDefault.Enabled = false; 
	}
}

I don't believe this is a CR issue. CR assumes you have access to the printer. Add a try/catch around the Printer name function to get more info. Once you grant access then CR should be able to print.

Check the link in the code and/or post to the Microsoft forums in Visual Studio on how to pass/set Impersonation for your app in IIS to access the printers. It's the IIS Service and app pool that needs the permission to get/set access to the printer, CR will then have access to the printer name once the app has permissions.

Thanks

Don

Former Member
0 Kudos

> //For printers exposed to System account as per MS Kbase

> //http://support.microsoft.com/default.aspx?scid=kb;en-us;184291

>

> //Look to HKEY_USERS\.Default\Software\Microsoft\Windows NT\CurrentVersion\Devices

> Microsoft.Win32.RegistryKey mySystemPrinters =

> Microsoft.Win32.Registry.Users.OpenSubKey(@".DEFAULT\Software\Microsoft\Windows NT\CurrentVersion\Devices");

> foreach (String defaultPrinters in mySystemPrinters.GetValueNames())

> {

> cboDefaultPrinters.Items.Add(defaultPrinters);

> }

Yeah, I've come across that KB article before,

it said the SYSTEM account has no printers by default

and therefore any printer name will always be invalid to the system account

However, we are IMPERSONATING IIS/ASP.NET's worker process as USER1 and

PRINTER1 should be a valid printer name to USER1

And after the impersonation, System.Drawing.Printing.PrinterSettings.InstalledPrinters

correctly contains the printers of USER1 (therefore, I'm not sure if the registry traversing in your code is necessary)

What I don't understand is, 1) Printdocument.printersettings.printername = "PRINTER1" works 2) System.Drawing.Printing.PrinterSettings.InstalledPrinters is correct (show USER1's printers) ==> but why reportdocument.printersettings.printername="PRINTER1" fails?

(as I said, rptDoc1.PrintOptions.PrinterName = "PRINTER1" throws a COMException, the message is like "invalid printer name" with that GUID in curly brackets,

please also find the HRESULT errorcode in my previous post)

Also, I want to ask, if I follow the KB article to import the registry entries to .DEFAULT,

do I still need to traverse the registry to get the printers?

> I don't believe this is a CR issue. CR assumes you have access to the printer. Add a try/catch around the Printer name function to get more info. Once you grant access then CR should be able to print.

> Check the link in the code and/or post to the Microsoft forums in Visual Studio on how to pass/set Impersonation for your app in IIS to access the printers. It's the IIS Service and app pool that needs the permission to get/set access to the printer, CR will then have access to the printer name once the app has permissions.

>

> Thanks

> Don

If it is related to access rights then how come the PrintDocument works?!

Remember that before Print(A) and Print(B), the impersonation as USER1 is already executed

so, both printing are executed using the rights/credentials of USER1,

and are using the SAME printer

so the conclusion is that, it should be obvious that here

the impersonation is effective to the printdocument, but not the reportdocument

rptClientDoc.PrintOutputController.PrintReport(rasPROpts);

I would like to know what RAS is about, since we are just using CR that comes with VS 2010,

would I be able to use RAS as shown in your code?

We are having a public holiday here so I'm not with my computer at office and

I'm not be able to try out the RAS clientdoc in VS2010,

my VS at home is VS2005, is clientdoc also available?

what I've done before is to use reportdocument to load a .rpt file,

can RAS' clientdoc load the same rpt too?

or should the clientdoc be associated to an existing reportdocument?

Edited by: david.hc.chan on Apr 23, 2011 8:18 AM

Former Member
0 Kudos

Look, is your code extracted from an existing windows forms app (or web app, whatever)

that can correctly print?

why don't you send the whole project to me

so that I can test it myself?

or, I can send you the web app that would not be able to print

so that you can test yourself if there is anything wrong in the code?

0 Kudos

Hi David,

RAS is included with CR for VS 2010, it's not included in any other version of VS.

this forum is not support case system but for all users to help each other. We can't attach files to these posts. I suggest you purchase a support case that way your test app and logs etc. can be passed back and forth between the SAP Rep and you.

I still think this is a MS issue and not a CR configuration problem. CR just passes the info for the printer to the Spooler.

Process Monitor may be able to show you where your are getting the access denied issues.

Also, wrapping your function in a try/catch may give you more info also.

Thank you

Don

former_member183750
Active Contributor
0 Kudos

This may be as simple as defining your system printers. See the following:

http://support.microsoft.com/kb/184291/en-us

Other than that, see the blog [What are these "support" forums good for anyhow?|/people/ludek.uher/blog/2011/04/07/what-are-these-support-forums-good-for-anyhow]

- Ludek

Former Member
0 Kudos

Hi,

I'm trying your approach to print via ReportClientDocument.PrintOutputController:

try
{
	// on the clicking of a button of a winform app
	ReportDocument rpt;
	rpt = ProvideRpt();
	CrystalDecisions.ReportAppServer.Controllers.PrintReportOptions rasPROpts = new CrystalDecisions.ReportAppServer.Controllers.PrintReportOptions();
	//RAS.ReportDefModel.PrintOptions RASP_Opt = new RAS.ReportDefModel.PrintOptions();
	//RASP_Opt.PrinterName = txt_CRPrinter.Text;
	rasPROpts.PrinterName = txt_CRPrinter.Text;
	rpt.ReportClientDocument.PrintOutputController.PrintReport(rasPROpts);   // <--- COMException (0x80040154): Class not registered - CrystalPrintControl
	
}
catch (Exception ex)
{

	MessageBox.Show(ex.Message);
}

I got a COMException (0x80040154): Class not registered - CrystalPrintControl

at CrystalDecisions.ReportAppServer.Controllers.PrintOutputControllerClass.PrintReport(PrintReportOptions options)
   at WindowsFormsApplication1.Form1.button11_Click(Object sender, EventArgs e) in C:\Users\edpdavc\Documents\Visual Studio 2010\Projects\WebApplicationCS\WindowsFormsApplication1\Form1.cs:line 252

I googled on CrystalPrintControl a bit, and looks like I'm in the same situation as [this post|;

Do I need to install the runtime for CRVS2010 [here|http://wiki.sdn.sap.com/wiki/pages/viewpage.action?pageId=56787567]?

(My computer is Windows 7 64 bit, do I need to install both CRRuntime_64bit_13_0.msi and CRRuntime_13_0.msm?)

But note that I am testing the app on a development machine with VS2010 installed, I think it is not necessary?

Also, I found out from google that the related dll is PrintControl.dll, do I need to regsvr32 it?

Thanks for your help again!

0 Kudos

Hi David,

That link is for the RTM release. Get SP1 from this link:

[original link is broken]

Update your DEV PC to SP1.

Running the MSI installer will do everything required to deploying our runtime. It's not required on your DEV PC.

Include all of these in your app and then the functions will be available:

using CrystalDecisions.CrystalReports.Engine;

using CrystalDecisions.Shared;

using CrystalDecisions.ReportAppServer.ClientDoc;

using CrystalDecisions.ReportAppServer.Controllers;

using CrystalDecisions.ReportAppServer.ReportDefModel;

using CrystalDecisions.ReportAppServer.CommonControls;

using CrystalDecisions.ReportAppServer.CommLayer;

using CrystalDecisions.ReportAppServer.CommonObjectModel;

using CrystalDecisions.ReportAppServer.ObjectFactory;

using CrystalDecisions.ReportAppServer.DataSetConversion;

using CrystalDecisions.ReportAppServer.DataDefModel;

using CrystalDecisions.ReportSource;

And the Windows or WEB viewer.

Thank you

Don

Former Member
0 Kudos

I've installed CRforVS_13_0_1.exe, but still no luck

I've re-tested the RAS code (ReportClientDocument.PrintController.Printtoprinter),

it still said the same error msg (class not registered)

I also re-tested the original ,

still said "printer is invalid".

0 Kudos

Hi David,

Try this:

On the open/load of the report I assign the Report to RPT and then set it to RAS Client doc also so either can be used:

rptClientDoc = rpt.ReportClientDocument;

Then in my dialog box to populate the printer info I use this:

CrystalDecisions.ReportAppServer.ReportDefModel.PrintOptions rptPRT = new CrystalDecisions.ReportAppServer.ReportDefModel.PrintOptions();

rptPRT = rptClientDoc.PrintOutputController.GetPrintOptions();

System.Drawing.Printing.PrintDocument pDoc = new System.Drawing.Printing.PrintDocument();

CRPrinterName.Text = rpt.PrintOptions.PrinterName.ToString();

I don't get an exception....

Then to set the Printer to the drop down Printer I selected I use this code:


private void btnSetPrinter_Click(object sender, System.EventArgs e)
{
    System.Drawing.Printing.PrintDocument pDoc = new System.Drawing.Printing.PrintDocument();
    CrystalDecisions.ReportAppServer.Controllers.PrintReportOptions rasPROpts = new CrystalDecisions.ReportAppServer.Controllers.PrintReportOptions();

    CrystalDecisions.ReportAppServer.Controllers.PrintReportOptions MYPRTOpts = new CrystalDecisions.ReportAppServer.Controllers.PrintReportOptions();

    if (rdoCurrent.Checked)
    {
        pDoc.PrinterSettings.PrinterName = cboCurrentPrinters.Text;
        //pDoc.PrinterSettings.SupportsColor = true;

        MYPRTOpts.PrinterName = cboCurrentPrinters.Text;
        MYPRTOpts.PaperSize = (CrPaperSizeEnum) pDoc.PrinterSettings.PaperSizes[cboCurrentPaperSizes.SelectedIndex].Kind;
        MYPRTOpts.PaperSource = (CrPaperSourceEnum) pDoc.PrinterSettings.PaperSources[cboCurrentPaperTrays.SelectedIndex].Kind;
        // added the below line to verify the changes work.
        //CrystalDecisions.ReportAppServer.ReportDefModel.CrPaperOrientationEnum.crPaperOrientationLandscape;
        //MYPRTOpts.PaperOrientation = CrPaperOrientationEnum.crPaperOrientationLandscape;

    }
    else
    {
        pDoc.PrinterSettings.PrinterName = cboDefaultPrinters.Text;

        MYPRTOpts.PrinterName = cboDefaultPrinters.Text;
        MYPRTOpts.PaperSize = (CrPaperSizeEnum)
            pDoc.PrinterSettings.PaperSizes[cboDefaultPaperSizes.SelectedIndex].Kind;
        MYPRTOpts.PaperSource = (CrPaperSourceEnum)
            pDoc.PrinterSettings.PaperSources[cboDefaultPaperTrays.SelectedIndex].Kind;
    }
}

So as long as the printer is available through your impersonation code it should fill in the info/select your printer. If not then the issue is still permission related through IIS and you should post on the IIS forum at Microsoft for a solution.

Thanks again

Don

Answers (2)

Answers (2)

Former Member
0 Kudos

Also, we're not using something like crystal enterprise,

just CR .NET out-of-the-box

Former Member
0 Kudos

what type is rptClientDoc?

Former Member
0 Kudos

Some more info:

Visual Studio version: 2010
CPU Architecture: 64bit

Would there be a patch ready to fix this problem?

Edited by: david.hc.chan on Apr 27, 2011 7:57 AM