So I have created a form to allow our Marketing team to restart a computer that displays a slideshow/important information for visitors etc
The plan is to deploy this to other user comptuers and then they can do one of the three following tasks:
Restart now
Timed/Scheduled restart
Cancel Timed/Scheduled restart
The application works fine on my computer just fine in debug and in build.
When installing on other people's computers it seems as if it is launching psexec but then not doing anything.
I added some catch exceptions in at which point it shows me the following error:
standardout has not been redirected
However when researching into this I seem to already have the code most people suggest to fix this issue.
My code is as below:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;
using System.IO;
namespace Media_Wall_Restart_Scheduler
{
public partial class frm_mediawall_startform : Form
{
public frm_mediawall_startform()
{
InitializeComponent();
input_time.Value = DateTime.Now;
}
static class Programmability
{
/* Secure Credential Store - This is for remote reboots */
public static readonly string mediawallcomputername = #"\\computername";
public static readonly string adminusername = "computeraccount";
public static readonly string admindomainame = "domainname";
public static readonly string adminpassword = "computeraccountpassword";
public static readonly string addadminpassword = " -p " + adminpassword;
public static readonly string adminuseraccount = admindomainame + #"\" + adminusername;
public static readonly string addadminuseraccount = " -u " + admindomainame + #"\" + adminusername;
public static readonly string Restartnow = mediawallcomputername + addadminuseraccount + addadminpassword + " shutdown -r -t 30";
public static readonly string CancelShutdown = mediawallcomputername + addadminuseraccount + addadminpassword + " shutdown -a";
public static readonly string psexecpath = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "Resources", "PsExec.exe"));
/* End Secure credential Store */
}
private void Btn_restart_now_Click(object sender, EventArgs e)
{
/* Quick and simple Restart now command */
Process Restart_now = new Process();
Restart_now.StartInfo.UseShellExecute = false;
Restart_now.StartInfo.RedirectStandardOutput = true;
Restart_now.StartInfo.RedirectStandardError = true;
Restart_now.StartInfo.RedirectStandardInput = true;
Restart_now.StartInfo.FileName = Programmability.psexecpath;
var Restartnow_args = new List<string> { Programmability.mediawallcomputername, Programmability.addadminuseraccount, Programmability.addadminpassword, "shutdown -s -t 30" };
Restart_now.StartInfo.Arguments = string.Join(" ", Restartnow_args);
{
Restart_now.Start();
string Output = Restart_now.StandardOutput.ReadToEnd();
string Errormessage = Restart_now.StandardError.ReadToEnd();
Restart_now.WaitForExit();
}
}
public void Btn_scheduled_restart_Click(object sender, EventArgs e)
{
/* Gets the current time */
DateTime Timenow = DateTime.Now;
DateTime Restarttime = input_time.Value;
/* Takes the Scheduled time and subtracts from now time above */
var ScheduledRestartTime = Math.Ceiling((Restarttime - Timenow).TotalSeconds);
/* Run the command to restart the Media wall at the specifed time */
Process Timed_Restart = new Process();
Timed_Restart.StartInfo.UseShellExecute = false;
Timed_Restart.StartInfo.RedirectStandardOutput = true;
Timed_Restart.StartInfo.RedirectStandardError = true;
Timed_Restart.StartInfo.RedirectStandardInput = true;
Timed_Restart.StartInfo.FileName = Programmability.psexecpath;
var TimedRestart_args = new List<string> { Programmability.mediawallcomputername, Programmability.addadminuseraccount, Programmability.addadminpassword, "shutdown -r", $"-t {ScheduledRestartTime}" };
Timed_Restart.StartInfo.Arguments = string.Join(" ", TimedRestart_args);
{
Timed_Restart.Start();
string Output = Timed_Restart.StandardOutput.ReadToEnd();
string Errormessage = Timed_Restart.StandardError.ReadToEnd();
Timed_Restart.WaitForExit();
}
}
private void Btn_stop_restart_Click(object sender, EventArgs e)
{
Process Stop_Restart = new Process();
Stop_Restart.StartInfo.UseShellExecute = false;
Stop_Restart.StartInfo.RedirectStandardOutput = true;
Stop_Restart.StartInfo.RedirectStandardError = true;
Stop_Restart.StartInfo.RedirectStandardInput = true;
Stop_Restart.StartInfo.FileName = Programmability.psexecpath;
var cancel_args = new List<string> { Programmability.mediawallcomputername, Programmability.addadminuseraccount, Programmability.addadminpassword, "shutdown -a" };
Stop_Restart.StartInfo.Arguments = String.Join(" ", cancel_args);
{
Stop_Restart.Start();
string Output = Stop_Restart.StandardOutput.ReadToEnd();
string Errormessage = Stop_Restart.StandardError.ReadToEnd();
Stop_Restart.WaitForExit();
}
}
}
}
I added the following changes when trying to catch the error but this has not helped me get any further. I will add just one of the controls for show here but it has been applied to each button
private void Btn_stop_restart_Click(object sender, EventArgs e)
{
try
{
Process Stop_Restart = new Process();
Stop_Restart.StartInfo.UseShellExecute = false;
Stop_Restart.StartInfo.RedirectStandardOutput = true;
Stop_Restart.StartInfo.RedirectStandardError = true;
Stop_Restart.StartInfo.RedirectStandardInput = true;
Stop_Restart.StartInfo.FileName = Programmability.psexecpath;
var cancel_args = new List<string> { Programmability.mediawallcomputername, Programmability.addadminuseraccount, Programmability.addadminpassword, "shutdown -a" };
Stop_Restart.StartInfo.Arguments = String.Join(" ", cancel_args);
using (var stopreader = Stop_Restart.StandardOutput)
{
Stop_Restart.BeginOutputReadLine();
Stop_Restart.Start();
string Output = Stop_Restart.StandardOutput.ReadToEnd();
string Errormessage = Stop_Restart.StandardError.ReadToEnd();
Stop_Restart.WaitForExit();
var StopConsoleOut = stopreader.ReadToEnd();
MessageBox.Show(StopConsoleOut, "Success", MessageBoxButtons.OK);
}
}
catch (Exception)
{
MessageBox.Show($"Running psexec failed as {Programmability.psexecpath}", "Error", MessageBoxButtons.OK);
throw;
}
}
I'm going to answer based on your information of "it works on my machine" and "PSExec is opening but not doing anything".
Remember that when PSExec is run for the first time you are required to use -accepteula as per PSExec's output:
"This is the first run of this program. You must accept EULA to
continue. Use -accepteula to accept EULA."
Have you completed this step on the machines which you are deploying this form app to?
Edit:
If you have accepted the EULA, then you should try to identify what var "Errormessage" is.
I would - for troubleshooting on the machines you are deploying to sake - recommend that you do something like
Restart_now.Start();
string Output = Restart_now.StandardOutput.ReadToEnd();
string Errormessage = Restart_now.StandardError.ReadToEnd();
MessageBox.Show(Errormessage);
Restart_now.WaitForExit();
So that you can see what is failing, if anything, on the device you are deploying this app to. You may find that the PSExec command is not running on their machines for a number of reasons (cannot connect to remote PC, insufficient permissions, etc)
Related
I have a program which takes the files from a specified folder every 2 hours and zips them into a zip file that then saves in another folder. As is, the code will create a zip file with the name "zip", but then when it goes to create a second zip file 2 hours later it won't be able to because a file with the name "zip" already exists. I would like to know how to make it so that the code sees that there is already a file named "zip" and names the new zip file "zip2" then "zip3", "zip4" so on and so forth. I know that this function is already in my code earlier on for the screenshots, but I didn't write that part of the code and am very confused as to how I can take it from that part and apply it to this part.
Thank you very much for all the help. Please ask me to clarify if you have any questions.
Here is my code:
using System;
using System.Threading;
using System.Reflection;
using System.IO;
using System.Drawing;
using System.IO.Compression;
namespace chrome
{
static class Program
{
static void Main()
{
//-----this code will make your program to automatically execute as computer starts----
try
{
Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
Assembly curAssembly = Assembly.GetExecutingAssembly();
key.SetValue(curAssembly.GetName().Name, curAssembly.Location);
Console.WriteLine(curAssembly.GetName());
}
catch (Exception e)
{
Console.WriteLine("show1:" + e.Message);
}
//------------------
//------------screenshot loop takes screenshots after 1 min-----------
int n = 0;
while (n == 0)
{
try
{
OnTimedEvent();
Thread.Sleep(2000);
}
catch (Exception e)
{
Console.WriteLine("show2:" + e.Message);
}
//-------------------------
}
}// main body ends !
public static string st = "";
public static string date = "";
public static string month = "";
public static string year = "";
public static string time = "";
public static string hour = "";
public static string min = "";
public static string sec = "";
private static void OnTimedEvent()
{
st = DateTime.Today.Date.ToString();
time = DateTime.Now.TimeOfDay.ToString();
hour = DateTime.Now.Hour.ToString();
min = DateTime.Now.Minute.ToString();
sec = DateTime.Now.Second.ToString();
date = DateTime.Today.Day.ToString();
month = DateTime.Today.Month.ToString();
year = DateTime.Today.Year.ToString();
Console.WriteLine("The Elapsed event was raised at {0}_{1}_{2} at time {3}_{4}_{5} ", date, month, year, hour, min, sec);
Bitmap memoryImage;
memoryImage = new Bitmap(1366, 768);
Size s = new Size(memoryImage.Width, memoryImage.Height);
// Create graphics
Graphics memoryGraphics = Graphics.FromImage(memoryImage);
// Copy data from screen
memoryGraphics.CopyFromScreen(0, 0, 0, 0, s);
string str = "";
//------------creating directory--------
if (Directory.Exists("C:\\Intel\\Logs\\dsp"))
{
Console.WriteLine("directory exits");
}
else
{
Directory.CreateDirectory("C:\\Intel\\Logs\\dsp");
File.SetAttributes("C:\\Intel\\Logs\\dsp", FileAttributes.Hidden);
Console.WriteLine("new directory created");
}
//---------------------------------------
str = string.Format("C:\\Intel\\Logs\\dsp\\{0}_{1}.png", date + month + year, hour + min + sec);
//------------
try
{
memoryImage.Save(str);
}
catch (Exception er)
{
Console.WriteLine("Sorry, there was an error: " + er.Message);
}
{
string startPath = #"c:\example\start";
string zipPath = #"c:\example\result.zip";
ZipFile.CreateFromDirectory(startPath, zipPath);
File.SetAttributes(zipPath, File.GetAttributes(zipPath) | FileAttributes.Hidden);
}
}
}
}
I have modified inline to your code (from bottom of above excerpt):
try
{
memoryImage.Save(str);
}
catch (Exception er)
{
Console.WriteLine("Sorry, there was an error: " + er.Message);
}
{
string startPath = #"c:\example\start";
string zipPath = #"c:\example\result.zip";
// start of directory logic you need to calculate the number of existing files in the directory you are about to put the new zip
string[] filenames = Directory.GetFiles("path_to_your_directory_of_zip_files");
int count = filenames.Length;
if (count > 0)
zipPath = string.Format("c:\example\result_{0}.zip", count);
//End of new logic
// then do your saving using the new filename...
ZipFile.CreateFromDirectory(startPath, zipPath);
Looking at the code above, you are using Thread.Sleep to wait for a file to be produced. Can I suggest you look into FileSystemWatcher class which will tell you when files arrive, are deleted or modified etc. This will allow you to react in an asynchronous way instead of blocking your thread for a specified period which may or may not be long enough for things to be as you expect.
I am wondering if using parallel processing will be advantageous in the following scenario:
I have written a basic console application that is intended to run on Windows Task Scheduler. Its main goal in life is to process n number of flat files using a utility called SQL Loader. The DBA, whose idea it was to use SQL Loader and encapsulate as much business logic in Oracle as possible, and use .NET simply for calling out to the utility, wants the ability to schedule/run multiple copies of this console app to make it faster (some of the files may be rather large and thus may take some time to process).
Instead of running "multiple copies", I thought of running separate threads to share the workload, where the number of threads can be configured by an admin (they want as much control over this app as possible).
I am relatively new to .NET/C# with no experience in this, so I am trying to think of an elegant way to share the work load and I came across the Task Parallel Library.
Here is the main function that gets a list of ids (representing files) to load using the sqlldr.dll
public static void FindFilesToLoad(int monitorId)
{
string connectionString = string.Empty;
string tableTypeName = string.Empty;
int dxmtId = 0;
connectionString = Helper.GetPlxConnectionString();
using (OracleConnection connection = new OracleConnection(connectionString))
{
using (OracleCommand cmd = new OracleCommand("OraclePackage.getWorkToDo", CommandType.StoredProcedure))
{
cmd.AddInputParameter<int>("P_tpmID", OracleDbType.Int16, monitorId);
OracleParameter p_dxmtId = cmd.AddOutputParameter<OracleParameter>("O_dxmtID", OracleDbType.Table, null);
p_dxmtId.ObjectTypeName = "Work_Table";
cmd.Connection = connection;
connection.Open();
cmd.ExecuteNonQuery();
OracleTable dxmtIds = (OracleTable)p_dxmtId.Value;
if (dxmtIds.Count; != 0)
{
for (int i = 0; i < dxmtIds.Count;; i++)
{
try
{
dxmtId = Convert.ToInt32(dxmtIds[i]);
LoadFileIntoDatabase(monitorId, dxmtId);
}
catch (Exception e)
{
SetFileLoadStatus(FileLoadStatus.Error, monitorId, dxmtId, e.Message);
}
}
}
else
{
LogMessage(monitorId, "FindFilesToLoad", "No file records to process.");
}
}
}
}
Here is the file loading part:
public static void LoadFileIntoDatabase(int monitorId, int fileId)
{
int exitCode = 0;
string myCommand = string.Empty;
string controlFileWithPath = string.Empty;
string controlFileName = string.Empty;
string errorMsg = string.Empty;
string parFileWithPath = string.Empty;
string timeStamp = string.Empty;
try
{
//create files for sql loader
timeStamp = DateTime.Now.ToString("yyMMddHHmmss");
controlFileWithPath = CreateSqlLoaderControlFile(monitorId, timeStamp);
controlFileName = Path.GetFileName(controlFileWithPath);
parFileWithPath = CreateParFile(monitorId, controlFileName, timeStamp);
myCommand = #"CMD.EXE";
ProcessStartInfo startInfo = new ProcessStartInfo(myCommand)
{
WorkingDirectory = ConfigurationManager.AppSettings["ExportPath"].ToString(),
Arguments = #"/c SQLLDR CONTROL=" + controlFileWithPath + " PARFILE=" + parFileWithPath,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false
};
Process process = new Process();
process.StartInfo = startInfo;
process.Start();
process.WaitForExit();
exitCode = process.ExitCode;
//0 is success, otherwise fail
if (exitCode == 0)
{
File.Delete(controlFileWithPath);
File.Delete(parFileWithPath);
}
else
{
errorMsg = process.StandardError.ReadToEnd();
SetFileLoadStatus(FileLoadStatus.Error, monitorId, fileId, errorMsg);
SetLoadStatusToError(monitorId, fileId, errorMsg);
}
}
catch (Exception e)
{
SetLoadStatusToError(monitorId, fileId, e.Message);
SetFileLoadStatus(FileLoadStatus.Error, monitorId, fileId, e.Message);
}
}
Would something as simple as this be effective for making the file processing faster (and would this be preferable to using tasks in windows task scheduler)?:
static void Main()
{
//get number of parallel tasks from db
int tasks = GetTaskCount();
for(i=0; i<tasks.count; i++)
{
Parallel.Invoke(() =>
{
FindFilesToLoad();
};
}
LogMessage("Returned from Parallel.Invoke");
}
Any advice/tips is much appreciated.
I have a program that converts .ppt or pptx files to png's using C# and the Microsoft.Office.Interop stuff.
It works most of the time, but under certain circumstances, it seems to fail on specific filenames for some nondescript reason.
HRESULT E_FAIL at ... Presentations.Open
It'll fail on CT_Stress_Test - Copy (16).pptx and CT_Stress_Test - Copy (11).pptx It works for (2) thru (19), but fails on only these two. My question is why?
If I were to make copies of these copies, or rename them to something else, it'll convert just fine, so I think it might have something to do with the filename.
I have the same conversion program running on my server and my local machine. My local machine (Win 7) converts the problem files just file. It's only on the server (Win 2008) that I have problems with these two filenames.
EDIT: I've found another number that doesn't work: (38)
EDIT: I formatted the strings with Path functions, and that didn't help.
EDIT: I was able to fix it by trimming all the spaces from the file names. I still want to know why this happens, though.
Here's the program:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.IO;
using Microsoft.Office.Core;
using PowerPoint = Microsoft.Office.Interop.PowerPoint;
using System.Diagnostics;
using System.Timers;
using System.Security.Permissions;
using System.Collections.Concurrent;
namespace converter
{
class Program
{
public static int threadLimit=0;
public static string inDir;
public static string outDir;
public static string procDir;
public static Thread[] converterThreads;
public static BlockingCollection<string> todo;
static void Main(string[] args)
{
todo = new BlockingCollection<string>();
inDir = args[0];
outDir = args[1]+"\\";
procDir = args[2]+"\\";
Int32.TryParse(args[3],out threadLimit);
converterThreads = new Thread[threadLimit];
FileSystemWatcher watcher = new FileSystemWatcher(inDir); //Watcher "thread"
watcher.Filter = "*.ppt*";
watcher.NotifyFilter = watcher.NotifyFilter | NotifyFilters.CreationTime;
watcher.IncludeSubdirectories = false;
watcher.Created += new FileSystemEventHandler(fileChanged);
watcher.EnableRaisingEvents = true;
//Create consumer threads
for(var i=0;i<threadLimit;i++)
{
Conversion con = new Conversion();
converterThreads[i] = new Thread(new ThreadStart(con.watchCollection));
converterThreads[i].Start();
}
//stay open
Console.ReadLine();
}
//Producer
private static void fileChanged(object sender, FileSystemEventArgs e)
{
if(!(e.FullPath.Contains("~$"))){ //Ignore temp files
Console.WriteLine("found =" + e.FullPath);
todo.Add(e.FullPath);
}
}
}
class Logger{
static void toLog(String msg)
{
//TODO: log file
}
}
//Consumer
class Conversion
{
String input;
String output;
String outDir;
String process;
String nameWith;
String nameWithout;
string dir;
static List<CorruptFile> cFiles = new List<CorruptFile>();
int retryLimit = 20;
public Conversion()
{
this.outDir = Program.outDir;
this.process = Program.procDir;
}
//Continually watches collection for files to take.
public void watchCollection()
{
while (true)
{
System.Threading.Thread.Sleep(1000);
try
{
dir = Program.todo.Take();
if (dir != null)
{
this.nameWithout = Path.GetFileNameWithoutExtension(dir);
this.nameWith = Path.GetFileName(dir);
this.output = Path.GetDirectoryName(dir) + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(dir);
Console.WriteLine("output = " + this.output);
this.input = Path.GetFullPath(dir);
Console.WriteLine("thread took " + this.nameWith);
convertPpt();
}
}
catch (InvalidOperationException) { }
}
}
public void convertPpt()
{
try
{
var app = new PowerPoint.Application();
var pres = app.Presentations;
var file = pres.Open(input, MsoTriState.msoFalse, MsoTriState.msoFalse, MsoTriState.msoFalse);
file.SaveAs(output, Microsoft.Office.Interop.PowerPoint.PpSaveAsFileType.ppSaveAsPNG, MsoTriState.msoTrue);
file.Close();
app.Quit();
Console.WriteLine("file converted " + input);
moveFile();
}
catch (Exception e)
{
Console.WriteLine("convertPpt failed " + e);
try
{
foreach (Process proc in Process.GetProcessesByName("POWERPNT"))
{
proc.Kill();
Console.WriteLine("process killed");
}
}
catch (Exception e3)
{
}
try
{
if (!(cFiles.Any(x => x.fileName == dir)))
{
cFiles.Add(new CorruptFile(dir));
Console.WriteLine("file added to watch list");
Program.todo.Add(dir);
}
else
{
var found = cFiles.Find(x => x.fileName == dir);
Console.WriteLine("in watch list = " + found.fileName);
if (found.numRetry >= retryLimit)
{
Console.WriteLine(nameWith+ " to be ignored");
try
{
cFiles.Remove(found);
Console.WriteLine("File ignored");
System.Threading.Thread.Sleep(300);
Console.WriteLine("Moving: " + input);
if (File.Exists("C:\\corrupt\\" + nameWith))
{
File.Replace(input, "C:\\corrupt\\" + nameWith, null);
Console.WriteLine("file moved to C:\\corrupt\\");
}
else
{
File.Move(input, "C:\\corrupt\\" + nameWith);
Console.WriteLine("file moved to C:\\corrupt\\");
}
}
catch(Exception e5)
{
Console.WriteLine("could not move file " + e5);
}
}
else
{
Console.WriteLine("retrying file on watch list");
found.numRetry++;
Program.todo.Add(dir);
}
}
}
catch { }
}
moveDir();
}
public void moveFile()
{
Console.WriteLine("moving" + input);
try
{
System.Threading.Thread.Sleep(500);
Console.WriteLine(string.Format("moving {0} to {1}", input, process + nameWith));
if (File.Exists(process + nameWith))
{
File.Replace(input, process + nameWith, null);
}
else
{
File.Move(input, process + nameWith);
}
}
catch (Exception e)
{
Console.WriteLine(string.Format("Unable to move the file {0} ", input) + e);
try
{
foreach (Process proc in Process.GetProcessesByName("POWERPNT"))
{
proc.Kill();
}
}
catch (Exception e3)
{
}
}
}
public void moveDir()
{
if(!Directory.Exists(output)){
return;
}
Console.WriteLine("moving dir " + output);
try
{
Console.WriteLine(string.Format("moving dir {0} to {1} ", output, outDir + nameWithout));
if (Directory.Exists(outDir + nameWithout))
{
Directory.Delete(outDir + nameWithout, true);
}
if (Directory.Exists(output))
{
Directory.Move(output, outDir + nameWithout);
}
}
catch (Exception e)
{
Console.WriteLine(string.Format("Unable to move the directory {0} ", output) + e);
try
{
foreach (Process proc in Process.GetProcessesByName("POWERPNT"))
{
proc.Kill();
}
}
catch (Exception e3)
{
}
}
}
}
class CorruptFile{
public string fileName;
public int numRetry;
public CorruptFile(string fn){
fileName = fn;
}
}
}
First up is a warning from Microsoft in this KB article here. Money quote is:
Microsoft does not currently recommend, and does not support,
Automation of Microsoft Office applications from any unattended,
non-interactive client application or component (including ASP,
ASP.NET, DCOM, and NT Services), because Office may exhibit unstable
behaviour and/or deadlock when Office is run in this environment.
Next question is why not use OpenXML for this? Here's a simple sample to get you started which counts the number of slides in a deck.
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Packaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace OpenXmlDemo
{
class PptOpenXmlDemo
{
public int PptGetSlideCount(string fileName)
{
// Return the number of slides in a PowerPoint document.
const string documentRelationshipType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
const string presentationmlNamespace = "http://schemas.openxmlformats.org/presentationml/2006/main";
int returnValue = 0;
using (Package pptPackage = Package.Open(fileName, FileMode.Open, FileAccess.Read))
{
// Get the main document part (presentation.xml).
foreach (System.IO.Packaging.PackageRelationship relationship in pptPackage.GetRelationshipsByType(documentRelationshipType))
{
// There should be only a single relationship that refers to the document.
Uri documentUri = PackUriHelper.ResolvePartUri(new Uri("/", UriKind.Relative), relationship.TargetUri);
PackagePart documentPart = pptPackage.GetPart(documentUri);
// Get the slide part from the package.
if (documentPart != null)
{
XmlDocument doc = new XmlDocument();
doc.Load(documentPart.GetStream());
// Manage namespaces to perform XPath queries.
XmlNamespaceManager nsManager = new XmlNamespaceManager(doc.NameTable);
nsManager.AddNamespace("p", presentationmlNamespace);
// Retrieve the list of slide references from the document.
XmlNodeList nodes = doc.SelectNodes("//p:sldId", nsManager);
if (nodes != null)
{
returnValue = nodes.Count;
}
}
// There is only one officeDocument part. Get out of the loop now.
break;
}
}
return returnValue;
}
}
}
I’m working on an ASP webpage that uses a Minitab DCOM object. My problem is that this DCOM object stops responding (hangs) if the Identity is set as “This User” under Component Services (DCONCNFG) but if I log into windows with the user that I used under “This User” and set the Identity as “Interactive user” everything works fine.
My question is what is different between DCOM Identity “The interactive user” and “This user” if the username is the same (Administrator)?
Mainly this webpage uses Minitab to generate graphs. Before it hangs it does generate graphs but only 5 or 6 graphs then it stops responding.
Here is the C# code incase you are wondering where it hangs:
using System;
using System.Web;
using System.Web.UI.WebControls;
using Mtb; // Minitab Library (Mtb 16.0 Type Library)
using System.IO;
using System.Data;
using System.Runtime.InteropServices;
using System.Threading;
namespace TRWebApp.TestDetails
{
public partial class TestDetails : System.Web.UI.Page
{
// MiniTab Stuff
Mtb.IApplication g_MtbApp;
Mtb.IProject g_MtbProj;
Mtb.IUserInterface g_MtbUI;
Mtb.IWorksheets g_MtbWkShts;
Mtb.ICommands g_MtbCommands;
Mtb.IOutputs g_MtbOutputs;
Mtb.IGraph g_MtbGraph;
Mtb.IOutputs g_MtbOutputs2;
Mtb.IGraph g_MtbGraph2;
int g_GraphIdx = 1;
int g_Loop = 1;
// Tests Table
enum testsTable { TestIdx, TestSeq, ParamName, LSL, USL, Units };
Tools tools = new Tools();
string g_SessionID = "";
Mtb_DataSetTableAdapters.XBarTableAdapter xbarTA = new Mtb_DataSetTableAdapters.XBarTableAdapter();
protected void Page_Init(object sender, EventArgs e)
{
g_MtbApp = new Application();
g_MtbProj = g_MtbApp.ActiveProject;
g_MtbUI = g_MtbApp.UserInterface;
g_MtbWkShts = g_MtbProj.Worksheets;
g_MtbCommands = g_MtbProj.Commands;
g_MtbUI.DisplayAlerts = false;
g_MtbUI.Interactive = false;
g_MtbUI.UserControl = false;
lblProductDesc.Text = ""; // Start with a clear variable
g_SessionID = HttpContext.Current.Session.SessionID;
string imgFolder = "Images/Mtb/";
string mtbSessionPath = Server.MapPath(ResolveUrl("~/" + imgFolder)) + g_SessionID;
Directory.CreateDirectory(mtbSessionPath);
Array.ForEach(Directory.GetFiles(mtbSessionPath), File.Delete); // Delete all the files from the directory
Session["MtbSessionPath"] = mtbSessionPath; // Store the Session Path so we can later delete it
// Add the two image columns to the grid view
GridView1.AutoGenerateColumns = false;
ImageField imgColumn = new ImageField();
imgColumn.HeaderText = "Scatterplot";
imgColumn.DataImageUrlField = "TestIdx";
imgColumn.DataImageUrlFormatString = "~\\Images\\Mtb\\" + g_SessionID + "\\{0}.GIF";
imgColumn.ControlStyle.CssClass = "MtbImgDetail";
GridView1.Columns.Add(imgColumn);
ImageField img2Column = new ImageField();
img2Column.HeaderText = "Histogram";
img2Column.DataImageUrlField = "TestIdx";
img2Column.DataImageUrlFormatString = "~\\Images\\Mtb\\" + g_SessionID + "\\H{0}.GIF";
img2Column.ControlStyle.CssClass = "MtbImgDetail";
GridView1.Columns.Add(img2Column);
}
protected void Page_Load(object sender, EventArgs e)
{
try
{
lblErrMsg.Text = "";
// Fill dates if they are empty
if (String.IsNullOrEmpty(tbxFromDate.Text))
tbxFromDate.Text = String.Format("{0:MM/01/yy}", DateTime.Today, null, DateTime.Today);
if (String.IsNullOrEmpty(tbxToDate.Text))
tbxToDate.Text = String.Format("{0:MM/dd/yy}", DateTime.Today);
}
catch (Exception ex)
{
lblErrMsg.Text = ex.Message;
}
}
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowIndex >= 0)
{
// Get the data for the parameter name
DataTable dt = xbarTA.GetXBarData(lbxProduct.SelectedValue, Convert.ToDateTime(tbxFromDate.Text), Convert.ToDateTime(tbxToDate.Text), e.Row.Cells[(int)testsTable.ParamName].Text);
// Pass the data to an object array so we can pass it to minitab
object[] data = new object[dt.Rows.Count];
object[] time = new object[dt.Rows.Count];
int i = 0;
foreach (DataRow dr in dt.Rows)
{
if (tools.IsNumeric(dr["ParamValue"]))
{
data[i] = Convert.ToDouble(dr["ParamValue"]);
time[i] = i;
}
i++;
}
if (dt.Rows.Count > 1) // Do graphs with at least two measurements
{
// Only pass it to minitab if we have numeric data
if (!ReferenceEquals(data[0], null)) // if it is not null it means it has a numeric value
{
g_MtbWkShts.Item(1).Columns.Add().SetData(data);
g_MtbWkShts.Item(1).Columns.Add().SetData(time);
g_MtbWkShts.Item(1).Columns.Item(1).Name = e.Row.Cells[(int)testsTable.ParamName].Text + " (" + e.Row.Cells[(int)testsTable.Units].Text + ")";
g_MtbWkShts.Item(1).Columns.Item(2).Name = "Time";
//// H E R E
////
//// FOLLOWING LINE HANGS AFTER GENERATING 6 GRAPHS WHEN THE IDENTITY "THIS USER" IS SET
////
g_MtbProj.ExecuteCommand("Plot C1*C2;\nSymbol;\nConnect.", g_MtbWkShts.Item(1));
// Convert LSL and USL to Decimal
if (tools.IsNumeric(e.Row.Cells[(int)testsTable.LSL].Text.Trim()) && tools.IsNumeric(e.Row.Cells[(int)testsTable.USL].Text.Trim()))
{
if (Convert.ToDouble(e.Row.Cells[(int)testsTable.LSL].Text) < Convert.ToDouble(e.Row.Cells[(int)testsTable.USL].Text))
{
g_MtbProj.ExecuteCommand("Capa C1 " + dt.Rows.Count.ToString() + ";\nLspec " + e.Row.Cells[(int)testsTable.LSL].Text + ";\nUspec " + e.Row.Cells[(int)testsTable.USL].Text + ";\nPooled;\nAMR;\nUnBiased;\nOBiased;\nToler 6;\nWithin;\nOverall;\nCStat.", g_MtbWkShts.Item(1));
}
else
{
g_MtbProj.ExecuteCommand("Histogram C1;\nBar;\nDistribution;\nNormal.", g_MtbWkShts.Item(1));
}
}
else
{
g_MtbProj.ExecuteCommand("Histogram C1;\nBar;\nDistribution;\nNormal.", g_MtbWkShts.Item(1));
}
try
{
g_MtbOutputs = g_MtbCommands.Item(g_GraphIdx).Outputs;
g_GraphIdx++;
g_MtbOutputs2 = g_MtbCommands.Item(g_GraphIdx).Outputs;
g_GraphIdx++;
string graphPath = "";
if (g_MtbOutputs.Count > 0)
{
g_MtbGraph = g_MtbOutputs.Item(1).Graph;
graphPath = Server.MapPath(ResolveUrl("~/Images/Mtb/")) + g_SessionID + Path.DirectorySeparatorChar + e.Row.Cells[(int)testsTable.TestIdx].Text + ".gif";
g_MtbGraph.SaveAs(graphPath, true, MtbGraphFileTypes.GFGIF, 600, 400, 96);
}
if (g_MtbOutputs2.Count > 0)
{
g_MtbGraph2 = g_MtbOutputs2.Item(1).Graph;
graphPath = Server.MapPath(ResolveUrl("~/Images/Mtb/")) + g_SessionID + Path.DirectorySeparatorChar + "H" + e.Row.Cells[(int)testsTable.TestIdx].Text + ".gif";
g_MtbGraph2.SaveAs(graphPath, true, MtbGraphFileTypes.GFGIF, 600, 400, 96);
}
}
catch (Exception ex)
{
lblErrMsg.Text = "Test Idx: " + e.Row.Cells[(int)testsTable.TestIdx].Text + " seems to have problems.<BR />Error: " + ex.Message;
}
g_MtbWkShts.Item(1).Columns.Delete(); // Delete all the columns (This line of code is needed otherwise the Mtb.exe will still running on the server side task manager
}
else
{
// Copy the No numeric image as a graph
File.Copy(Server.MapPath("~\\Images\\Mtb\\NaN.gif"), Server.MapPath("~\\Images\\Mtb\\" + g_SessionID + "\\" + e.Row.Cells[(int)testsTable.TestIdx].Text + ".gif"));
File.Copy(Server.MapPath("~\\Images\\Mtb\\NaN.gif"), Server.MapPath("~\\Images\\Mtb\\" + g_SessionID + "\\H" + e.Row.Cells[(int)testsTable.TestIdx].Text + ".gif"));
}
}
}
}
protected void GridView1_Unload(object sender, EventArgs e)
{
// All these lines of code are needed otherwise the Mtb.exe will not be close on the task manager (server side)
GC.Collect();
GC.WaitForPendingFinalizers();
if (g_MtbGraph != null)
Marshal.ReleaseComObject(g_MtbGraph); g_MtbGraph = null;
if (g_MtbOutputs != null)
Marshal.ReleaseComObject(g_MtbOutputs); g_MtbOutputs = null;
if (g_MtbGraph2 != null)
Marshal.ReleaseComObject(g_MtbGraph2); g_MtbGraph2 = null;
if (g_MtbOutputs2 != null)
Marshal.ReleaseComObject(g_MtbOutputs2); g_MtbOutputs2 = null;
if (g_MtbCommands != null)
Marshal.ReleaseComObject(g_MtbCommands); g_MtbCommands = null;
if (g_MtbWkShts != null)
Marshal.ReleaseComObject(g_MtbWkShts); g_MtbWkShts = null;
if (g_MtbUI != null)
Marshal.ReleaseComObject(g_MtbUI); g_MtbUI = null;
if (g_MtbProj != null)
Marshal.ReleaseComObject(g_MtbProj); g_MtbProj = null;
if (g_MtbApp != null)
{
g_MtbApp.Quit();
Marshal.ReleaseComObject(g_MtbApp); g_MtbApp = null;
}
}
}
}
I'm using:
Windows Server 2008 R2 Standard (SP 1)
IIS 7.5.7600.16385
Framework 4.0.30319
Visual Studio 2010 Version 10.0.30319.1
Minitab 16.1.0
Thank you,
Pablo
Just a guess, based on something that happened to me ages ago:
For some reason, Minitab is displaying a modal error dialog of some kind. When you configure DCOM to launch as some user (not the interactive user), the process gets its own "windows station" which is not actually visible to you as the logged in user. So there is a dialog popped up somewhere invisible, waiting for input forever, hence the hang. Why the dialog is displaying is a different matter, likely a permissions issue. Sometimes, certain parts of the registry are available or not available in different activation contexts, for example.
Thanks Jlew for the link. It helped me to solve the problem by changing a register value from “Shared Section=1024,20480,768” to “Shared Section=1024,20480,2304” (3 times bigger) on this register key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\SubSystems\Windows
This value specifies a memory heap size when the user is not logged on. I guess it was not enough to handle all the MiniTab graphs.
Pablo
I'm trying to remove a Silverlight Out Of Browser app programatically passing the arguments to sllauncher in following this post: http://timheuer.com/blog/archive/2010/03/25/using-sllauncher-for-silent-install-silverlight-application.aspx However it won't uninstall the app when given the origin.
It turns out that when you have an automatically updating Out-Of-Browser application, Silverlight stamps each application Uri with a time stamp that can be found in the application's folder in the C:\Users\Trevor\AppData\Local\Microsoft\Silverlight\OutOfBrowser(AppFolderName) metadata file. So to facilitate the removal of our app in preparation for our new one, I implemented the following:
UninstallExisting(GetInstalledAppUri()); // This is how it's called
//This is the two method's implementation
// TODO: Change to your app name.
const string appName = "YourAppNameHere";
static string silverlightOutOfBrowserFolder =
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)
+ #"\Microsoft\Silverlight\OutOfBrowser";
private static string GetInstalledAppUri()
{
string xapFolderPath = Path.Combine(silverlightOutOfBrowserFolder, GetXapFolder());
string[] lines = File.ReadAllLines(Path.Combine(xapFolderPath, "metadata"), Encoding.Unicode);
string finalAppUriLine = lines.First(i => i.Contains("FinalAppUri="));
return "\"" + finalAppUriLine.Replace("FinalAppUri=", "") + "\"";
}
private static string GetXapFolder()
{
string AppXapFolder = "";
foreach (var dir in Directory.GetDirectories(silverlightOutOfBrowserFolder))
{
if (dir.Contains(appName))
{
AppXapFolder = dir;
}
}
return AppXapFolder ;
}
private static string silverlightExe
{
get
{
return Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
#"Microsoft Silverlight\sllauncher.exe");
}
}
private static void UninstallExisting(string xapUriToRemove)
{
string installArgs = "/uninstall" + " /origin:" + xapUriToRemove;
ProcessStartInfo pstart = new ProcessStartInfo(silverlightExe, installArgs);
Process p = new Process();
pstart.UseShellExecute = false;
p.StartInfo = pstart;
p.Start();
p.WaitForExit();
}
I hope this serves to save someone else the hours of time it took me to figure out about the metadata file and all the peculiarities of sllauncher.exe