c# - Capture screen on server desktop session -


i have developed gui test framework integrationtesting of our company website on scheduled basis. when fails, it'll take screenshot of desktop, among other things. runs unattended on logged in user on dedicated windows server 2008.

the problem taking screenshot on desktop have disconnected remote desktop session from. following exception:

system.componentmodel.win32exception (0x80004005): handle invalid      @ system.drawing.graphics.copyfromscreen(int32 sourcex, int32 sourcey, int32 destinationx, int32 destinationy, size blockregionsize, copypixeloperation copypixeloperation)      @ system.drawing.graphics.copyfromscreen(point upperleftsource, point upperleftdestination, size blockregionsize)      @ integrationtester.testcaserunner.takescreenshot(string name) in c:\vs2010\integrationtester\integrationtester\config\testcaserunner.cs:line 144      @ integrationtester.testcaserunner.starttest() in c:\vs2010\integrationtester\integrationtester\config\testcaserunner.cs:line 96 

the takescreenshot() method looks this:

public static void takescreenshot(string name)         {             var bounds = screen.getbounds(point.empty);             using (bitmap bitmap = new bitmap(bounds.width, bounds.height))             {                 using (graphics g = graphics.fromimage(bitmap))                 {                     g.copyfromscreen(point.empty, point.empty, bounds.size);                 }                 bitmap.save("somefilename", imageformat.jpeg);             }         } 

i have made sure screensaver set "none" no timeout. have implemented piece of code couple of pinvokes send mouse move, hoping generate desktop graphics handle.. no.

intptr hwnd = getforegroundwindow(); if (hwnd != intptr.zero)     sendmessage(hwnd, 0x200, intptr.zero, intptr.zero); 

any advice appreciated.

in order capture screen need run program in session of user. because without user there no way have desktop associated.

to solve can run desktop application take image, application can invoked in session of active user, can done service.

the code below allows invoke desktop application in such way run on local user's desktop.

if need execute particular user, check code in article allow service interact desktop? ouch.. can consider using function logonuser.

the code:

public void execute() {     intptr sessiontokenhandle = intptr.zero;     try     {         sessiontokenhandle = sessionfinder.getlocalinteractivesession();         if (sessiontokenhandle != intptr.zero)         {             processlauncher.startprocessasuser("executable path", "command line", "working directory", sessiontokenhandle);         }     }     catch     {         //what gonna do?     }         {         if (sessiontokenhandle != intptr.zero)         {             nativemethods.closehandle(sessiontokenhandle);         }     } }  internal static class sessionfinder {     private const int int_consolesession = -1;      internal static intptr getlocalinteractivesession()     {         intptr tokenhandle = intptr.zero;         int sessionid = nativemethods.wtsgetactiveconsolesessionid();         if (sessionid != int_consolesession)         {             if (!nativemethods.wtsqueryusertoken(sessionid, out tokenhandle))             {                 throw new system.componentmodel.win32exception();             }         }         return tokenhandle;     } } 

internal static class processlauncher {     internal static void startprocessasuser(string executablepath, string commandline, string workingdirectory, intptr sessiontokenhandle)     {         var processinformation = new nativemethods.process_information();         try         {             var startupinformation = new nativemethods.startupinfo();             startupinformation.length = marshal.sizeof(startupinformation);             startupinformation.desktop = string.empty;             bool result = nativemethods.createprocessasuser             (                 sessiontokenhandle,                 executablepath,                 commandline,                 intptr.zero,                 intptr.zero,                 false,                 0,                 intptr.zero,                 workingdirectory,                 ref startupinformation,                 ref processinformation             );             if (!result)             {                 int error = marshal.getlastwin32error();                 string message = string.format("createprocessasuser error: {0}", error);                 throw new applicationexception(message);             }         }                 {             if (processinformation.processhandle != intptr.zero)             {                 nativemethods.closehandle(processinformation.processhandle);             }             if (processinformation.threadhandle != intptr.zero)             {                 nativemethods.closehandle(processinformation.threadhandle);             }             if (sessiontokenhandle != intptr.zero)             {                 nativemethods.closehandle(sessiontokenhandle);             }         }     } }  internal static class nativemethods {     [dllimport("kernel32.dll", entrypoint = "closehandle", setlasterror = true, charset = charset.auto, callingconvention = callingconvention.stdcall)]     internal static extern bool closehandle(intptr handle);      [dllimport("advapi32.dll", charset = charset.unicode, setlasterror = true)]     internal static extern bool createprocessasuser(intptr tokenhandle, string applicationname, string commandline, intptr processattributes, intptr threadattributes, bool inherithandle, int creationflags, intptr envrionment, string currentdirectory, ref startupinfo startupinfo, ref process_information processinformation);      [dllimport("kernel32.dll", entrypoint = "wtsgetactiveconsolesessionid")]     internal static extern int wtsgetactiveconsolesessionid();      [dllimport("wtsapi32.dll", setlasterror = true)]     [return: marshalas(unmanagedtype.bool)]     internal static extern bool wtsqueryusertoken(int sessionid, out intptr phtoken);      [structlayout(layoutkind.sequential)]     internal struct process_information     {         public intptr processhandle;         public intptr threadhandle;         public int processid;         public int threadid;     }      [structlayout(layoutkind.sequential)]     internal struct startupinfo     {         public int length;         public string reserved;         public string desktop;         public string title;         public int x;         public int y;         public int width;         public int height;         public int consolecolumns;         public int consolerows;         public int consolefillattribute;         public int flags;         public short showwindow;         public short reserverd2;         public intptr reserved3;         public intptr stdinputhandle;         public intptr stdoutputhandle;         public intptr stderrorhandle;     } } 

this code modification of 1 found @ article allow service interact desktop? ouch. (must read)


addendum:

the code above allows execute program in desktop of user logged locally on machine. method specific current local user, possible user. check code @ article allow service interact desktop? ouch. example.

the core of method function createprocessasuser, can find more @ msdn.

replace "executable path" path of executable run. replace "command line" string passed execution arguments, , replace "working directory" working directory want. example can extract folder of executable path:

    internal static string getfolder(string path)     {         var folder = system.io.directory.getparent(path).fullname;         if (!folder.endswith(system.io.path.directoryseparatorchar.tostring()))         {             folder += system.io.path.directoryseparatorchar;         }         return folder;     } 

if have service, can use code in service invoke desktop application. desktop application may the service executable... can use assembly.getexecutingassembly().location executable path. can use system.environment.userinteractive detect if executable not running service , pass execution arguments information task needed do. in context of answer capture screen (for example copyfromscreen), else.


Comments

Popular posts from this blog

c# - How to set Z index when using WPF DrawingContext? -

razor - Is this a bug in WebMatrix PageData? -

visual c++ - Using relative values in array sorting ( asm ) -