Calling Console Application (.exe) in Event Receiver and Getting Error - sharepoint

I am using SharePoint foundation. I have a console application that is used to run some OCR process. I am calling the exe of the console application from windows service and it is working fine. I am trying to call the same exe from an event receiver but unable to call the exe and getting some error. The Event receiver is working fine but unable to call exe. I have tried to call the other exes like notepad.exe but getting same error. The details are below:
Code:
public override void ItemAdded(SPItemEventProperties properties)
{
try
{
base.ItemAdded(properties);
Log("Event Occured.");
string OCRedText = string.Empty;
string Listname = properties.ListTitle;
string itemName = Convert.ToString(properties.ListItem["Name"]);
string itemTitle = Convert.ToString(properties.ListItem["Title"]);
callService(); // Here is the method to call Process
SPListItem item = properties.ListItem;
if (System.Threading.Monitor.TryEnter(myLock, TimeSpan.FromSeconds(100)))
{
if (Convert.ToString(item["OCRed"]) == "False")
{
item["OCRed"] = "True";
Thread.Sleep(10000);
item.SystemUpdate();
Log("Item Added and Updated.");
}
else
{
Log("Can not update the Item.");
}
}
Log("Event End."+"\r\n");
}
catch (Exception ex)
{
Log("Error in Item Added Event Receiver.");
Log(ex.ToString());
}
}
public void callService()
{
Log("Calling Service is not easy.");
try
{
ProcessStartInfo pinfoService = new ProcessStartInfo();
pinfoService.FileName = #"D:\Khan\khan.exe";
//pinfoService.FileName = #"C:\Windows\System32\notepad.exe";
pinfoService.UseShellExecute = false;
pinfoService.RedirectStandardError = true;
pinfoService.RedirectStandardInput = true;
pinfoService.RedirectStandardOutput = true;
pinfoService.CreateNoWindow = true;
pinfoService.WindowStyle = ProcessWindowStyle.Hidden;
Log("FileName: " + pinfoService.FileName);
Log("Arguments for callService : "+pinfoService.Arguments);
Process pService = new Process();
pService.StartInfo = pinfoService;
Log("Process Before Start.");
Thread.Sleep(5000);
pService.Start();
Thread.Sleep(2000);
Log("Process Before wait for exit.");
pService.WaitForExit();
Log("Process Completed.");
}
catch (Exception ex)
{
Log("Error in callService(). Please contact your Administrator.");
Log(ex.ToString());
}
}
and below is the error I am getting on pService.Start();
=========================================
Info : Process Before Start.
Info : Error in callService(). Please contact your Administrator.
Info : System.ComponentModel.Win32Exception: Not enough quota is available to process this command
at System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo)
at OCRonUploadDoc.EventReceiver1.EventReceiver1.callService()
=========================================
I am unable to figure out the issue. Please help me...!!!
Thanks in Advance.
Khan Abubakar

I think that the asp.net account under which the application pool runs does not have permissions to start the exe file. You can check this out http://www.daniweb.com/web-development/aspnet/threads/386380/cannot-run-exe-files-in-asp.net-application
However if your system will be used by more users you can run into problems really quickly, because every change of a document will spawn a new process. The server will run out of ram and the farm will not be unavailable.

Related

Is it possable to call a method that takes this.Handle as an argument inside a background worker in C#

I am working on a stand-alone WinForm program in C# that uses the Solidworks EPDM api. The program takes a top level assembly and finds all the referenced and referencing files in the assembly. e.g. all sub-assemblies, part files, and drawings. The program then checks out all the files from EPDM, updates the data cards, and checks in all the files back to the EPDM.
I have successfully implemented the portion of the code that finds all the referenced and referencing files and updates the data card information using a background worker. This portion of the code does not require access the the UI thread. I would like to be able to add the code that checks out the files and checks them back in within a background worker. The problem is that the methods used to do the checkout and check-in take this.Handle as an argument. I know that accessing the UI thread from within a background worker will throw a cross thread exception. The code does not access any of the UI controls. It only need access to this.Handle. Is it possible to pass this.Handle to a background worker in a thread safe way that will not throw a cross thread exception?
This is my first use of background workers so my knowledge is limited. Below is the code that I would like to run in a background worker.
private void BatchCheckout(Dictionary<string, string> SelectedFiles)
{
try
{
IEdmBatchGet batchGetter = (IEdmBatchGet)vault.CreateUtility(EdmUtility.EdmUtil_BatchGet);
EdmSelItem[] ppoSelection = new EdmSelItem[SelectedFiles.Count];
IEdmFile5 aFile;
IEdmFolder5 aFolder;
IEdmFolder5 ppoRetParentFolder;
IEdmPos5 aPos;
int i = 0;
foreach (KeyValuePair<string, string> kvp in SelectedFiles)
{
aFile = vault1.GetFileFromPath(kvp.Key, out ppoRetParentFolder);
aPos = aFile.GetFirstFolderPosition();
aFolder = aFile.GetNextFolder(aPos);
ppoSelection[i] = new EdmSelItem();
ppoSelection[i].mlDocID = aFile.ID;
ppoSelection[i].mlProjID = aFolder.ID;
i = i + 1;
}
batchGetter.AddSelection((EdmVault5)vault1, ref ppoSelection);
batchGetter.CreateTree(this.Handle.ToInt32(), (int)EdmGetCmdFlags.Egcf_Lock);
batchGetter.GetFiles(this.Handle.ToInt32(), null);
}
catch (System.Runtime.InteropServices.COMException ex)
{
MessageBox.Show("HRESULT = 0x" + ex.ErrorCode.ToString("X") + " " + ex.Message);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "\n" + GetStackTrace(ex));
}
}
I have been a reader of StackOverflow for many years and have found answers to just about every question I have ever had. This is my first ever question on StackOverflow. I am really hoping that someone will have an answer to this problem.
EDIT:
I have successfully test AndrewK's suggestion and am happy to report that it did work for my batch checkout method. When I run my batch check-in method in a background worker I'm getting the following COM exception:
Unable to cast COM object of type 'System.__ComObject' to interface type 'EPDM.Interop.epdm.IEdmBatchUnlock2'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{F0970446-4CBB-4F0F-BAF5-F9CD2E09A5B3}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).
I only get this exception if I run the code from a background worker.
Here is the code from my BatchCheckin method:
private void BatchCheckin(Dictionary<string, string> SelectedFiles)
{
try
{
int i = 0;
IEdmFolder5 ppoRetParentFolder;
IEdmFile5 aFile;
IEdmFolder5 aFolder;
IEdmPos5 aPos;
EdmSelItem[] ppoSelection = new EdmSelItem[SelectedFiles.Count];
IEdmBatchUnlock2 batchUnlock;
foreach (KeyValuePair<string, string> kvp in SelectedFiles)
{
aFile = vault5.GetFileFromPath(kvp.Key, out ppoRetParentFolder);
aPos = aFile.GetFirstFolderPosition();
aFolder = aFile.GetNextFolder(aPos);
ppoSelection[i] = new EdmSelItem();
ppoSelection[i].mlDocID = aFile.ID;
ppoSelection[i].mlProjID = aFolder.ID;
i = i + 1;
}
batchUnlock = (IEdmBatchUnlock2)vault7.CreateUtility(EdmUtility.EdmUtil_BatchUnlock);
batchUnlock.AddSelection((EdmVault5)vault5, ref ppoSelection);
batchUnlock.CreateTree(0, (int)EdmUnlockBuildTreeFlags.Eubtf_ShowCloseAfterCheckinOption + (int)EdmUnlockBuildTreeFlags.Eubtf_MayUnlock);
batchUnlock.Comment = "Updates";
batchUnlock.UnlockFiles(0, null);
}
catch (System.Runtime.InteropServices.COMException ex)
{
MessageBox.Show("HRESULT = 0x" + ex.ErrorCode.ToString("X") + " " + ex.Message);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "\n" + GetStackTrace(ex));
}
}
I am getting the exception when I make the call to vault7.CreateUtility. The BatchCheckin code is nearly identical to the BatchCheckout. I'm making the same call to vault7.CreateUtility in both methods. The only difference is the EdmUtility flag is set to EdmUtil_BatchUnlock in the BatchCheckin method. Any clue on this one AndrewK?
UPDATE:
I was able to resolve the COM exception by changing batchUpdate from the IEdmBatchUnlock2 interface to the IEdmBatchUnlock interface. Here is the code change:
private void BatchCheckin(Dictionary<string, string> SelectedFiles)
{
int i = 0;
IEdmFolder5 ppoRetParentFolder;
IEdmFile5 aFile;
IEdmFolder5 aFolder;
IEdmPos5 aPos;
EdmSelItem[] ppoSelection = new EdmSelItem[SelectedFiles.Count];
IEdmBatchUnlock batchUnlock = (IEdmBatchUnlock)vault7.CreateUtility(EdmUtility.EdmUtil_BatchUnlock);
try
{
foreach (KeyValuePair<string, string> kvp in SelectedFiles)
{
aFile = vault5.GetFileFromPath(kvp.Key, out ppoRetParentFolder);
aPos = aFile.GetFirstFolderPosition();
aFolder = aFile.GetNextFolder(aPos);
ppoSelection[i] = new EdmSelItem();
ppoSelection[i].mlDocID = aFile.ID;
ppoSelection[i].mlProjID = aFolder.ID;
i = i + 1;
}
batchUnlock.AddSelection((EdmVault5)vault5, ref ppoSelection);
batchUnlock.CreateTree(0, (int)EdmUnlockBuildTreeFlags.Eubtf_ShowCloseAfterCheckinOption + (int)EdmUnlockBuildTreeFlags.Eubtf_MayUnlock);
batchUnlock.Comment = "Release to Production ECO";
batchUnlock.UnlockFiles(0, null);
}
catch (System.Runtime.InteropServices.COMException ex)
{
MessageBox.Show("HRESULT = 0x" + ex.ErrorCode.ToString("X") + " " + ex.Message);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "\n" + GetStackTrace(ex));
}
}
I am guessing that this is a bug in the IEdmBatchUnlock2 interface. The IEdmBatchUnlock2 will cause a COM exception if called from a background worker but will not cause a COM exception if called from the UI thread. The IEdmBatchUnlock interface will not cause a COM exception when called from a background worker.
Just put a 0 in there for the handle. As long as your code will not require user input, it will work. I do it often.
batchGetter.AddSelection((EdmVault5)vault1, ref ppoSelection);
batchGetter.CreateTree(0, (int)EdmGetCmdFlags.Egcf_Lock);
batchGetter.GetFiles(0, null);

My app crashes when I try to send a request to the server

Well, it actually works pretty well on my android studio simulator but when I try to run it on my phone it just crashes.
I just want to send a number to the server and get a response with the data that I need to that number. so this is my code which do that:
thread = new Thread() {
#Override
public void run() {
//server stuff
try {
//Connecting
if(!userClass.equals("")) {
Log.i(debugString, "Attempting to connect to server");
socket = new Socket(hostname, portnumber);
Log.i(debugString, "Connection established!");
BufferedWriter bw = new BufferedWriter((new OutputStreamWriter(socket.getOutputStream())));
bw.write("" + userClass);
bw.newLine();
bw.flush();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
input = br.readLine();
}
} catch (IOException e) {
Log.e(debugString, e.getMessage());
} finally {
threadComplete = true;
}
}
};
thread.start();
while(!threadComplete)
continue;
then I just use this thread whenever I want to get the updated info for my request like that:
String getUserClass = userClass;
if(!getUserClass.equals(""))
{
threadComplete = false;
userClass = getUserClass;
thread.start();
while (!threadComplete)
continue;
changes.setText(input);
}
else Toast.makeText(this, "Error, choose your class", Toast.LENGTH_SHORT).show();
BTW, in the end of every thread (on the emulator because on my phone it crashes) I get a message:
Skipped 91 frames! The application may be doing too much work on its main thread.
and I have another problem, I also use IntentService to run my app service on the background, and obviously I don't want it to run constantly forever, so I made a loop which contains at the end of each loop a wait() command, but the problem is that when I set the time to wait for longer than 3000 milliseconds or so, the service crashes.
my code for the background service:
synchronized (this) {
int count = 0;
while (count<4) {
try {
wait(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (notifications && !userClass.equals("")) {
new Thread() {
#Override
public void run() {
//server stuff
try {
//Connecting
if (!userClass.equals("")) {
Log.i("debug", "Attempting to connect to server");
socket = new Socket(hostname, portnumber);
Log.i("debug", "Connection established!");
BufferedWriter bw = new BufferedWriter((new OutputStreamWriter(socket.getOutputStream())));
bw.write("" + userClass);
bw.newLine();
bw.flush();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
input = br.readLine();
}
} catch (IOException e) {
Log.e("debug", e.getMessage());
} finally {
complete = true;
}
}
}.start();
while (!complete)
continue;
Toast.makeText(this, "" + input, Toast.LENGTH_SHORT).show();
NotificationManager mNotifyMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.chanka)
.setContentTitle("ביטול שיעורים: ")
.setContentText(input);
mNotifyMgr.notify(mNotificationId, mBuilder.build());
mNotificationId++;
Toast.makeText(this, "" + input, Toast.LENGTH_SHORT).show();
count++;
}
}
}
This following piece of code is the culprit -
while (!threadComplete)
continue;
You are kind of putting the main thread on a long loop. Android does not allow that. The general construct in these kind of use cases is this -
Step 1 - Show a progress dialog to the user indicating that you are
doing something important and user needs to wait till that is
complete. Show some meaningful text in the progress dialog which makes
sense to the user.
Step 2 - Start a async connection to the server. There are lot of
options in Android to do this. But for your purpose AsyncTask might
be useful. Connect to your server, fetch and parse data in the
doInBackground method of AsyncTask and once the task is complete,
let onPostExecute publish the same to the Main thread.
Step 3 - Once you get back the result from the Async task, you may
dismiss the progress dialog and continue with whatever you were doing.
Please note that the main thread should not be blocked at any time. This is the event handling thread of the app and handles all events (User initiated or system initiated). If the thread is blocked, you get the kind of error you are seeing now. Specifically in your case, Android system is not able to do some draw operations because of the while loop.
Create a new Asynctask and run the socket establisment codes inside it :)
socket = new Socket(hostname, portnumber);

Call SSIS Package from c# Console Application For Each Loop

I have a Console Application which is invoking SSIS Package.Below is the code which is working Fine.
public static void ExecuteSSIS_Staging()
{
DataAccessLayer objDAL = new DataAccessLayer();
LogManager_SSIS objlogM = new LogManager_SSIS();
String strDestinationFilePath = System.Configuration.ConfigurationManager.AppSettings.Get("FileDownloaded");
try
{
Package pkg;
Application app;
DTSExecResult pkgResults;
MyEventListener eventListener = new MyEventListener();
string staging_pkgLocation = System.Configuration.ConfigurationManager.AppSettings.Get("SSIS_Staging_Filepath").ToString();
app = new Application();
pkg = app.LoadPackage(staging_pkgLocation, eventListener);
pkgResults = pkg.Execute(null, null, eventListener, null, null);
if (pkgResults == Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success)
{
Console.WriteLine("Success");
}
else if (pkgResults == Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure)
{
string err = "";
foreach (Microsoft.SqlServer.Dts.Runtime.DtsError local_DtsError in pkg.Errors)
{
string error = local_DtsError.Description.ToString();
err = err + error;
}
throw new Exception("Error Occurred while executing the SSIS Staging package:" + err);
}
}
catch (Exception ex)
{
throw new Exception("SSIS Package Execution Failed:" + ex.Message.ToString());
}
}
Now I am in a position to Invoke this Package inside Foreach Loop.
static void Main(string[] args)
{
try
{
foreach (DateTime FileDate in SortedDates)
{
ExecuteSSIS_Staging(FileDate);
}
}
Catch(Exception ex)
{
}
}
I am getting Many Issues like
Could not load file or assembly 'Microsoft.SqlServer.ManagedDTS
and few other DLL reference error.
Can anyone suggest me, how can i invoke SSIS Package Inside Foreach loop. The main thing is, In my Local machine it is working obsolutely file. But When i deploy it in server, it is not.
The actuall issue is i have added
Microsoft.SQLServer.ManagedDTS.dll version 9.0
in one machine. When i tried to open it in other machine, some how DLL is refernced to
Microsoft.SQLServer.ManagedDTS.dll version 10.0 version.
I changed it again & executed. Now Working Fine.

RFCommConnectionTrigger in Windows Universal Apps To detect Incoming Bluetooth Connection

I am working on a Windows Universal App. I Want to get the Data from a Bluetooth Device to the Windows Phone. I am Using the Concept of RFCommCommunicationTrigger for this Purpose.
Here's the code Snippet I am Using
var rfTrigger = new RfcommConnectionTrigger();
// Specify what the service ID is
rfTrigger.InboundConnection.LocalServiceId = RfcommServiceId.FromUuid(new Guid("<some_base_guid>"));
//Register RFComm trigger
var rfReg = RegisterTaskOnce(
"HWRFCommTrigger",
"BackgroundLibrary.RFBackgroundTask",
rfTrigger, null
);
SetCompletedOnce(rfReg, OnTaskCompleted);
Here the Function of RegisterTaskOnce
static private IBackgroundTaskRegistration RegisterTaskOnce(string taskName, string entryPoint, IBackgroundTrigger trigger, params IBackgroundCondition[] conditions)
{
// Validate
if (string.IsNullOrEmpty(taskName)) throw new ArgumentException("taskName");
if (string.IsNullOrEmpty(entryPoint)) throw new ArgumentException("entryPoint");
if (trigger == null) throw new ArgumentNullException("trigger");
// Look to see if the name is already registered
var existingReg = (from reg in BackgroundTaskRegistration.AllTasks
where reg.Value.Name == taskName
select reg.Value).FirstOrDefault();
Debug.WriteLine("Background task "+ taskName+" is already running in the Background");
// If already registered, just return the existing registration
if (existingReg != null)
{
return existingReg;
}
// Create the builder
var builder = new BackgroundTaskBuilder();
builder.TaskEntryPoint = entryPoint;
builder.Name = taskName;
builder.SetTrigger(trigger);
// Conditions?
if (conditions != null)
{
foreach (var condition in conditions)
{
builder.AddCondition(condition);
}
}
// Register
return builder.Register();
}
Here's the code for SetCompletedOnce this will add a Handler only once
static private void SetCompletedOnce(IBackgroundTaskRegistration reg, BackgroundTaskCompletedEventHandler handler)
{
// Validate
if (reg == null) throw new ArgumentNullException("reg");
if (handler == null) throw new ArgumentNullException("handler");
// Unsubscribe in case already subscribed
reg.Completed -= handler;
// Subscribe
reg.Completed += handler;
}
I have also Written the BackgroundLibrary.RFBackgroundTask.cs
public sealed class RFBackgroundTask : IBackgroundTask
{
public async void Run(IBackgroundTaskInstance taskInstance)
{
BackgroundTaskDeferral deferral = taskInstance.GetDeferral();
try
{
Debug.WriteLine(taskInstance.TriggerDetails.GetType());
taskInstance.Canceled += new BackgroundTaskCanceledEventHandler(OnCanceled);
Debug.WriteLine("RFComm Task Running");
Debug.WriteLine(taskInstance.TriggerDetails.GetType().ToString());
}
catch (System.Exception e)
{
Debug.WriteLine("RFComm Task Error: {0}", e.Message);
}
deferral.Complete();
}
}
The Run Method is Invoked Every Time The Device tries to Open the Connection.
The type of the Trigger that is obtained (the type I am debugging in the run method of the RFBackgroundTask.cs) is printed as
Windows.Devices.Bluetooth.Background.RfcommConnectionTriggerDetails
But I am Unable use that because I dont have this Class in the BackgroundLibrary project.
The Documentation says that this Provides information about the Bluetooth device that caused this trigger to fire.
It has Variables like Socket,RemoteDevice etc.
I think I am Missing something very simple
Can you please help me out .
Once your background task is launched, simply cast the TriggerDetails object to an RfcommConnectionTriggerDetails object:
public sealed class RFBackgroundTask : IBackgroundTask
{
public async void Run(IBackgroundTaskInstance taskInstance)
{
BackgroundTaskDeferral deferral = taskInstance.GetDeferral();
try
{
taskInstance.Canceled += new BackgroundTaskCanceledEventHandler(OnCanceled);
RfcommConnectionTriggerDetails details = (RfcommConnectionTriggerDetails)taskInstance.TriggerDetails;
StreamSocket = details.Socket; // Rfcomm Socket
// Access other properties...
}
catch (System.Exception e)
{
Debug.WriteLine("RFComm Task Error: {0}", e.Message);
}
deferral.Complete();
}
}

Change user password in an active directory machine located in another domain

I have this code to change the password of a user in an active directory:
DirectoryEntry directoryEntry = new DirectoryEntry("LDAP://0.0.0.0/CN=John Smith,OU=12345,OU=Project,DC=mysite,DC=local");
directoryEntry.AuthenticationType = AuthenticationTypes.Secure;
directoryEntry.Username = "adminusername";
directoryEntry.Password = "adminpassword";
directoryEntry.Invoke("SetPassword", new object[] { "newPassword" });
directoryEntry.Properties["LockOutTime"].Value = 0; //unlock account
When I try to execute this code directly into the server where is located the active directly, this work perfectly but when I try to execute it with a machine located in another domain, I receive this error:
System.Reflection.TargetInvocationException: Exception has been thrown by the ta
rget of an invocation. ---> System.Runtime.InteropServices.COMException: The RPC
server is unavailable. (Exception from HRESULT: 0x800706BA)
This is the only one limitation that I have because with the same admin user and other credentials, I'm able to add user, remove user, add group, rename any object, etc... BUT not changing password.
Not that I tried with this code and it doesn't work too:
public bool SetPassword(string userName, string newPassword, Domain.ActiveDirectory.Credentials credentials)
{
try
{
using (var pc = new PrincipalContext(ContextType.Domain, credentials.ServerName, credentials.OrganizationalUnitsDn + "," + credentials.DomainControllerName))
{
using (var user = UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, userName))
{
if (user == null)
{
return false;
}
user.SetPassword(newPassword);
return true;
}
}
}
catch (Exception e)
{
return false;
}
}
Anyone have an idea?
Thank you.

Resources