Link to home
Start Free TrialLog in
Avatar of pivar
pivarFlag for Sweden

asked on

Checking for designtime without ComponentState

Hi,

Is it possible to check for designtime without using the ComponentState property?

Thanks,

/pivar
Avatar of DaFox
DaFox

Hi pivar.

Why don't you want to use the ComponentState property??

Solution:
Use FindWindow() to look for a window classname "TAppWindow". If you succeed use GetWindowThreadProcessID() and compare it to GetCurrentProcessID(). If they are the same the code is running in the context of the IDE process.
If you run it hitting F9 your program runs in a separate process and it'll return false. ;-)

Markus
is it called TAppWindow? I remember (and to be sure I looked with WinSight) TAppBuilder. anyway that's not good idea to check for designtime.
if your app contains forms or datamodules you can use this function:

// uses Screen variable, but that requires Forms in uses.
function IsDesignTime: boolean;
begin
  if Screen.FormCount > 0 then
    Result := csDesigning in Screen.Forms[0].ComponentState
  else
    if Screen.DataModuleCount > 0 then
      Result := csDesigning in Screen.DataModules[0].ComponentState
    else
      Result := False;
end;

wbr, mo.
Hi mocarts.

> anyway that's not good idea to check for designtime

That's why I asked pivar why he does not want to use the "normal" ComponentState way. But it's reliable and I can't think of bad side effects atm.

> is it called TAppWindow? I remember (and to be sure I looked with WinSight) TAppBuilder

Don't know exactly. I don't have access to my Delphi atm :(

Markus
Avatar of pivar

ASKER

Thanks for your replies,

The background is that I have a function that is called by several different components, recent changes make me have to check for designtime in this function. I don't want to check ComponentState in the component before calling the function since this I do this in a lot of places and it will give me a lot of work. Nor do I want to send the component in every function-call for the same reason.

I've tested both solutions and I can't get neither to work.

Markus, there is no window called "TAppWindow" (in D5 anyway), but there is a "TAppBuilder". But I receive different process ids from GetWindowThreadProcessID and GetCurrentProcessID, so this return false.

Mocarts, I do have Forms and DataModules (both Counts are > 0) but Screen.Forms[0].ComponentState does not hold csDesigning, but ComponentState in the component from where I call the function holds csDesigning!

/pivar
Sorry, you have to get the parent pid.

Use:

// NT
function GetParentProcessIDForNT: Integer;
var
  hNTDLL: Integer;
  NtQueryInformationProcess: TNtQueryInformationProcess;
  PBI: TProcessBasicInformation;
  ReturnLength: Integer;
begin
  Result := 0;
  // Attempt to load NTDLL
  hNTDLL := LoadLibrary('NTDLL.DLL');
  if hNTDLL <> 0 then
  begin
    // Retrieve address of NtQueryInformationProcess
    NtQueryInformationProcess := GetProcAddress(hNTDLL,
'NtQueryInformationProcess');
    if Assigned(NTQueryInformationProcess) then
    begin
      // Call NtQueryInformationProcess
      NtQueryInformationProcess(GetCurrentProcess,
ProcessBasicInformation,
        PBI, SizeOf(PBI), ReturnLength);
      // Return parent process ID
      Result := PBI.InheritedFromUniqueProcessID;
    end;
    // Release NTDLL
    FreeLibrary(hNTDLL);
  end;
end;

// 9x, ME, 2000, XP
function GetParentProcessIDForWindows: Integer;
var
  Kernel32: THandle;
  CreateToolhelp32Snapshot: TCreateToolhelp32Snapshot;
  Process32First: TProcess32First;
  Process32Next: TProcess32Next;
  Snapshot: THandle;
  Entry: TProcessEntry32;
  WalkResult: Boolean;
  ID: ULONG;
begin
  Result := 0;
  // Attempt to load KERNEL32
  Kernel32 := LoadLibrary('KERNEL32.DLL');
  if Kernel32 <> 0 then
  begin
    // Retrieve ToolHelp32 function addresses
    CreateToolhelp32Snapshot :=
      GetProcAddress(Kernel32, 'CreateToolhelp32Snapshot');
    Process32First := GetProcAddress(Kernel32, 'Process32First');
    Process32Next := GetProcAddress(Kernel32, 'Process32Next');
    if Assigned(CreateToolhelp32Snapshot) and
       Assigned(Process32First) and
       Assigned(Process32Next) then
    begin
      // Retrieve current process ID for comparison
      ID := GetCurrentProcessId;
      // Create processes snapshot
      Snapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
      if Integer(Snapshot) <> -1 then
      begin
        // Start walking list of processes
        Entry.dwSize := SizeOf(TProcessEntry32);
        WalkResult := Process32First(Snapshot, Entry);
        // Walk through entire list until result can be determined
        while (GetLastError <> ERROR_NO_MORE_FILES) and (Result = 0)
do
        begin
          if WalkResult then
          begin
            // If this is the current process, return its parent
            if Entry.th32ProcessID = ID then
              Result := Entry.th32ParentProcessID;
          end;
          // Move to next item in the process list
          Entry.dwSize := SizeOf(TProcessEntry32);
          WalkResult := Process32Next(Snapshot, Entry);
        end;
        // Release handle to the snapshot
        CloseHandle(Snapshot);
      end;
    end;
    // Release KERNEL32
    FreeLibrary(Kernel32);
  end;
end;

Markus
BTW:

1. > Nor do I want to send the component in every function-call for the same reason.

What about a global var?

2. You're right, it's called "TAppBuilder"

Markus
how about to check Application.ExeName?
in designtime it is delphi32.exe..
you can additionaly compare Application.ExeName against Module name where component resides.

interface
...
var
  IsDesignTime: boolean = False;

implementation

// copied from sysutils (not exported)
function GetModuleName(Module: HMODULE): string;
var
  ModName: array[0..MAX_PATH] of Char;
begin
  SetString(Result, ModName, Windows.GetModuleFileName(Module, ModName, SizeOf(ModName)));
end;

initialization
  IsDesignTime := SameText(ExtractFileName(Application.ExeName), 'delphi32.exe');
  // or
  //IsDesignTime := not SameText(GetModuleName(HInstance), Application.ExeName);

end.
I just read on the net that this is another possibily:


var
  bDesigning:boolean;
initialization
  bDesigning := assigned(Application.MainForm) and Application.MainForm.Name='AppBuilder');


(never did that though ;-)

Markus
Avatar of pivar

ASKER

Thanks for all replies,

I will use Markus last suggestion. But I don't know if we should split the points, or? I think Mocarts suggestion was on the same level as Markus, but uses a little more overhead.

What do you think?

/pivar
ASKER CERTIFIED SOLUTION
Avatar of DaFox
DaFox

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I don't mind. but DaFox presented here more advanced tehniques :) so you can give him more points :)

there is no overhead in my example - you don't need this GetModuleName if you use uncommented code:

initialization
 IsDesignTime := SameText(ExtractFileName(Application.ExeName), 'delphi32.exe');

that's all. and this is the same as checking for MainForm.Name

wbr, mo.
Avatar of pivar

ASKER

Hi again,

Since I think both answers should be rewarded I also submit a question with 250 points for mocarts.

Thanks,

/pivar