C# Service Will not write files, no errors - c#

EDIT:
Ok, as of now and looking through countless posts I this i've arrived to a solution, I cannot do what I need to do from a service, I wanted it to be a service so that it would always be on for the computer, but apparently with the way services are written I may not be able to run the commands I want to run because "The service does not run in the same space as the users desktop" so it wont be able to capture the desktop, at least, thats what im gathering so far.
As for now, I'll leave this here and maybe find a way to start a program under the users name when they logon, to capture the desktop, rather than try and do it from the service directly.
I've been banging my head on the wall for a couple hours now trying to figure this out, I've never made a service before, just forms applications, well my next project (Client Server Model Client Monitoring utility) needs to be installed as a service on the client machines and send data back to the main server.
Having never written a service before I looked up how to write one and how to install it and whatnot. I got it all working fine, the current working version spits an event log out every 30 seconds to show its working.
I started by running it in LocalSystem because I assumed it had the permissions to write to the file, but after that failed I tried LocalService, that didn't work either.
Im specifying the Directory as C:\WatcherData\Test.jpg
and tested it in a regular forms application (which works)
OutputImage.Save("c:\watcherdata\test.jpg", ImageFormat.Jpeg);
No exceptions, no events, it just doesn't happen, but the EventLog message is put in immediately before it,so it should be reaching that point, right?
Any assistance would be appreciated, If you need to know anything else I would be happy to oblige
EDIT:
Here goes a little code:
private void ServiceWorkerThread(object state)
{
while (!this.stopping)
{
this.eventLog1.WriteEntry("This is a test2");
CallMe();
Thread.Sleep(30000);
}
this.stoppedEvent.Set();
}
private void CallMe()
{
try
{
int screenWidth = Screen.GetBounds(new Point(0, 0)).Width;
int screenHeight = Screen.GetBounds(new Point(0, 0)).Height;
Bitmap OutputImage = new Bitmap(screenWidth, screenHeight);
Graphics gfx = Graphics.FromImage((Image) OutputImage);
gfx.CopyFromScreen(0, 0, 0, 0, new Size(screenWidth, screenHeight));
OutputImage.Save("c:\\watcherdata\\test.jpg", ImageFormat.Jpeg);
}
catch (Exception e)
{
this.eventLog1.WriteEntry(e.Message + "\r\n" + e.StackTrace, EventLogEntryType.Error);
}
}
most of it was taken from a Microsoft sample document, as I said, I'm new to services
currently still trying to figure it out, will let you guys know if i get anywhere
EDIT 2
After playing around some more I managed to get it to write to the file, After realizing that most of the problem was with my lack of knowledge on how to build services and installers, apparently i wasnt rebuilding the installers when i built my service.
Now it just writes all black, a large, black picture. but at least its writing!

How about some source code?
I might add some tracing to make sure the file write code is executed.
Most cases, this type of failure is a permissions issue and/or folks are trying to write to a Windows system directory. You question suggests you are ensuring that you are NOT writing to a Windows Directory. Please make sure c:\watcherdata folder exists.

Related

A generic error occurred in GDI+ with iTextSharp, only on a particular server

Most of the questions about this error (and wow, there are a lot) revolve around saving to a file, which isn't what I'm doing.
My code is as follows - .NET 4.5, MVC3, IIS7.5, Win2008R2:
string fileName = /* something.png */;
string imageLocation = HttpContext.Current.Server.MapPath(
string.Format(#"~/Content/images/{0}", fileName));
var image = iTextSharp.text.Image.GetInstance(
System.Drawing.Image.FromFile(imageLocation),
System.Drawing.Imaging.ImageFormat.Png);
Decompiling iTextSharp, the GetInstance method looks like:
public static Image GetInstance(Image image, ImageFormat format)
{
MemoryStream memoryStream = new MemoryStream();
image.Save(memoryStream, format); // <-- Exception here
return Image.GetInstance(memoryStream.ToArray());
}
The exception I get is:
System.Runtime.InteropServices.ExternalException (0x80004005):
A generic error occurred in GDI+.
at System.Drawing.Image.Save(Stream stream, ImageCodecInfo encoder, EncoderParameters encoderParams)
at iTextSharp.text.Image.GetInstance(Image image, ImageFormat format)
So it's failing when attempting to save the image into a MemoryStream, not to a file or the HTTP response.
This just started happening to an existing application that worked fine previously. The exact same code functions perfectly on a different server and my local machine (all 3 are 2008R2), and it happens to every application on my production server (I have 4), and also even a brand new one with the same codebase I put up there for testing this issue.
So I assume there's something with my specific production server, maybe IIS. Windows updates seem to be the same between the two servers, so I don't think that's it.
Anything else that you can think of which might be environment-specific to cause this error? I can re-work the code to clean up our part a bit, like creating a new in-memory image instead of using the one created from the file, but since this is my production system, I'd rather find a short-term solution without a code-fix.
EDIT
Some interesting stuff as I'm troubleshooting...I added a console app to the server, and ran it using the same account as the web app, with the same code (just those couple lines), and it worked fine. I added an empty MVC application with the same couple lines, using a new application pool, and it worked fine - I changed this application pool to use the same user account as the main app, and it still worked.
I changed the new test app to the same app pool as the app, and it failed with the same exception as the regular app. So something is wrong with that application pool, but it isn't the user.
The app pools are identical as far as I can tell. And the main one recycles overnight, and I saw the problem yesterday, so a recycle didn't cut it.
If I can't figure something out, I'll reset IIS and/or the server tonight and see if that clears it up.
EDIT 2
I just tried various combinations of this (from this question) on my dummy app, as well as putting another intermediary image in there, and still nothing...
var image = System.Drawing.Image.FromStream(
new MemoryStream(System.IO.File.ReadAllBytes(imageLocation)));
var image3 = iTextSharp.text.Image.GetInstance(
image, System.Drawing.Imaging.ImageFormat.Png);
Drives me nuts...
This was resolved with the "Microsoft solution" of turning it off and back on again - an IIS reset with iisreset /restart on the command line, and it started working again.
So I have no idea what caused the problem, or if it'll ever happen again.

Graphics.CopyFromScreen() and GetDC(0) fail with "The handle is invalid"

I have an application that takes screenshots from the local computer.
This works since many years correctly until suddenly a colleague reported me that he got an "The handle is invalid" error from my application.
This error came from inside the .NET framework from Graphics.CopyFromScreen().
To work around this I replaced this function with C++ code using GetDC(GetDesktopWindow()) / GetDC(NULL) and BitBlt() to copy the screen into a bitmap. Now I got ERROR_INVALID_HANDLE.
This happens on Windows 7.
What is going on there ?
I can not investigate this problem on my own because I cannot reproduce it and my colleague is in another country.
I searched in Google and lots of people report this error.
But all posts that I found were from people who tried to take a screenshot from a client computer through ASP code on a server. I don't understand how people can have the strange desire to capture the client's computer from a website. It is obvious that this will not work.
But I could not find one single case where someone reports this problem from an application that cannot capture the screen of the SAME computer in the SAME session where the application itself is running.
After investigating more with my colleague and giving him ideas what he can try, he told me that he starts my application through a remote desktop session.
The remote desktop session creates a virtual desktop (you see for example that the desktop wallpaper is missing).
I told my colleague to install a VNC client to remote control the computer instead of a remote desktop session and now all works fine. He installed TightVNC which uses the REAL desktop user session instead of creating a virtual session and locking the screen of the machine.
So if anyone gets reports of "The handle is invalid" while taking a screen capture, ask your users if they use a remote desktop session.
To detect a remote desktop session in code you can write:
in C++:
if (GetSystemMetrics(SM_REMOTESESSION) > 0)
{
MessageBox(m_hWnd, L"This application may not work correctly in a remote desktop session", "Error", MB_ICONSTOP);
}
or in C#:
if (System.Windows.Forms.SystemInformation.TerminalServerSession)
{
Messagebox.Show("This application may not work correctly in a remote desktop session");
}
Note that the problem is not reproducible on all computers. When I test on my own Windows 7 it works. So there are probably any additional system settings or other factors that trigger the "The handle is invalid" error (service packs / hotfixes...?).
But my colleague reports that he has never seen the error again after he stopped using the remote desktop connection.
There are a few reasons this can happen but the underlying theme is that the desktop window isn't available when this method is called.
In addition to the reasons mentioned above, another reason this can happen is if this method is being called when the screen is locked.
The code for CopyFromScreen has this section:
int result = SafeNativeMethods.BitBlt(targetDC, destinationX, destinationY, destWidth, destHeight, screenDC, sourceX, sourceY, (int) copyPixelOperation);
//a zero result indicates a win32 exception has been thrown
if (result == 0) {
throw new Win32Exception();
}
It would seem to me that the safest course of action would be that if you make use of this function, make sure that you also write your code assuming that receiving a Win32Exception or an unavailable Desktop Window is a use case which must be handle so the application doesn't crash.

C# Inconsistent Security Group Membership

I apologize for how open ended I'm sure this will end up. I'll try to break this up in manageable chunks.
I'm writing a program that deals with SCCM. This program is locked down by security groups.
If you are not a member of the 'Server Operators' group, you don't get in. Simple. I've been testing for awhile on my dev machine (a Dell that is on wireless) with no issues.
When I released a beta, I found that under certain circumstances the program will not pick up on the user's security group membership and therefore deny access.
I was able to reproduce the issue, it seems machines on wireless tend to have this issue. Though, it's more complicated than that.
-Freshly imaged machines seem to have this issue
-Not all wireless machines; my dev machine is wireless
-One desktop (no wireless) has this issue. (It's at a remote site, so I can't really pick that one apart) I think it's a fresh image as well. I did however test on another computer at the same site - worked fine.
-Connecting to ethernet seems to have an effect - 75% of the time it fixes the issue somehow - after a bit of a wait. (Works on both ethernet and wireless at that point)
I've been trying to get a breakpoint set on one of these machines so I can see what is going on. Problem is, by the time I get VS.net installed the problem solves itself. I know (very little) about remote debugging - currently looking into that. This scenario makes me wonder if it's update related (the image is fairly up to date, maybe a month or two out?)
I also wrote a small utility that tests the login procedure (using the same code) and it finds the security group every time. Wat.
Code for finding security group of a user:
(courtesy of Stack :) )
static bool IsUserMemberOf_(string user, string group)
{ // (I realize the user parameter is superfluous in this case)
try
{
DirectoryEntry entry = new DirectoryEntry("LDAP://" + TC.act_Domain, TC.act_AD_User, TC.enc_GetADPassword());
DirectorySearcher mySearcher = new DirectorySearcher(entry);
mySearcher.Filter = "(&(objectClass=user)(|(cn=" + TC.act_AD_User + ")(sAMAccountName=" + TC.act_AD_User + ")))";
SearchResult result = mySearcher.FindOne();
foreach (string GroupPath in result.Properties["memberOf"])
{
if (GroupPath.Contains(group))
{
return true;
}
}
}
catch (DirectoryServicesCOMException)
{
}
return false;
}
I've also tried another method (using Principal.IsMemberOf() ), which had the same result. I've also investigated DNS/Network problems. Not ruling it out, but doesn't seem to be a factor in the testing I've done.
I'm at a loss. If anyone has any thoughts, by all means please lay them on me.
Thanks
Yeah, it was the .net version. Our image starts with .net 4.0. Throwing 4.5.2 at it clears it right up. I would have expected an error at runtime, but I guess not.
... I'll show myself out

Windows Service not working when installed, works fine in Debug mode; crashes on Moving/deleting files

I created a windows service which watches a directory. When a file is dumped into it, it takes the data and puts it into a database. Then this file is moved to another directory and deleted. It works fine in debug mode. But when i install it on my computer it stops after throwing the data into the database and the file in question is neither moved or deleted. I suspect a permission issue is involved. I tried to create a event log:
public Service1()
{
InitializeComponent();
if (!System.Diagnostics.EventLog.SourceExists("MySource"))
{
System.Diagnostics.EventLog.CreateEventSource(
"MySource", "MyNewLog");
}
eventLog1.Source = "MySource";
eventLog1.Log = "MyNewLog";
}
So i have three questions.
(1) What could be causing my service to work as described in debug but fail when installed on my computer.(2) I have initiated a event log as shown above. But do i need to add other code to record the event of my service stopping. I presume this would be done in a 'override onShutdown' method.(3) Finally when my service stops, i want to look at the event log. But i do not know how to do this, is in administrative tools? stored as a file on some directory?
Here is edit to this post in lieu of the grateful advice given below.
try
{
File.Move(e.FullPath, finalString);
File.Delete(e.FullPath);
}
catch(Exception q)
{
EventLog.WriteEntry("MySource", q.ToString(), EventLogEntryType.Error);
using (StreamWriter w = new StreamWriter(ConfigurationManager.AppSettings["fmd"], true))
{
w.Write(DateTime.Now.ToString("dd-MM-yyyy_hh-mm-ss"));
w.Write(q.ToString());
}
}
As per suggestion i put a try-catch around the file move and delete plus i added a OnShutdown method:
protected override void OnShutdown()
{
using (StreamWriter w = new StreamWriter(ConfigurationManager.AppSettings["ond"], true))
{
w.Write("stop OnShutdown");
}
//EventLog.WriteEntry("MySource", message, EventLogEntryType.Error);
}
I do not know how to pass any system error message to the shutdown method, so any advice appreciated. When i installed my modified code as a service, it again stopped before moving or deleting the files. Neither of my two logs accessed by a stream recorded anything. Plus the event viewer showed nothing either?
You can write as following,
if (!EventLog.SourceExists("MySource"))
EventLog.CreateEventSource("MySource", "Application");
EventLog.WriteEntry("MySource", message, EventLogEntryType.Error);
to view the event log messages, Goto Administrator Tools -> Event Viewer and look for the source you have created. or Just simply type eventvwr in run window.
When Services installed, it works under SYSTEM User account where service might not have access to some resources. Please put logs and see where exactly the issue is.
If you service installed in your development machine, use attach to process option under DEBUG Menu in Visual Studio to find out.
What could be causing my service to work as described in debug but fail when installed on my computer?
Permissions. The service is likely running under LocalSystem or Network Service if you didn't provide a different identity.
I have initiated a event log as shown above. But do i need to add other code to record the event of my service stopping. I presume this would be done in a 'override onShutdown' method?
Yes, you're assumption is correct.
Finally when my service stops, i want to look at the event log. But i do not know how to do this, is in administrative tools?
Just hit Windows Key+R to get the Run dialog and type eventvwr.
Well i found the reason for all the commotion. I eventually found some logs in the event viewer. They were listed in Administrative events in custom logs. There were three error logs: .Net runtime; Application error & Service Control Manager. In '.Net Runtime' the stack showed a unhandled exception for system.windows.forms. I stupidly included a pop up box in my release version. But even when i commented this away; i got a error. So i went back and found other message boxes, primarily in try catch statements. Removed these and solved the issue.

In need of some advice controlling a C# winforms application via a asp.net website

I'm working on a little project for a basic Youtube remote control, whereby I have a helper app running on my PC, and then can send commands from a website accessed via the web browser on my phone.
Reading through threads on other sites from people trying to do the same thing I've realized it is not a concept that most people would be comfortable with, but I am struggling to think of another way to do it beyond writing a native app for my phone and having it communicate with the helper application internally via WLAN(Would be happy to do this, but don't have the cash to spring for a new mac to develop for my iphone).
If I were to stick with the Website/Winforms model, is there a way to do this in such a way that (most) people would be comfortable running?
The ideas I had so far were:
a) Build a web server into the helper app(Though not sure of the logistics of having it host an ASP.net site)
b) Host the site externally, and have the helper app periodically poll a database/webservice on a server to receive commands (Sketchy and i imagine very resource heavy)
Sorry for the wall of text, I'm capable of running with an idea and building it, I'm just not sure what is possible and considered the 'best' way to do something like this.
Any advice would be appreciated.
Cheers
Edit Thanks, just to be clear, when i say uncomfortable, I mean - Would you be ok with having a website being able to send potentially ANY command to your computer? This seems to be the problem raised in other discussions about this topic. Obviously I'm not trying to do anything malicious, but as I said, it seemed to be a concern.
If this is a controlled environment where you can always open a port on the firewall for incoming communication, you can have the web app make a WCF call back to the Windows Client through the users firewall.
If not (which is what I suspect), you may be better off polling a web service. Just do it every few seconds and whatever you're checking in that web service call (a database?) make sure it's well optimized. Perhaps just have it return some status int/enum or something very light weight to instruct the client on the next call to make (0 = no update, 1 = command1, 2 = command2, etc).
As for how you do the polling, you could do something like:
int seconds = 4;
System.Timers.Timer _clientTimer = new System.Timers.Timer(seconds * 1000);
_clientTimer.AutoReset = false;
_clientTimer.Elapsed += clientTimer_Elapsed;
_clientTimer.Start();
private void clientTimer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
// Connect to web service, get status, if status != 0 do something...
}
finally
{
_clientTimer.Start();
}
}
NOTE: the auto-reset = false means that each time the Elapsed event fires, the timer is stopped. In the approach I've taken, I let the timer stop so the client can process the web service results and then start the timer once again after it's done. This will help prevent multiple requests from piling up if a connection is real slow.
That's all I can think of :)

Categories

Resources