Subversion Repositories fastphp

Rev

Rev 70 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 70 Rev 91
1
unit RunPHP;
1
unit RunPHP;
2
 
2
 
3
interface
3
interface
4
 
4
 
5
uses
5
uses
6
  SysUtils, Forms, Classes, Windows;
6
  SysUtils, Forms, Classes, Windows;
7
 
7
 
8
type
8
type
9
  TInputRequestCallback = function(var data: AnsiString): boolean of object;
9
  TInputRequestCallback = function(var data: AnsiString): boolean of object;
10
  TOutputNotifyCallback = function(const output: AnsiString): boolean of object;
10
  TOutputNotifyCallback = function(const output: AnsiString): boolean of object;
11
  TRunCodeExplorer = class(TThread)
11
  TRunCodeExplorer = class(TThread)
12
  private
12
  private
13
    FInputRequestCallback: TInputRequestCallback;
13
    FInputRequestCallback: TInputRequestCallback;
14
    FOutputNotifyCallback: TOutputNotifyCallback;
14
    FOutputNotifyCallback: TOutputNotifyCallback;
15
    FInputWaiting: AnsiString;
15
    FInputWaiting: AnsiString;
16
    FInputWasSuccessful: boolean;
16
    FInputWasSuccessful: boolean;
17
    FOutputWaiting: AnsiString;
17
    FOutputWaiting: AnsiString;
18
    FOutputWasSuccessful: boolean;
18
    FOutputWasSuccessful: boolean;
19
  protected
19
  protected
20
    procedure CallInputRequestCallback;
20
    procedure CallInputRequestCallback;
21
    procedure CallOutputNotifyCallback;
21
    procedure CallOutputNotifyCallback;
22
  public
22
  public
23
    PhpExe: string;
23
    PhpExe: string;
24
    PhpFile: string;
24
    PhpFile: string;
25
    WorkDir: string;
25
    WorkDir: string;
26
    property InputRequestCallback: TInputRequestCallback read FInputRequestCallback write FInputRequestCallback;
26
    property InputRequestCallback: TInputRequestCallback read FInputRequestCallback write FInputRequestCallback;
27
    property OutputNotifyCallback: TOutputNotifyCallback read FOutputNotifyCallback write FOutputNotifyCallback;
27
    property OutputNotifyCallback: TOutputNotifyCallback read FOutputNotifyCallback write FOutputNotifyCallback;
28
    procedure Execute; override;
28
    procedure Execute; override;
29
  end;
29
  end;
30
 
30
 
31
implementation
31
implementation
32
 
32
 
33
procedure TRunCodeExplorer.Execute;
33
procedure TRunCodeExplorer.Execute;
34
 
34
 
35
  function ProcessRunning(PI: TProcessInformation): boolean; inline;
35
  function ProcessRunning(PI: TProcessInformation): boolean; inline;
36
  var
36
  var
37
    exitcode: Cardinal;
37
    exitcode: Cardinal;
38
  begin
38
  begin
39
    result := GetExitCodeProcess(PI.hProcess, exitcode) and (exitcode = STILL_ACTIVE);
39
    result := GetExitCodeProcess(PI.hProcess, exitcode) and (exitcode = STILL_ACTIVE);
40
  end;
40
  end;
41
 
41
 
42
var
42
var
43
  SA: TSecurityAttributes;
43
  SA: TSecurityAttributes;
44
  SI: TStartupInfo;
44
  SI: TStartupInfo;
45
  PI: TProcessInformation;
45
  PI: TProcessInformation;
46
  StdOutPipeRead, StdOutPipeWrite: THandle;
46
  StdOutPipeRead, StdOutPipeWrite: THandle;
47
  StdInPipeRead, StdInPipeWrite: THandle;
47
  StdInPipeRead, StdInPipeWrite: THandle;
48
  WasOK: Boolean;
48
  WasOK: Boolean;
49
  Buffer: array[0..255] of AnsiChar;
49
  Buffer: array[0..255] of AnsiChar;
50
  BytesRead, BytesWritten: Cardinal;
50
  BytesRead, BytesWritten: Cardinal;
51
  WorkDir: string;
51
  WorkDir: string;
52
  Handle: Boolean;
52
  Handle: Boolean;
53
  testString: AnsiString;
53
  testString: AnsiString;
54
  Output, OutputLastCache: string;
54
  Output, OutputLastCache: string;
55
const
55
const
56
  SIGNAL_END_OF_TRANSMISSION = #1#2#3#4#5#6#7#8;
56
  SIGNAL_END_OF_TRANSMISSION = #1#2#3#4#5#6#7#8;
57
  SIGNAL_TERMINATE           = #8#7#6#5#4#3#2#1;
57
  SIGNAL_TERMINATE           = #8#7#6#5#4#3#2#1;
58
begin
58
begin
59
  if Self.WorkDir = '' then
59
  if Self.WorkDir = '' then
60
    WorkDir := ExtractFilePath(ParamStr(0))
60
    WorkDir := ExtractFilePath(ParamStr(0))
61
  else
61
  else
62
    WorkDir := Self.WorkDir;
62
    WorkDir := Self.WorkDir;
63
 
63
 
64
  if not FileExists(Self.PhpExe) then exit;
64
  if not FileExists(Self.PhpExe) then exit;
65
  if not FileExists(Self.PhpFile) then exit;
65
  if not FileExists(Self.PhpFile) then exit;
66
 
66
 
67
  Output := '';
67
  Output := '';
68
  OutputLastCache := '';
68
  OutputLastCache := '';
69
  with SA do begin
69
  with SA do begin
70
    nLength := SizeOf(SA);
70
    nLength := SizeOf(SA);
71
    bInheritHandle := True;
71
    bInheritHandle := True;
72
    lpSecurityDescriptor := nil;
72
    lpSecurityDescriptor := nil;
73
  end;
73
  end;
74
  CreatePipe(StdOutPipeRead, StdOutPipeWrite, @SA, 0);
74
  CreatePipe(StdOutPipeRead, StdOutPipeWrite, @SA, 0);
75
  CreatePipe(StdInPipeRead, StdInPipeWrite, @SA, 0);
75
  CreatePipe(StdInPipeRead, StdInPipeWrite, @SA, 0);
76
  try
76
  try
77
    with SI do
77
    with SI do
78
    begin
78
    begin
79
      FillChar(SI, SizeOf(SI), 0);
79
      FillChar(SI, SizeOf(SI), 0);
80
      cb := SizeOf(SI);
80
      cb := SizeOf(SI);
81
      dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
81
      dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
82
      wShowWindow := SW_HIDE;
82
      wShowWindow := SW_HIDE;
83
      hStdInput := StdInPipeRead;
83
      hStdInput := StdInPipeRead;
84
      hStdOutput := StdOutPipeWrite;
84
      hStdOutput := StdOutPipeWrite;
85
      hStdError := StdOutPipeWrite;
85
      hStdError := StdOutPipeWrite;
86
    end;
86
    end;
87
 
87
 
88
    Handle := CreateProcess(nil, PChar('"'+Self.PhpExe+'" -f "'+Self.PhpFile+'"'),
88
    Handle := CreateProcess(nil, PChar('"'+Self.PhpExe+'" -f "'+Self.PhpFile+'"'),
89
                            nil, nil, True, 0, nil, PChar(WorkDir), SI, PI);
89
                            nil, nil, True, 0, nil, PChar(WorkDir), SI, PI);
90
    CloseHandle(StdOutPipeWrite);
90
    CloseHandle(StdOutPipeWrite);
91
 
91
 
92
    sleep(100);
92
    sleep(100);
93
 
93
 
94
    if Handle then
94
    if Handle then
95
      try
95
      try
96
        while not Self.Terminated and ProcessRunning(PI) do
96
        while not Self.Terminated and ProcessRunning(PI) do
97
        begin
97
        begin
98
          {$REGION 'Get input from mainthread'}
98
          {$REGION 'Get input from mainthread'}
99
          if Assigned(FInputRequestCallback) then
99
          if Assigned(FInputRequestCallback) then
100
          begin
100
          begin
101
            Synchronize(CallInputRequestCallback);
101
            Synchronize(CallInputRequestCallback);
102
 
102
 
103
            if not FInputWasSuccessful then
103
            if not FInputWasSuccessful then
104
            begin
104
            begin
105
              Sleep(100);
105
              Sleep(100);
106
              continue;
106
              continue;
107
            end;
107
            end;
108
 
108
 
109
            // Attention: This call will block if the process exited
109
            // Attention: This call will block if the process exited
110
            WriteFile(StdInPipeWrite, FInputWaiting[1], Length(FInputWaiting), BytesWritten, nil);
110
            WriteFile(StdInPipeWrite, FInputWaiting[1], Length(FInputWaiting), BytesWritten, nil);
111
          end;
111
          end;
112
          {$ENDREGION}
112
          {$ENDREGION}
113
 
113
 
114
          {$REGION 'Terminate input sequence'}
114
          {$REGION 'Terminate input sequence'}
115
          testString := #13#10+SIGNAL_END_OF_TRANSMISSION+#13#10;
115
          testString := #13#10+SIGNAL_END_OF_TRANSMISSION+#13#10;
116
          WriteFile(StdInPipeWrite, testString[1], Length(testString), BytesWritten, nil);
116
          WriteFile(StdInPipeWrite, testString[1], Length(testString), BytesWritten, nil);
117
          {$ENDREGION}
117
          {$ENDREGION}
118
 
118
 
119
          {$REGION 'Gather output'}
119
          {$REGION 'Gather output'}
120
          Output := '';
120
          Output := '';
121
          repeat
121
          repeat
122
            WasOK := ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil);
122
            WasOK := ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil);
123
            if BytesRead > 0 then
123
            if BytesRead > 0 then
124
            begin
124
            begin
125
              Buffer[BytesRead] := #0;
125
              Buffer[BytesRead] := #0;
126
              Output := Output + Buffer;
126
              Output := Output + string(Buffer);
127
              if Pos(SIGNAL_END_OF_TRANSMISSION, Output) >= 1 then
127
              if Pos(SIGNAL_END_OF_TRANSMISSION, Output) >= 1 then
128
              begin
128
              begin
129
                Output := StringReplace(Output, SIGNAL_END_OF_TRANSMISSION, '', []);
129
                Output := StringReplace(Output, SIGNAL_END_OF_TRANSMISSION, '', []);
130
                break;
130
                break;
131
              end;
131
              end;
132
            end;
132
            end;
133
          until not WasOK or (BytesRead = 0) or Self.Terminated or not ProcessRunning(PI);
133
          until not WasOK or (BytesRead = 0) or Self.Terminated or not ProcessRunning(PI);
134
          {$ENDREGION}
134
          {$ENDREGION}
135
 
135
 
136
          {$REGION 'Notify main thread about output'}
136
          {$REGION 'Notify main thread about output'}
137
          if Assigned(FOutputNotifyCallback) and (OutputLastCache <> Output) and not Self.Terminated and ProcessRunning(PI) then
137
          if Assigned(FOutputNotifyCallback) and (OutputLastCache <> Output) and not Self.Terminated and ProcessRunning(PI) then
138
          begin
138
          begin
139
            FOutputWaiting := Output;
139
            FOutputWaiting := Output;
140
            Synchronize(CallOutputNotifyCallback);
140
            Synchronize(CallOutputNotifyCallback);
141
            if FOutputWasSuccessful then
141
            if FOutputWasSuccessful then
142
            begin
142
            begin
143
              OutputLastCache := Output;
143
              OutputLastCache := Output;
144
            end;
144
            end;
145
          end;
145
          end;
146
          {$ENDREGION}
146
          {$ENDREGION}
147
        end;
147
        end;
148
 
148
 
149
        // Signal the code explorer to terminate
149
        // Signal the code explorer to terminate
150
        (*
150
        (*
151
        testString := #13#10+SIGNAL_TERMINATE+#13#10;
151
        testString := #13#10+SIGNAL_TERMINATE+#13#10;
152
        WriteFile(StdInPipeWrite, testString[1], Length(testString), BytesWritten, nil);
152
        WriteFile(StdInPipeWrite, testString[1], Length(testString), BytesWritten, nil);
153
        WaitForSingleObject(PI.hProcess, INFINITE);
153
        WaitForSingleObject(PI.hProcess, INFINITE);
154
        *)
154
        *)
155
        TerminateProcess(Pi.hProcess, 0);
155
        TerminateProcess(Pi.hProcess, 0);
156
 
156
 
157
        CloseHandle(StdInPipeWrite);
157
        CloseHandle(StdInPipeWrite);
158
      finally
158
      finally
159
        CloseHandle(PI.hThread);
159
        CloseHandle(PI.hThread);
160
        CloseHandle(PI.hProcess);
160
        CloseHandle(PI.hProcess);
161
      end;
161
      end;
162
  finally
162
  finally
163
    CloseHandle(StdOutPipeRead);
163
    CloseHandle(StdOutPipeRead);
164
    CloseHandle(StdInPipeRead);
164
    CloseHandle(StdInPipeRead);
165
  end;
165
  end;
166
end;
166
end;
167
 
167
 
168
{synchron} procedure TRunCodeExplorer.CallInputRequestCallback;
168
{synchron} procedure TRunCodeExplorer.CallInputRequestCallback;
169
begin
169
begin
170
  FInputWasSuccessful := FInputRequestCallback(FInputWaiting);
170
  FInputWasSuccessful := FInputRequestCallback(FInputWaiting);
171
end;
171
end;
172
 
172
 
173
{synchron} procedure TRunCodeExplorer.CallOutputNotifyCallback;
173
{synchron} procedure TRunCodeExplorer.CallOutputNotifyCallback;
174
begin
174
begin
175
  FOutputWasSuccessful := FOutputNotifyCallback(FOutputWaiting);
175
  FOutputWasSuccessful := FOutputNotifyCallback(FOutputWaiting);
176
end;
176
end;
177
 
177
 
178
end.
178
end.
179
 
179