Code Execution Only In Finished Exe

I have some code in my app which switches to the screen resolution the app was designed to work in (800x600). This works fine.

My native screen rez is 1280x1024 and every time I run my app while in the Delphi IDE, on exit, all the Delphi windows are bunched up in the top left corner.

Enabling it for the final compile and disabling it while working on it in the IDE is getting to be a bit of a pain - especially when I forget to enable it for the final compile and only discover it after I've re-built the installer and installed it on my test machine! :)

Is there any way to have the screen rez code executed ONLY when the finished exe is run - but not when working in the IDE.

I have a feeling that it's using the compiler directives, ($IFDEF?), but I can't find any info on exactly how it's done.

I'm sure this is one of those very easy questions to answer... if you know how it's done! :)

TDK_Man
LVL 1
tdk_manAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Wim ten BrinkSelf-employed developerCommented:
Actually, you could use FindWindow to check if the Delphi IDE is running or not but that doesn't make it really clear if you're running from within the IDE or not. But Delphi does not have an easy way to check if it's run from the IDE or in some other way.
Technically, it should be possible to check the process stack and check who created your process. If Delphi is the parent process of your executable then you know you're running in the IDE, otherwise you're running stand-alone, even through Delphi might be running at the same time.
0
MolandoCommented:
Check to see  if DebugHook<>0 then the  program is running in the ide. if it is not zero, then it is running outside the  IDE

so:

var
  dm : TDEVMODE;

  if DebugHook = 0 then begin
      ZeroMemory(@dm, sizeof(TDEVMODE));
      dm.dmSize := sizeof(TDEVMODE);
      dm.dmPelsWidth  := 1024;
      dm.dmPelsHeight := 768;
      dm.dmFields := DM_PELSWIDTH or DM_PELSHEIGHT;
      ChangeDisplaySettings(dm, 0);
      end;

Molando
    end;

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
cqhallCommented:
DebugHook is an excellent find.  

However, be aware that if integrated debugging is disabled (Tools|Debugger Options..., Integrated debugging checkbox), the result will be 0 (standalone) even if the application is run from the IDE (F9, Run|Run).  In fact, the application is essentially outside the IDE, because you can close Delphi without it complaining and Run|Program Reset is diabled.
0
Cloud Class® Course: CompTIA Healthcare IT Tech

This course will help prep you to earn the CompTIA Healthcare IT Technician certification showing that you have the knowledge and skills needed to succeed in installing, managing, and troubleshooting IT systems in medical and clinical settings.

tdk_manAuthor Commented:
Mmm yes...

I forgot that when you run your program, you aren't really in the IDE - just executing the exe which has been created. Good point!

I'm thinking of the old interpreter days when you compiled your exe afterwards.

Molando:

That looks like it should do the trick - thanks. I'll try it out and report back to award the points if it all goes to plan. :)

TDK_Man
0
moorhouselondonCommented:
You could use paramstr to pass a command line string to the program when it is run.  In the Run menu is a Command Line Parameters box where you can type in whatever parameters you want.  These parameters are persistent between runs of the compiler.

The snag with this is that the user of the application could guess that you were using this technique and go into the shortcut icon and amend it to run with the same parameter, but it is unlikely for the average user to hit on this.

In your program, before creating forms, etc.

if paramstr(1)='DebugMode' then
  screenres this
else
  screenres that;


0
Wim ten BrinkSelf-employed developerCommented:
I have thought about using DebugHook too but I realised that it would still be possible to run the application from the IDE without the debugger being attached. One other problem could arise if your process is run from another debugger, e.g. Borland's stand-alone debugger. But that's fortunately not the case here.

I did find one interesting alternative, though... I've been experimenting with WMI lately and when I create a list of processes (select * from Win32_Process) iced that my process has a ParentProcessId property. With this ParentProcessId you could search for the parent process and if this parent happens to be Delphi, you're running it from Delphi. Otherwise, it's run in some different way...

Let's show something WMI-based that WORKS! :-)

uses
  Windows, SysUtils, Classes, ActiveX, ComObj, WbemScripting_TLB, ShellAPI;

function IsRunFromDelphi: Boolean;
const
  sQuery = 'SELECT * FROM Win32_Process WHERE (ProcessId = "%s")';
var
  ExecutablePath: string;
  Item: SWbemObject;
  Locator: ISWbemLocator;
  NumProp: LongWord;
  ObjectSet: ISWbemObjectSet;
  OleProperty: OleVariant;
  ParentProcessId: string;
  Query: WideString;
  Services: ISWbemServices;
begin
  Result := False;
  try
    Locator := CoSWbemLocator.Create;
    Services := Locator.ConnectServer( '', 'root\cimv2', '', '', '', '', 0, nil );
    Query := Format( sQuery, [ IntToStr( GetCurrentProcessId ) ] );
    ObjectSet := Services.ExecQuery( Query, 'WQL', wbemFlagBidirectional, nil );
    if Succeeded( ( ObjectSet._NewEnum as IEnumVariant ).Next( 1, OleProperty, NumProp ) ) and ( NumProp > 0 ) and Succeeded( IDispatch( OleProperty ).QueryInterface( SWBemObject, Item ) ) then begin
      ParentProcessId := VarToStr( Item.Properties_.Item( 'ParentProcessId', 0 ) );
      Query := Format( sQuery, [ ParentProcessId ] );
      ObjectSet := Services.ExecQuery( Query, 'WQL', wbemFlagBidirectional, nil );
      if Succeeded( ( ObjectSet._NewEnum as IEnumVariant ).Next( 1, OleProperty, NumProp ) ) and ( NumProp > 0 ) and Succeeded( IDispatch( OleProperty ).QueryInterface( SWBemObject, Item ) ) then begin
        ExecutablePath := VarToStr( Item.Properties_.Item( 'ExecutablePath', 0 ) );
        Result := ( pos( 'delphi32.exe', LowerCase( ExecutablePath ) ) > 0 )
      end;
    end;
  except Result := False;
  end;
end;

Well, the uses clause might contain a bit too many units. Above code runs good in Delphi 5 and I've used the following code to test it:

    if IsRunFromDelphi then begin
      MessageBox( GetDesktopWindow, 'Delphi', 'Running from...', MB_OK );
    end
    else begin
      MessageBox( GetDesktopWindow, 'stand-alone', 'Running...', MB_OK );
    end;

When running from Delphi, it displayed Delphi. When run from the Norton commander, it returns Stand-alone. You could actually use above code to go all the way back to the top parent process. The drawback is of course that you need to use WMI in your application, which is only installed on newer operating systems and systems that have Internet Explorer 5 or higher installed.

I have a ready-to use WMI unit at http://www.workshop-alex.org/sources/WbemScripting_TLB/WbemScripting_TLB.html and http://www.workshop-alex.org/sources/WbemScripting_TLB/WbemScripting_TLB.pas that can be used in Delphi 7. It won't add much overhead to your application, though. It's just a bit complicated when you start playing with it...
0
Wim ten BrinkSelf-employed developerCommented:
You don't need the ShellAPI unit. And some other units might be dropped too. I think you do need the Windows, SysUtils and ActiveX units, though. Above code snippet originates from a simple WMI test applicatiuon that I'm playing with, and I added above code about half an hour ago. :-) (And checked that it works!)
0
tdk_manAuthor Commented:
You certainly know your onions Alex!

I'm only a vey minor league programmer and to be honest, you lost me after        

 Locator :=    

:)

I didn't want anyone to go to absolutely *any* lengths to find a solution - I was just after a quick kludge to have a bit of code executed only when the IDE isn't running, (I hoped anyway).

This I'm afraid is from my old GFA days where you could put a single conditional statement  allowing code to be temporarily disabled in non-compiled code (or vice-versa).

When the solution gets that technical, you have to wonder whether it's worth all the effort you have obviously put into it just to solve a rather trivial problem - ie me being rather lazy! :)

"There's no easy way to do it" would have shut me up.

TDK_Man
0
gwalkeriqCommented:
Try the DebugHook <> 0 test then and if you're happy with the result close the question. I use this all the time and it serves my purposes well to fill in magic passwords or popup debug messages, etc. -- it does not get simpler than this.
0
Wim ten BrinkSelf-employed developerCommented:
@qwalkeriq, sure, use of the debughook is useful and has been suggested before. But it's not perfect, since the application could be run from the IDE without the debugger being attached in which case the screen will get messed up again.

@tdk_man, well... The solution does it's work so you could try to include it in your source. It's not really that difficult either, as long as you remember that WMI is just some kind of database with your whole Windows configuration inside. It contains the funniest stuff, all kinds of performance counters and anything else you might be interested in. It's just a bit difficult to get the right code to make it work. :-)
Basically, what I just do is connect to the WMI database and execute a query twice. First to find the current process using the GetCurrentProcessID API so I can determine the parent process. Then I use the same query to find the parent process so I can check it's name. If the name happens to contain the Delphi executable name then I know it's started from Delphi. This code could actually be used to make sure your application is executed from the right process. You could, for example, create an executable that could only be started from another of your applications. All you have to do is check for the name of that other process.

What I've done with WMI is probably also possible by using some other API techniques but those would be really complicated. I just execute two queries on the WMI database... :-)

And personally, as an experienced Delphi developer who "knows his onions" I don't think it's a complex solution. Then again, I'm already deep into this WMI stuff for the last 3, 4 years...
0
Wim ten BrinkSelf-employed developerCommented:
Oh, what the heck... If you download that WbemScripting_TLB.pas file from my site and add the unit below too, then all you have to do is use the one and only function in this unit... I know the two additional units might make things seem more complicated, but they are ready-to-use solutions. ;-)

unit untCheckForDelphi;
interface
function IsRunFromDelphi: Boolean;
implementation
uses Windows, SysUtils, ActiveX, WbemScripting_TLB;
function IsRunFromDelphi: Boolean;
const
  sQuery = 'SELECT * FROM Win32_Process WHERE (ProcessId = "%s")';
var
  ExecutablePath: string;
  Item: SWbemObject;
  NumProp: LongWord;
  ObjectSet: ISWbemObjectSet;
  OleProperty: OleVariant;
  Query: WideString;
  Services: ISWbemServices;
begin
  Result := False;
  try
    Services := CoSWbemLocator.Create.ConnectServer( '', 'root\cimv2', '', '', '', '', 0, nil );
    Query := Format( sQuery, [ IntToStr( GetCurrentProcessId ) ] );
    ObjectSet := Services.ExecQuery( Query, 'WQL', wbemFlagBidirectional, nil );
    if Succeeded( ( ObjectSet._NewEnum as IEnumVariant ).Next( 1, OleProperty, NumProp ) ) and ( NumProp > 0 ) and Succeeded( IDispatch( OleProperty ).QueryInterface( SWBemObject, Item ) ) then begin
      Query := Format( sQuery, [ VarToStr( Item.Properties_.Item( 'ParentProcessId', 0 ) ) ] );
      ObjectSet := Services.ExecQuery( Query, 'WQL', wbemFlagBidirectional, nil );
      if Succeeded( ( ObjectSet._NewEnum as IEnumVariant ).Next( 1, OleProperty, NumProp ) ) and ( NumProp > 0 ) and Succeeded( IDispatch( OleProperty ).QueryInterface( SWBemObject, Item ) ) then begin
        ExecutablePath := VarToStr( Item.Properties_.Item( 'ExecutablePath', 0 ) );
        Result := ( pos( 'delphi32.exe', LowerCase( ExecutablePath ) ) > 0 )
      end;
    end;
  except Result := False;
  end;
end;
end.

Difficult? Using the function IsRunFromDelphi is all you need...
0
tdk_manAuthor Commented:
In my case, Molando's DebugHook suggestion worked perfectly - sorry for the delay in being able to test it BTW.

I accept that it may not work in 100% of situations, but in my particular case if it fails in the finished exe for example, the worst  that can happen is that the user will have to change screen rez before using it! That's not critical.

As such, I've gone for the DebugHook option because of it's simplicity.

Thanks for all the other suggestions though.

TDK_Man
0
Wim ten BrinkSelf-employed developerCommented:
Oh, don't worry. I just showed an interesting alternative way. I just wished I had mentioned the DebugHook option too but didn't consider it reliable enough. :-)
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.