[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 364
  • Last Modified:

To RLibby > The Autologin project we discussed

Hi Russell! Well this is it.

Regards Peter!



unit Main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls,SHDocvw, StdCtrls,GhostApp, Buttons, ComCtrls, Wininet,
  jpeg;

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    Image1: TImage;
    GhostApp1: TGhostApp;
    SpeedButton1: TSpeedButton;
    ProgressBar1: TProgressBar;
    Timer2: TTimer;
    Label1: TLabel;
    Timer3: TTimer;
    edtURL: TEdit;
    edtUserName: TEdit;
    edtPassword: TEdit;
    edtButton: TEdit;
    procedure FormCreate(Sender: TObject);
    function Go1: Boolean;
  //  function Connected: boolean;
    procedure Timer1Timer(Sender: TObject);
    procedure SpeedButton1Click(Sender: TObject);
    procedure Timer2Timer(Sender: TObject);
    procedure Timer3Timer(Sender: TObject);

  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
 function GetOnlineStatus : Boolean;
implementation

{$R *.dfm}

uses mshtml_tlb, Shellapi;



function TForm1.Go1:boolean;
var
  ShellWindow: IShellWindows;
  WB: IWebbrowser2;
  spDisp: IDispatch;
  IDoc1: IHTMLDocument2;
  Document: Variant;
  k, m: Integer;
  ovElements: OleVariant;
  i: Integer;
begin
result:=false; //assume no go

 ShellWindow := CoShellWindows.Create;
  // get the running instance of Internet Explorer
  for k := 0 to ShellWindow.Count do
  begin
    spDisp := ShellWindow.Item(k);
    if spDisp = nil then Continue;
    // QueryInterface determines if an interface can be used with an object
    spDisp.QueryInterface(iWebBrowser2, WB);
    if WB <> nil then
    begin try

      WB.Document.QueryInterface(IHTMLDocument2, iDoc1);
      except
      end;
      if iDoc1 <> nil then
      begin
        WB := ShellWindow.Item(k) as IWebbrowser2;
        begin
          Document := WB.Document;
          // count forms on document and iterate through its forms
          for m := 0 to Document.forms.Length - 1 do
          begin
            ovElements := Document.forms.Item(m).elements;
            // iterate through elements
            for i := 0 to ovElements.Length - 1 do
            begin
              // when input fieldname is found, try to fill out
              try
                if (CompareText(ovElements.item(i).tagName, 'INPUT') = 0) and
                  (CompareText(ovElements.item(i).type, 'text') = 0) then
                begin
                  ovElements.item(i).Value := edtUserName.Text;
                end;
              except
              end;
              try
                if (CompareText(ovElements.item(i).tagName, 'INPUT') = 0) and
                  (CompareText(ovElements.item(i).type, 'password') = 0) then
                begin
                  ovElements.item(i).Value := edtPassword.Text;
                end;
              except
              end;
              // when Submit button is found, try to click
              try
                if (CompareText(ovElements.item(i).tagName, 'INPUT') = 0) and
                  (CompareText(ovElements.item(i).type, 'SUBMIT') = 0) and
                  (ovElements.item(i).Value = edtButton.Text) then  
                begin
                  ovElements.item(i).Click;
                  result:=true; // we're a go!

                end;
              except
              end;
            end;
          end;
        end;
      end;
    end;
  end;
end;

 


procedure TForm1.FormCreate(Sender: TObject);
    var
  AStyle: Cardinal;
begin
AStyle := GetWindowLong(Application.Handle,GWL_EXSTYLE);
SetWindowLong(Application.Handle,GWL_EXSTYLE, AStyle or WS_EX_TOOLWINDOW);
label1.Caption := 'Connecting';
ShellExecute(HANDLE,
    'open',
    PChar(edtURL.Text),
    nil,
    nil,
    SW_SHOW);
    Timer1.Enabled := true;
end;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
Timer1.Enabled := False;
 label1.Caption := 'Logging in';

If Go1 then
Timer2.Enabled := True
else begin
label1.caption := 'Failure';
Timer3.Enabled := true;
end;
end;

procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
Application.Terminate;
end;

procedure TForm1.Timer2Timer(Sender: TObject);
begin
Timer2.Enabled := false;
Progressbar1.Position := 100;
Label1.Caption := 'Logged in';
Timer3.Enabled := true;
end;

procedure TForm1.Timer3Timer(Sender: TObject);
begin
Timer3.Enabled := False;
Close;
end;

end.

Ps let me know if you need more points ok?
0
PeterdeB
Asked:
PeterdeB
  • 6
  • 4
1 Solution
 
PeterdeBAuthor Commented:
The function GetOnlineStatus can be cut out > I already did that but apparently not all.

Regards,

Peter
0
 
Russell LibbySoftware Engineer, Advisory Commented:
This should address most of the issues you are running into.

usage is simple (simple is good <g>)
example use:

  with TAutoLogin.Create do
  begin
     // Load page - will return when loaded, failed, or time out value is set
     if LoadPage('http://www.experts-exchange.com/') then
     begin
        // Login to page
        if Login('foo', 'bar') then
           MessageBox(Application.Handle, 'Logged in', nil, MB_OK or MB_TOPMOST or MB_SETFOREGROUND)
        else
           MessageBox(Application.Handle, 'Failed login', nil, MB_OK or MB_TOPMOST or MB_SETFOREGROUND);
     end
     else
        MessageBox(Application.Handle, 'Not Loaded', nil, MB_OK or MB_TOPMOST or MB_SETFOREGROUND);
     // Close window
     Close;
     // Free object
     Free;
  end;


SOurce code follows.

Let me know if you have any problems
RUssell


unit AutoLogin;
////////////////////////////////////////////////////////////////////////////////
//
//   Unit        :  AUTOLOGIN
//   Date        :  12.01.2004
//   Authors     :  rllibby
//                  PeterdeB
//                  Carzzkiss
//
//   Description :  Provides an automated login mechanism for IE hosted web
//                  pages.
//
////////////////////////////////////////////////////////////////////////////////
interface

////////////////////////////////////////////////////////////////////////////////
//   Conditional Defines
////////////////////////////////////////////////////////////////////////////////
{$IFDEF VER130}
  {$DEFINE D5}
{$ENDIF}

////////////////////////////////////////////////////////////////////////////////
//   Include Units
////////////////////////////////////////////////////////////////////////////////
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ActiveX, ComObj, SHDocVw, WinInet, ie_events {$IFNDEF D5}, Variants {$ENDIF};

////////////////////////////////////////////////////////////////////////////////
//   AutoLogin Class
////////////////////////////////////////////////////////////////////////////////
type
  TAutoLogin        =  class(TObject)
  private
     // Private declarations
     FTracking:     IDispatch;
     FServerEvents: TIEEvents;
     FMaxWait:      Integer;
     FDelay:        Integer;
     FLoaded:       Boolean;
     FCancelled:    Boolean;
  protected
     // Protected declarations
     procedure      OnNavigateStart(Sender: TObject; const pDisp: IDispatch; var URL: OleVariant; var Flags: OleVariant; var TargetFrameName: OleVariant; var PostData: OleVariant; var Headers: OleVariant; var Cancel: WordBool);
     procedure      OnServerNavigate(Sender: TObject; const pDisp: IDispatch; var URL: OleVariant);
     procedure      OnServerComplete(Sender: TObject; const pDisp: IDispatch; var URL: OleVariant);
     procedure      OnServerQuit(Sender: TObject);
     procedure      Navigate(URL: String);
  public
     // Public declarations
     constructor    Create;
     destructor     Destroy; override;
     procedure      Close;
     function       LoadPage(Page: String): Boolean;
     function       CanLogin: Boolean;
     function       Login(UserID: String; Password: String): Boolean;
     property       Cancelled: Boolean read FCancelled;
     property       MaxWaitTime: Integer read FMaxWait write FMaxWait;
     property       RedirectDelayCheck: Integer read FDelay write FDelay;
  end;

implementation

procedure TAutoLogin.Close;
begin

  // Check to see if connected
  if FServerEvents.Connected then
  begin
     // Quit
     FServerEvents.Source.Quit;
     // Disconnect
     FServerEvents.Disconnect;
  end;

end;

function TAutoLogin.CanLogin: Boolean;
var  ovDocument:    OleVariant;
     ovElement:     OleVariant;
     ovInput:       OleVariant;
     ovPassword:    OleVariant;
     ovSubmit:      OleVariant;
     dwFrames:      Integer;
     dwIndex:       Integer;
begin

  // Set default result
  result:=False;

  // Must be connected
  if FServerEvents.Connected then
  begin
     // Make sure it is ready
     if not(FServerEvents.Source.Offline) and (FServerEvents.Source.ReadyState = READYSTATE_COMPLETE) then
     begin
        // Check for elements in page
        if Assigned(FServerEvents.Source.Document) then
        begin
           // Set defaults
           ovInput:=Unassigned;
           ovPassword:=Unassigned;
           ovSubmit:=Unassigned;
           // Get the document object
           ovDocument:=FServerEvents.Source.Document;
           try
              // Walk the frames
              for dwFrames:=0 to ovDocument.Forms.Length-1 do
              begin
                 // Walk elements
                 for dwIndex:=0 to ovDocument.Forms.Item(dwFrames).All.Length-1 do
                 begin
                    // Get element
                    ovElement:=ovDocument.Forms.Item(dwFrames).All.Item(dwIndex);
                    // Check input
                    if (CompareText(String(ovElement.tagName), 'input') = 0) then
                    begin
                       // Check input
                       if (CompareText(String(ovElement.Type), 'text') = 0) then
                          // Get input
                          ovInput:=ovElement
                       // Check password
                       else if (CompareText(String(ovElement.Type), 'password') = 0) then
                          // Set password
                          ovPassword:=ovElement
                       // Check for submit
                       else if (Pos(LowerCase('submit'), LowerCase(String(ovElement.Name))) > 0) then
                       begin
                          // Must be in the same context as user/password (eg, don't falsely pick up a search button)
                          if (VarType(ovInput) > varEmpty) and (VarType(ovPassword) > varEmpty) then
                          begin
                             // Have submit
                             ovSubmit:=ovElement;
                          end;
                       end;
                    end;
                    // Release element
                    ovElement:=Unassigned;
                    // Do we have all elements?
                    if (VarType(ovInput) > varEmpty) and
                       (VarType(ovPassword) > varEmpty) and
                       (VarType(ovSubmit) > varEmpty) then
                    begin
                       // We can login on this page
                       result:=True;
                       // Break
                       break;
                    end;
                 end;
                 // If success then break
                 if result then break;
              end;
           finally
              // Clear refs
              ovInput:=Unassigned;
              ovPassword:=Unassigned;
              ovSubmit:=Unassigned;
              ovDocument:=Unassigned;
           end;
        end;
     end;
  end;

end;

function TAutoLogin.Login(UserID: String; Password: String): Boolean;
var  ovDocument:    OleVariant;
     ovElement:     OleVariant;
     ovInput:       OleVariant;
     ovPassword:    OleVariant;
     ovSubmit:      OleVariant;
     dwMaxWait:     DWORD;
     dwFrames:      Integer;
     dwIndex:       Integer;
     bSubmit:       Boolean;
begin

  // Set default submit result
  bSubmit:=False;

  // Must be connected
  if FServerEvents.Connected then
  begin
     // Make sure it is ready
     if not(FServerEvents.Source.Offline) and (FServerEvents.Source.ReadyState = READYSTATE_COMPLETE) then
     begin
        // Check for elements in page
        if Assigned(FServerEvents.Source.Document) then
        begin
           // Set defaults
           ovInput:=Unassigned;
           ovPassword:=Unassigned;
           ovSubmit:=Unassigned;
           // Get the document object
           ovDocument:=FServerEvents.Source.Document;
           try
              // Walk the frames
              for dwFrames:=0 to ovDocument.Forms.Length-1 do
              begin
                 // Walk elements
                 for dwIndex:=0 to ovDocument.Forms.Item(dwFrames).All.Length-1 do
                 begin
                    // Get element
                    ovElement:=ovDocument.Forms.Item(dwFrames).All.Item(dwIndex);
                    // Check input
                    if (CompareText(String(ovElement.tagName), 'input') = 0) then
                    begin
                       // Check input
                       if (CompareText(String(ovElement.Type), 'text') = 0) then
                          // Get input
                          ovInput:=ovElement
                       // Check password
                       else if (CompareText(String(ovElement.Type), 'password') = 0) then
                          // Set password
                          ovPassword:=ovElement
                       // Check for submit
                       else if (Pos(LowerCase('submit'), LowerCase(String(ovElement.Name))) > 0) then
                       begin
                          // Must be in the same context as user/password (eg, don't falsely pick up a search button)
                          if (VarType(ovInput) > varEmpty) and (VarType(ovPassword) > varEmpty) then
                          begin
                             // Have submit
                             ovSubmit:=ovElement;
                          end;
                       end;
                    end;
                    // Release element
                    ovElement:=Unassigned;
                    // Do we have all elements?
                    if (VarType(ovInput) > varEmpty) and
                       (VarType(ovPassword) > varEmpty) and
                       (VarType(ovSubmit) > varEmpty) then
                    begin
                       // Submit
                       ovInput.Value:=UserID;
                       ovPassword.Value:=Password;
                       ovSubmit.Click;
                       // Set result
                       bSubmit:=True;
                       // Break
                       break;
                    end;
                 end;
                 // If success then break
                 if bSubmit then break;
              end;
           finally
              // Clear refs
              ovInput:=Unassigned;
              ovPassword:=Unassigned;
              ovSubmit:=Unassigned;
              ovDocument:=Unassigned;
           end;
        end;
     end;
  end;

  // Did we submit the data?
  if bSubmit then
  begin
     // Clear flags
     FLoaded:=False;
     FCancelled:=False;
     FTracking:=nil;
     // Get max wait time
     dwMaxWait:=GetTickCount + LongWord(FMaxWait);
     // While not loaded and not cancelled - wait
     while not(FLoaded) and not(FCancelled) and (dwMaxWait > GetTickCount) do Application.ProcessMessages;
     // Is the loaded state set?
     if (FLoaded and not(FCancelled)) then
        // Success if we can no longer login
        result:=not(CanLogin)
     else
        // Failed
        result:=False;
  end
  else
     // Failed to login
     result:=False;

end;

function TAutoLogin.LoadPage(Page: String): Boolean;
var  lpUrl:         TURLComponents;
     lpszHost:      Array [0..MAX_PATH] of Char;
     ovDocument:    OleVariant;
     ovLocation:    OleVariant;
     szProto:       String;
     szHost:        String;
begin

  // Set default result
  result:=False;

  // Display wait
  Screen.Cursor:=crHourglass;

  // Check protocol for page
  if (Pos('http://', LowerCase(Page)) = 0) and (Pos('https://', LowerCase(Page)) = 0) then
  begin
     // Prepend the http:// to the page
     Page:='http://'+Page;
  end;

  // Resource protection
  try
     // Navigate
     Navigate(Page);
     // Check state and page
     if FServerEvents.Connected then
     begin
        // Check the document
        if Assigned(FServerEvents.Source.Document) then
        begin
           // Access the document
           ovDocument:=FServerEvents.Source.Document;
           // Access the location
           ovLocation:=ovDocument.Location;
           try
              // Check the location information
              szProto:=ovLocation.Protocol;
              szHost:=ovLocation.Host;
              // Crack the URL name to make sure it matches up
              ZeroMemory(@lpUrl, SizeOf(TURLComponents));
              ZeroMemory(@lpszHost, SizeOf(lpszHost));
              lpUrl.dwStructSize:=SizeOf(TURLComponents);
              lpUrl.lpszHostName:=@lpszHost;
              lpUrl.dwHostNameLength:=MAX_PATH;
              if InternetCrackUrl(PChar(Page), 0, ICU_DECODE, lpUrl) then
                 // Check the host, protocol, offline state, and ready state
                 result:=(Pos('res:', szProto) = 0) and
                          not(FServerEvents.Source.Offline) and
                          (FServerEvents.Source.ReadyState = READYSTATE_COMPLETE) and
                          (CompareText(szHost, lpszHost) = 0)
              else
                 // Check the protocol, offline state, and ready state
                 result:=(Pos('res:', szProto) = 0) and
                          not(FServerEvents.Source.Offline) and
                          (FServerEvents.Source.ReadyState = READYSTATE_COMPLETE);
           finally
              // Clear interfaces
              ovLocation:=Unassigned;
              ovDocument:=Unassigned;
           end;
        end;
     end;
  finally
     // Restore the cursor state
     Screen.Cursor:=crDefault;
  end;

end;

procedure TAutoLogin.Navigate(URL: String);
var  ovURL:         OleVariant;
     dwMaxWait:     DWORD;
     dwWait:        DWORD;
begin

  // Clear flags
  FLoaded:=False;
  FCancelled:=False;
  FTracking:=nil;

  // Make sure that we have bound to an instance of IE
  if not(FServerEvents.Connected) then
  begin
     // Create an instance of IE to connect to
     FServerEvents.ConnectTo(CoInternetExplorer.Create);
  end;

  // Make sure we are connected
  if FServerEvents.Connected then
  begin
     // Make sure this is visible
     FServerEvents.Source.Visible:=True;
     // Convert the url to an ole variant
     ovURL:=URL;
     // Navigate to the page
     FServerEvents.Source.Navigate2(ovURL, EmptyParam, EmptyParam, EmptyParam, EmptyParam);
     // Get max wait time
     dwMaxWait:=GetTickCount + LongWord(FMaxWait);
     // While not loaded and not cancelled - wait
     while not(FLoaded) and not(FCancelled) and (dwMaxWait > GetTickCount) do Application.ProcessMessages;
     // Is the loaded state set?
     if (FLoaded and not(FCancelled)) then
     begin
        // Set total time to wait
        dwWait:=GetTickCount + LongWord(FDelay);
        // Delay to check for redirect firing off
        while not(FCancelled) and (dwWait > GetTickCount) and (dwMaxWait > GetTickCount) do
        begin
           // Spin loop
           Application.ProcessMessages;
           // If loaded got toggled off then we can safely leave
           if not(FLoaded) then break;
        end;
        // Loop if the flag was turned off
        while not(FLoaded) and not(FCancelled) and (dwMaxWait > GetTickCount) do Application.ProcessMessages;
     end;
  end;

end;

procedure TAutoLogin.OnNavigateStart(Sender: TObject; const pDisp: IDispatch; var URL: OleVariant; var Flags: OleVariant; var TargetFrameName: OleVariant; var PostData: OleVariant; var Headers: OleVariant; var Cancel: WordBool);
begin

  // Clear flags
  FLoaded:=False;
  FCancelled:=False;
  FTracking:=nil;

end;

procedure TAutoLogin.OnServerNavigate(Sender: TObject; const pDisp: IDispatch; var URL: OleVariant);
begin

  // If tracking interface is nil then this is the top level frame
  if (FTracking = nil) then FTracking:=pDisp;

end;

procedure TAutoLogin.OnServerComplete(Sender: TObject; const pDisp: IDispatch; var URL: OleVariant);
begin

  // Compare against the tracking interface
  if Assigned(FTracking) and (FTracking = pDisp) then
  begin
     // Document is fully loaded
     FLoaded:=True;
  end;

end;

procedure TAutoLogin.OnServerQuit(Sender: TObject);
begin

  // Set the cancelled flag
  FCancelled:=True;

end;

constructor TAutoLogin.Create;
begin

  // Perform inherited
  inherited Create;

  // Default max wait time, and default delay to check for a redirection after a page has loaded
  FMaxWait:=10000;
  FDelay:=2000;

  // Clear tracking variables
  FLoaded:=False;
  FCancelled:=False;
  FTracking:=nil;

  // Create IE event interface
  FServerEvents:=TIEEvents.Create(Application.MainForm);

  // Bind the event handlers
  FServerEvents.BeforeNavigate2:=OnNavigateStart;
  FServerEvents.DocumentComplete:=OnServerComplete;
  FServerEvents.NavigateComplete2:=OnServerNavigate;
  FServerEvents.OnQuit:=OnServerQuit;

end;

destructor TAutoLogin.Destroy;
begin

  // Make sure all interfaces are cleared
  FTracking:=nil;

  // Release the server event handler
  FServerEvents.Free;

  // Perform inherited
  inherited Destroy;

end;

end.
0
 
PeterdeBAuthor Commented:
WOW!!! Just got outta bed and have to leave for now but after I get home I'll fire up Delphi cause I can hardly wait to test this code!!!

Max respect and admiration from somewhere overseas in Holland!! I will get back to you Mister!!!

Paul
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
Russell LibbySoftware Engineer, Advisory Commented:
No problem, and no rush.

----
I also forgot to explain a few of the properties/methods, so I will do that now.

1.) MaxWaitTime (r/w integer prop)

Determines the total time allowed for logging in, set in ms. Defaults to 10000 (10 seconds)

2.) RedirectDelayCheck (r/w integer prop)

During testing, I used some sites where I specified the home page, but got redirected to another page (the login page). In order to correctly handle the loading, I introduced the RedirectDelayCheck. What happens is this: once the page is completed, the program will delay for the amount of time specified by RedirectDelayCheck. If no new navigation is started, then the program continues. If a new navigation DOES start though, then the loaded state will get cleared and we will wait for the redirect page to finish loading. Defaults to 2000 ms (2 seconds). Again, this is only the amount of time we will wait for a NEW navigation to start. The time allowed for the page loading is determined by MaxWaitTime.

3.) procedure Close;

Closes the connected IE window.

4.) function  LoadPage(Page: String): Boolean;

Loads the specified page. A few checks are done to determine the "loaded" state.
 -  Protocol returned from page cannot be res://, which would mean an error occurred and IE loaded a page from a local dll.
 -  Browser cannot be offline
 -  Browser's ReadyState must be set to READYSTATE_COMPLETE
 - The host name returned from the document interface must match the host name specified in the URL that we loaded. (Uses InternetCrackURL to get this info out).

5.) function CanLogin: Boolean;

Determines if a page is loaded that allows for logging in.

6.) function Login(UserID: String; Password: String): Boolean;

Login to the currently loaded page using userid/password. Currently this function waits for the login process to complete, and then determines success by ensuring that the user can no longer login. This could be changed if needed. Side note: Its hard to determine when a login is successful because a page is always returned, and its only the contents of the page that determine if the login was successful or not.

7.) Cancelled (r boolean prop)

Determines if the last operation was cancelled by the user closing the IE window.

-----


Kind regards,
Russell
0
 
PeterdeBAuthor Commented:
I-T W-O-R-K-SSSSSS!! :)

Perfect! I replaced the logged in messagebox with form1.close so it 'disappears' right after its logged in > does that need more modification then simply replacing the messagebox code with form1.close? I ask this because all seems well and okay after I did that and ran the app. In fact the app got me here at EE just a second ago but perhaps you see things or problems I don't.

Regards and rewards ofcourse!! Creating an autologin app now consists of including the autologin app and drop app 10 lines of code et voila we're surfin and logging in! Some friends of mine asked me for an autologin app just to login to our forum and I now have some great news for them but in particular its great news for me since it wont take me that long to help them out even if all the members of the forum would (kindly:)) ask me for it!

Brilliant!

Thanks my friend for the effort you put into solving this matter in a professional way!

Paul
0
 
Russell LibbySoftware Engineer, Advisory Commented:
Paul,
You are most welcome, of course.

Regarding the demo; I put the messageboxes in there just for demo/display purposes only. You can close the form, or do whatever you need to do (it should not affect anything).  In fact, your code could be as simple as 6 lines.

with TAutoLogin.Create do
begin
   if LoadPage('http://www.experts-exchange.com/') then Login('foo', 'bar');
   Close;
   Free;
end;

which is the primary reason I placed the code within an object; it encapsulates the logic, requiring the programmer using this to know the absolute minimum in order to get this thing to work. And having source with this, you (or others) could modify this to do whatever else was needed.

Anyways, I am pleased that you are satisfied, because thats what really counts (and why most of us here donate our time to EE)

Happy surfing, and best regards,
Russell


0
 
PeterdeBAuthor Commented:
Hi Russell!

Just returned from some pc-repair-jobs some of my friends were struggling with. It's amazing to see your work I'm impressed to say the least. Although I thought I understood the main reason you 'placed the code within an object' I now come to understand what those words actually mean and I think this understanding is caused by the fact I've experienced exactly what you stated since I got lost easily in the code you posted.

My regards!

Paul
0
 
PeterdeBAuthor Commented:
Hi Russell!

In the project Wayne sent, you created the controls at run time. What is the advantage of this technique in regard to not creating them at run time?

My regards,

Paul
0
 
Russell LibbySoftware Engineer, Advisory Commented:

Paul,

The only advantage was that it made a demo simpler, as there were less steps for the person asking the question to follow (like adding a button to the form, set the event handlers, add an edit control, etc, etc, etc).

The format here on EE is great for sharing code clips, but somewhat limiting when trying to demonstrate/share full projects that include form files.

Regards,
Russell


0
 
PeterdeBAuthor Commented:
Oh okay I see thanks for your explanation!

My regards and max respect!

Paul
0

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

  • 6
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now