Solved

function to read the column headers of the outlook express main window

Posted on 2006-07-12
5
364 Views
Last Modified: 2010-04-05
hello there,

i have the following problem.


when i open outlook express i need to read the name of all the visible columns that exist in the current view of
 the OE window.

for example if you go

1)menu option "view"->"columns" and check only the "subject" and the "received" column are visible in the main OE window. i need a function that will return me the names "subject-received"

thanks a lot in advance
0
Comment
Question by:nikolaosk
  • 3
  • 2
5 Comments
 
LVL 26

Accepted Solution

by:
Russell Libby earned 500 total points
ID: 17091919

This solution will require an NT based system (Win2k, NT, XP, 2003, etc) due to the fact that you MUST allocate memory in the process space of OE using VirtualAllocEx, hopefully that is not a problem. Below is the code that reads the current columns from OE. The source for my ProcessMemory unit is also included.

Regards,
Russell

-----

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, CommCtrl, ProcessMemory;

type
  TForm1            = class(TForm)
     Button1:       TButton;
     procedure      Button1Click(Sender: TObject);
  private
     // Private declarations
  public
     // Public declarations
  end;

var
  Form1:            TForm1;

implementation
{$R *.DFM}

function GetOEColumns(List: TStrings): Integer;
var  pmItem:        TProcessMemory;
     pmText:        TProcessMemory;
     hwndOE:        HWND;
     hwndMV:        HWND;
     hwndML:        HWND;
     hwndList:      HWND;
     hwndHead:      HWND;
     dwPID:         DWORD;
     dwCount:       Integer;
     dwIndex:       Integer;
     hdItem:        THDItem;
     lpszBuffer:    Array [0..1024] of Char;
begin

  // Set default result (number of columns)
  result:=0;

  // Check List
  if Assigned(List) then
  begin
     // Lock list update
     List.BeginUpdate;
     // Resource protection
     try
        // Clear the list
        List.Clear;
        // Find application window
        hwndOE:=FindWindow('Outlook Express Browser Class', nil);
        // Check handle
        if (hwndOE <> 0) then
        begin
           // Get window thread process if
           if (GetWindowThreadProcessID(hwndOE, @dwPID) <> 0) then
           begin
              // Allocate process memory reader / writer
              pmItem:=TProcessMemory.Create(dwPID, SizeOf(THDItem));
              pmText:=TProcessMemory.Create(dwPID, Pred(SizeOf(lpszBuffer)));
              // Resource protection
              try
                 // Get child
                 hwndMV:=FindWindowEx(hwndOE, 0, 'Outlook Express Message View', nil);
                 // Check child
                 if (hwndMV <> 0) then
                 begin
                    // Get child
                    hwndML:=FindWindowEx(hwndMV, 0, 'Outlook Express Message List', nil);
                    // Check child
                    if (hwndML <> 0) then
                    begin
                       // Get child
                       hwndList:=FindWindowEx(hwndML, 0, nil, 'Outlook Express Message List');
                       // Check child
                       if (hwndList <> 0) then
                       begin
                          // Get final child
                          hwndHead:=FindWindowEx(hwndList, 0, 'SysHeader32', nil);
                          // Check child
                          if (hwndHead <> 0) then
                          begin
                             // Null terminate the buffer
                             lpszBuffer[1024]:=#0;
                             // Get count of columns in list view
                             dwCount:=Header_GetItemCount(hwndHead);
                             // Create empty strings in result
                             for dwIndex:=0 to Pred(dwCount) do List.Add('');
                             // Walk the columns
                             for dwIndex:=0 to Pred(dwCount) do
                             begin
                                // Clear column item
                                FillChar(hdItem, SizeOf(hdItem), 0);
                                // Prepare column header item
                                hdItem.Mask:=HDI_TEXT or HDI_ORDER or HDI_IMAGE;
                                hdItem.pszText:=pmText.Data;
                                hdItem.cchTextMax:=pmText.Size;
                                // Move item into Outlook Express process
                                pmItem.Write(@hdItem);
                                // Now have Outlook fill in the header item
                                if (SendMessage(hwndHead, HDM_GETITEM, dwIndex, Longint(pmItem.Data)) <> 0) then
                                begin
                                   // Read the item data back
                                   pmItem.Read(@hdItem);
                                   // Get text
                                   pmText.Read(@lpszBuffer);
                                   // For some columns like Priority, Flag, etc there is no text
                                   if (lpszBuffer[0] > #0) then
                                      // Set the column by its order (not index)
                                      List[hdItem.iOrder]:=lpszBuffer
                                   else
                                   begin
                                      // Check the iImage to determine what column it is
                                      case hdItem.iImage of
                                         4  :  List[hdItem.iOrder]:='Priority';
                                         5  :  List[hdItem.iOrder]:='Attachment';
                                         33 :  List[hdItem.iOrder]:='Flag';
                                         37 :  List[hdItem.iOrder]:='Watch / Ignore';
                                      end;
                                   end;
                                end;
                             end;
                          end;
                       end;
                    end;
                 end;
              finally
                 // Free process memory
                 pmItem.Free;
              end;
           end;
        end;
     finally
        // Unlock list
        List.EndUpdate;
     end;
     // Set result
     result:=List.Count;
  end;

end;


procedure TForm1.Button1Click(Sender: TObject);
var  listCols:      TStringList;
     szList:        String;
     dwIndex:       Integer;
begin

  listCols:=TStringList.Create;
  try
     if (GetOEColumns(listCols) > 0) then
     begin
        SetLength(szList, 0);
        for dwIndex:=0 to Pred(listCols.Count) do
        begin
           if (dwIndex < Pred(listCols.Count)) then
              szList:=szList+listCols[dwIndex]+'-'
           else
              szList:=szList+listCols[dwIndex];
        end;
        ShowMessage(szList);
     end
     else
        ShowMessage('No Columns');
  finally
     listCols.Free;
  end;

end;

end.

-- supporting unit --

unit ProcessMemory;
////////////////////////////////////////////////////////////////////////////////
//
//   Unit        :  ProcessMemory
//   Author      :  rllibby
//   Date        :  12.12.2005
//   Description :  Class object implementation for memory allocation, reading,
//                  and writing in another process's address space.
//
////////////////////////////////////////////////////////////////////////////////
interface

////////////////////////////////////////////////////////////////////////////////
//   Include units
////////////////////////////////////////////////////////////////////////////////
uses
  Windows, SysUtils;

////////////////////////////////////////////////////////////////////////////////
//   TProcessMemory
////////////////////////////////////////////////////////////////////////////////
type
  TProcessMemory    =  class(TObject)
  private
     // Private declarations
     FProcessID:    DWORD;
     FProcess:      THandle;
     FSize:         Cardinal;
     FData:         Pointer;
  public
     // Public declarations
     constructor    Create(ProcessID: DWORD; Size: Cardinal);
     destructor     Destroy; override;
     function       Read(Buffer: Pointer): Boolean;
     function       ReadData(Memory: Pointer; Buffer: Pointer; Size: Cardinal): Boolean;
     function       Write(Buffer: Pointer): Boolean;
     property       Data: Pointer read FData;
     property       Process: THandle read FProcess;
     property       ProcessID: DWORD read FProcessID;
     property       Size: Cardinal read FSize;
  end;

implementation

function TProcessMemory.ReadData(Memory: Pointer; Buffer: Pointer; Size: Cardinal): Boolean;
var  dwRead:        DWORD;
begin

  // Read from process memory into local memory
  result:=ReadProcessMemory(FProcess, Memory, Buffer, Size, dwRead);

end;

function TProcessMemory.Read(Buffer: Pointer): Boolean;
var  dwRead:        DWORD;
begin

  // Read from process memory into local memory
  result:=ReadProcessMemory(FProcess, FData, Buffer, FSize, dwRead);

end;

function TProcessMemory.Write(Buffer: Pointer): Boolean;
var  dwWrite:       DWORD;
begin

  // Write from local memory to the process memory
  result:=WriteProcessMemory(FProcess, FData, Buffer, FSize, dwWrite);

end;

constructor TProcessMemory.Create(ProcessID: DWORD; Size: Cardinal);
begin

  // Perform inherited
  inherited Create;

  // Set starting defaults
  FProcessID:=ProcessID;
  FSize:=Size;
  FData:=nil;

  // Attempt to open a handle to the process
  FProcess:=OpenProcess(PROCESS_ALL_ACCESS, False, FProcessID);

  // Check handle
  if (FProcess = 0) then
     // Failed to open process
     RaiseLastWin32Error
  else
  begin
     // Allocate memory block in process
     FData:=VirtualAllocEx(FProcess, nil, (FSize+SizeOf(DWORD)), MEM_COMMIT, PAGE_READWRITE);
     // Check data allocation
     if not(Assigned(FData)) then RaiseLastWin32Error;
  end;

end;

destructor TProcessMemory.Destroy;
begin

  // Resource protection
  try
     // Free allocated memory
     if Assigned(FData) then VirtualFreeEx(FProcess, FData, 0, MEM_RELEASE);
     // Close process handle
     if (FProcess <> 0) then CloseHandle(FProcess);
  finally
     // Perform inherited
     inherited Destroy;
  end;

end;

end.
0
 
LVL 26

Expert Comment

by:Russell Libby
ID: 17139989
Its been a week, with no response. Do you plan on addressing this question?

Russell
0
 

Author Comment

by:nikolaosk
ID: 17144401
yes you are right but your solution it is very complicated and it did not work for me for windows 98.
so i was not able to use your code.
0
 
LVL 26

Expert Comment

by:Russell Libby
ID: 17146577
>> yes you are right but your solution it is very complicated and it did not work for me for windows 98.
so i was not able to use your code.

What were you expecting? Interfacing with an application that exposes no means of direct interface is not an easy task, and I can tell you I put some time into the code that was posted above. So I don't appreciate having to wait a week for you to tell me that it didn't work. I already told you it would not work on non NT systems. So the answer to your original question:

>> when i open outlook express i need to read the name of all the visible columns that exist in the current view of
 the OE window. (windows 98)

is ...... you can't.

----

Russell




 




0
 

Author Comment

by:nikolaosk
ID: 17152416
i see your point and i think you are right.sorry for the delay...
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Polish reports in Access so they look terrific. Take yourself to another level. Equations, Back Color, Alternate Back Color. Write easy VBA Code. Tighten space to use less pages. Launch report from a menu, considering criteria only when it is filled…
This tutorial demonstrates a quick way of adding group price to multiple Magento products.

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now