Running C++ script from a batch

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
sambul35
Posts: 192
Joined: 18 Jan 2012 10:13

Running C++ script from a batch

#1 Post by sambul35 » 17 Mar 2016 19:36

I wanted to incorporate into a batch a C script to query monitor's EDID (restart monitor) in case such query is delayed at PC wakeup, and on-screen picture is lost. The batch can be started by a keyboard shortcut to its desktop shortcut, or by Win Scheduler. However, running below script has a side effect of Windows sending the monitor immediately to Sleep, while PC stays awake. Any way to correct the script & make a batch from it to avoid monitor sleep effect in Win 10 64-bit?

Code: Select all

#include
 
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    // Turn off monitor
    SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM) 2);
    // Turn on monitor
    SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM) -1);
 
    return 0;
}

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Running C++ script from a batch

#2 Post by aGerman » 18 Mar 2016 06:36

C, C++, and the like are compiled programming languages while scripting languages are interpreted languages. That means you can't use this code in a script directly. But you could download the compiled file from the linked site and either call it from within a batch code or use it directy.

Regards
aGerman

sambul35
Posts: 192
Joined: 18 Jan 2012 10:13

Re: Running C++ script from a batch

#3 Post by sambul35 » 18 Mar 2016 08:33

@ aGerman

Thanks for your remark. I'll try that, or may follow Hybrids and Chimeras thread by using VBS script version from the linked site, though its mentioned there to have a different effect. Before doing that, would be nice to find an answer to my above question about the cause and prevention method of monitor immediately sent to sleep upon that code execution. Why it happens, and how to avoid programmatically?

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: Running C++ script from a batch

#4 Post by foxidrive » 18 Mar 2016 08:41

sambul35 wrote:However, running below script has a side effect of Windows sending the monitor immediately to Sleep, while PC stays awake.


So the script isn't involved at all, coz batch can't run it. Why not compile the code and try the executable?

sambul35
Posts: 192
Joined: 18 Jan 2012 10:13

Re: Running C++ script from a batch

#5 Post by sambul35 » 18 Mar 2016 09:17

Sorry, you are correct, I meant running the exe file has such side effect. :wink: I posted the source code expecting it may hint where the problem was, since it was written about 10 years ago for older Windows version. Did you mean it should be re-compiled for Win 10 64-bit to fix the issue? Are you saying calling it from a batch is not a good idea?
Last edited by sambul35 on 18 Mar 2016 09:28, edited 1 time in total.

npocmaka_
Posts: 516
Joined: 24 Jun 2013 17:10
Location: Bulgaria
Contact:

Re: Running C++ script from a batch

#6 Post by npocmaka_ » 18 Mar 2016 11:41

If you have no installed C compiler and don't want to rely on any you'll need to use C# compiler (which is available on any windows machine (except some XP machines)) and to access the sendMessage function you'll nee Platform invoke - you can use this as example-> http://fci-h.blogspot.bg/2007/03/turn-o ... ode-c.html

Then you can create C#\Batch hybrid like here->http://www.dostips.com/forum/viewtopic.php?t=5260

penpen
Expert
Posts: 2009
Joined: 23 Jun 2013 06:15
Location: Germany

Re: Running C++ script from a batch

#7 Post by penpen » 18 Mar 2016 14:44

We could run something like a C# conversion of "C++"-source from script, if the C++ functionality is exported in an (.NET compatible) dll:
I've described it shortly here.
(This is nearly the same solution npocmaka_ uses; this solution will create the exe file temporarily.)

This is a sample result; just create the below "Monitor.ps1" Powershell script, and start it using:

Code: Select all

PowerShell -executionpolicy remotesigned -File Monitor.ps1


"Monitor.ps1"

Code: Select all

$Assem = (
   "System",
   "System.Runtime.InteropServices",
   "System.Threading"
)

$Source = @"
using System;
using System.Runtime.InteropServices;
using System.Threading;

using DWORD     = System.Int32;
using HWND      = System.IntPtr;
using LPARAM    = System.IntPtr;
using LRESULT   = System.IntPtr;
using UINT      = System.UInt32;
using ULONG_PTR = System.UIntPtr;
using WPARAM    = System.IntPtr;



namespace Penpen.Test {
   public static class Monitor {
      [DllImport("kernel32.dll")]
      static extern HWND GetConsoleWindow();

      [DllImport("user32.dll", CharSet = CharSet.Auto)]
      static extern LRESULT SendMessage(
         HWND   hWnd,
         UINT   Msg,
         WPARAM wParam,
         LPARAM lParam
      );

      static UINT   WM_SYSCOMMAND   = 0x0112;
      static WPARAM SC_MONITORPOWER = (IntPtr)0xF170;

      public const Int32 On  = (-1);
      public const Int32 Low = 1;
      public const Int32 Off = 2;

      public static void SetMode(Int32 mode) {
         SendMessage(GetConsoleWindow(), WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM) mode);
      }

      public static void RestartMonitor() {
         // Turn off monitor
         SetMode(Off);

         // Turn on monitor
         Thread.Sleep(2000);
         Mouse.move(0, 100);
         Mouse.move(0, -100);
      }
   }

   public static class Mouse {
      public static DWORD MOUSEEVENTF_MOVE = 0x0001;

      [DllImport("user32.dll")]
      static extern void mouse_event(
         DWORD     dwFlags,
         DWORD     dx,
         DWORD     dy,
         DWORD     dwData,
         ULONG_PTR dwExtraInfo
      );


      public static void move(Int32 dx, Int32 dy) {
         mouse_event(MOUSEEVENTF_MOVE, (DWORD) dx, (DWORD) dy, (DWORD) 0, ULONG_PTR.Zero);
      }
   }
}
"@

Add-Type -ReferencedAssemblies $Assem -TypeDefinition $Source -Language CSharp 

[Penpen.Test.Monitor]::RestartMonitor()
Note that "SendMessage(GetConsoleWindow(), WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM) On)" only works under certain circumstances, which cannot be guaranteed (easily), so i used this workaround:
- wait some time (needed; you may have to wait some more longer: depends on your hardware), and
- mov the mouse.
(Tested on Win 8.1 32 bit.)


penpen

sambul35
Posts: 192
Joined: 18 Jan 2012 10:13

Re: Running C++ script from a batch

#8 Post by sambul35 » 19 Mar 2016 07:48

Thank you guys for your prompt replies. While I'm following your suggestions, testing the above code, and also trying to validate the assumption that monitor goes to sleep because the original exe was compiled for an older Win version, I wanted to add a few relevant links for newbie readers:

What's the difference between C, C++, and C#
What is the difference between C++ and Visual C++?

Which compiler would you suggest for Win 10 apps and why? I guess MS Visual Studio is default choice? :)
Last edited by sambul35 on 20 Mar 2016 08:09, edited 1 time in total.

sambul35
Posts: 192
Joined: 18 Jan 2012 10:13

Re: Running C++ script from a batch

#9 Post by sambul35 » 19 Mar 2016 15:32

There were suggestions above to compile the code. I'm using Eclipse with latest MinGW to compile it. MinGW site doesn't seem to list compatible Windows versions. The source code posted on the above linked website appears to be incomplete? No response from the author.

Code: Select all

17:28:15 **** Incremental Build of configuration Debug for project hdmiOn ****
Info: Configuration "Debug" uses tool-chain "MinGW GCC" that is unsupported on this system, attempting to build anyway.
Info: Internal Builder is used for build
g++ -O0 -g3 -Wall -c -fmessage-length=0 -o "src\\hdmiOn1.o" "..\\src\\hdmiOn1.cpp"
..\src\hdmiOn1.cpp:1:9: error: #include expects "FILENAME" or <FILENAME>
 #include
         ^
..\src\hdmiOn1.cpp:3:12: error: expected initializer before 'WinMain'
 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
            ^

17:28:15 Build Finished (took 237ms)

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Running C++ script from a batch

#10 Post by aGerman » 19 Mar 2016 16:51

The source code posted on the above linked website appears to be incomplete?

Yes. First line has to be

Code: Select all

#include <windows.h>


Which compiler would you suggest for Win 10 apps and why?

Visual Studio Community 2015
It's free, up to date (except C Lib), supports Windows-related source code best, supports different (also Windows-specific) programming languages and extensions.

But that's all pretty much off-topic in this forum.

Regards
aGerman

sambul35
Posts: 192
Joined: 18 Jan 2012 10:13

Re: Running C++ script from a batch

#11 Post by sambul35 » 19 Mar 2016 20:39

@ aGerman

I don't want to go off topic too much towards source code compiling issues. To wrap it up, your correction fixed the issue, but the compiled exe couldn't run due to some dlls not found presumably in MinGW folder. That raises a valid concern: are any executables compiled with 3rd party compilers behave like this - i.e. they could only run on those PCs where the original compiler package with required dlls is installed?

And executables compiled with MS Visual Studio would only run on those PCs where Windows Software Development SDK is installed? In this case, how standalone EXE files (compiled programs) are distributed that can run on any Win PC, and support several Windows versions? I assume they include all required dlls packed inside the exe file or package?

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Running C++ script from a batch

#12 Post by aGerman » 20 Mar 2016 05:50

MinGW compiles with dependencies to some DLLs that you will find either in the "bin" or in the "lib" directory of the compiler. If you run your tool the error message tells you what DLLs are missing. You can resolve it
- if you copy the missing DLLs in the same folder together with your tool
- or with static linking where you have to pass options -static-libgcc and -static-libstdc++ to the linker.
I prefer the latter. It's a Linker Setting in your IDE (if you even use one).

Visual Studio compiles programs with similar dependencies. Either you have to install the "redistributable package" (for VS2015) on all computers that you want to run your tool. Again the alternative is static linking. Since I'm using a version with German menu you should rather search the Internet for an explanation in your mother tongue.

penpen
Expert
Posts: 2009
Joined: 23 Jun 2013 06:15
Location: Germany

Re: Running C++ script from a batch

#13 Post by penpen » 20 Mar 2016 10:47

sambul35 wrote:trying to test the assumption that monitor goes to sleep because the original exe was compiled for an older Win version
No, the executable is compiled a special windows api.
If windows supports this api, then the program is executed with no problems.
Actual APIs are "Win32"/"Win64" and ".NET":
Since XP 32 bit systems use "Win32" and ".NET" and 64 bit systems use "Win64" and ".NET".
So an application that is compiled against Win32" and ".NET" will work on all 32 bit windows since then.

The monitor goes to sleep because this program tells him to do so:
"SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM) 2);"

The problem is, that the code that should rewake the monitor doesn't work since win8 (Hearsay: Only works under certain circumstances):
"SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM) -1);"

Hearsay (don't know if that is true):
Since windows 8 (or so) its default behaviour when callling this line of code without proper initialization of monitor and graphic card is to do nearly nothing:
This initialization is part of the monitor/graphics card drivers and therefore not public available and also not standardized.
The workaround (to move the mouse) depends on the fact, that the system wakes up the monitor in a "clean way".


I assumed that you wanted to turn the monitor "off and on again".
If that is wrong, and you really want to read the EDID (and store it somewhere - for example to a file) then i guess you should read this (4. and 5. - i don't know it this suffices, but it sounds good):
http://ofekshilon.com/2011/11/13/reading-monitor-physical-dimensions-or-getting-the-edid-the-right-way/


Sidenote:
It makes no difference how you access the WinAPI, so
if you compile and link the c++ files to executables,
then they will exactly do the same as the c# code above.


penpen

sambul35
Posts: 192
Joined: 18 Jan 2012 10:13

Re: Running C++ script from a batch

#14 Post by sambul35 » 20 Mar 2016 13:04

I thank all participants for the code, explanations and suggestions. As you noted, it looks the original source code author assumed it queries the EDID when in fact it just cycles the monitor power, which apparently doesn't trigger re-initialization. I had a chance to test today the above powershell code and original exe when my monitor lost picture again, they both work as intended (except the wakeup part for the exe), but don't fix the issue. Meaning, on wakeup from sleep it appears that reading actual monitor EDID is delayed, and normal picture is replaced by a pattern of vertical lines on screen and garbled. The above code execution doesn't result in restoring normal picture. Actually, manually powering monitor off/on by its power button also doesn't restore picture.

On the other hand, re-initializing GPU & monitor with devcon is likely to restore picture without PC reboot, but I couldn't test it since devcon for some reason didn't want to run from batch. I will "process" the info in the above link trying to find out if code they posted can do the job of restoring lost pic without PC reboot. Another suggestion I found is setting GPU to use EDID Override instead of original monitor EDID. While that driver feature either not available for consumer GPUs, or doesn't work for pro AMD GPUs (in the latest driver), there're 3rd party tools like CRU that add EDID Override and seems to instruct driver to use it. However, it remains to be seen if it will actually prevent periodic picture loss on monitor wakeup. Indeed, why would it, since EDID data for each monitor is already written in Registry, but the driver either don't use it, or picture loss has a different mechanism. Generally its unclear why GPU driver would need to query monitor EDID at wakeup despite its record is already available in Registry?

The above are complex interdisciplinary issues, but they still can't be resolved without running a certain code, possibly a batch. :wink:

penpen
Expert
Posts: 2009
Joined: 23 Jun 2013 06:15
Location: Germany

Re: Running C++ script from a batch

#15 Post by penpen » 21 Mar 2016 09:25

sambul35 wrote:I will "process" the info in the above link trying to find out if code they posted can do the job of restoring lost pic without PC reboot.
The above won't auto-restore anything - it just reads the EDID (128/256 Bytes) copy from the registry to a (c#) variable.
I was unsure what you wanted to do (i misinterpreted parts of your OP):
The script (turning the monitor "off and on again") there does not query the EDID (for you),
but (while turning the monitor on again) advices the graphics card to do parts of PnP initialization (including to retrieve the EDID per DDC).


sambul35 wrote:On the other hand, re-initializing GPU & monitor with devcon is likely to restore picture without PC reboot, but I couldn't test it since devcon for some reason didn't want to run from batch.
If the above script doesn't solve your issue, then it is graphics card driver / dispaly adapter related:
Using devcon seems to reinitialize what went wrong.
I post in your referenced topic (never heard of a working executable that cannot be started from batch).


penpen

Post Reply