?
Solved

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

Posted on 2006-07-12
5
Medium Priority
?
374 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 2
5 Comments
 
LVL 26

Accepted Solution

by:
Russell Libby earned 2000 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

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
If you’ve ever visited a web page and noticed a cool font that you really liked the look of, but couldn’t figure out which font it was so that you could use it for your own work, then this video is for you! In this Micro Tutorial, you'll learn yo…
In this video, Percona Solutions Engineer Barrett Chambers discusses some of the basic syntax differences between MySQL and MongoDB. To learn more check out our webinar on MongoDB administration for MySQL DBA: https://www.percona.com/resources/we…
Suggested Courses
Course of the Month12 days, 13 hours left to enroll

777 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