|
Just FYI after playing around for
about 6 hours I hacked my way into
a component that will initialize
the way I want when dropped on
a form.
Maybe I'll work up a short article
showing how 'cause it's definitely
a feature that's very convenient.
When my C# programming book arrives
in the mail I'll consult that first
of course.
|
|
|
|
|
I am trying to customize PrintPreviewDialog for changing functionality of existing buttoms and add a few new buttons using C#, please tell me which dll need to be imported and what are the various methods available or need to be overriden for the same.
Sample code will help a lot.
regards
|
|
|
|
|
Did you read the documentation for the PrintPreviewDialog ? It states right at the bottom: the System.Windows.Forms.dll assembly. Read the documentation to learn what you can override. You will need to use Reflection to change existing behavior for buttons and other controls, however. The PrintPreviewDialog extends Form and just hosts a PrintPreviewControl with some buttons and combo boxes. You might consider a similar approach which would be easier depending on how much you want to change.
Just extend the Form class and host an instance of the PrintPreviewControl . Add your own controls and behavior to the form.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Thanks for your valuable suggestion. I am using PrintPreviewControl to make customized dialog, but the problem is that, how to integrate vertical scroll bar with next/previous page in co-ordination with the present zoom status. please do suggest
regards
|
|
|
|
|
I suggest you look at how the PrintPreviewDialog works. Download something like .NET Reflector[^] and find the PrintPreviewDialog in the System.Windows.Forms assembly. Use the decompiler to see how it works.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
I can't find the equivalent to PostMessage in Windows Forms. I'm currently using BeginInvoke, as it's much like it, but then I get memory leaks, since I ignore the AsyncResults. What should I do with them? Store them in a queue which I walk through later to see if the Completedflag is set and can then safelly call endinvoke?
Thanks in advance
|
|
|
|
|
You won't get memory leaks if you ignore AsyncResult s. .NET is GC'd. More than likely you're not using Control.InvokeRequired and Control.Invoke to call methods and get/set properties on controls created in a different thread. This is a common problem. When you comunicate with a control that was created on a different thread (the UI thread), you must use the ISynchronizeInvoke impementation that every control inherits from Control . This makes sure that communciate with the control happens in the UI thread.
If you want PostMessage , why not just P/Invoke it? If you read the forms, we're continually telling people to P/Invoke SendMessage to send the message immediately, but P/Invoking PostMessage is really no different. It would just look like this:
[DllImport("user32.dll")]
private static extern bool PostMessage(
IntPtr hWnd,
[MarshalAs(UnmanagedType.U4)] int msg,
IntPtr wParam,
IntPtr lParam); If you need to pass a struct or reference to a struct or something, instead of marshaling the struct yourself and passing it as an IntPtr , you could overload PostMessage like so:
[DllImport("user32.dll")]
private static extern bool PostMessage(
IntPtr hWnd,
[MarshalAs(UnmanagedType.U4)] int msg,
int wParam,
ref LVITEM lvItem); Of course, you'd need to declare a managed LVITEM struct (can be named whatever you like, though) that would marshal correctly.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Thank you very much for your answer. Although I don't agree on your discussion, I'll use the code you gave me.
I tested calling BeginInvoke(Nada) a hundred thousand times and then GC.Collect(); The memory footprint after the collection was over a hundred megs. ??? And the reason I ask is that I do use BeginInvoke, but am not satisfied with it. And Invoke is no option since it causes deadlocks in my case. (The UI is updated from a background process.)
|
|
|
|
|
Doesn't really matter if you don't agree with me - it's documented in the .NET Framework SDK. I suppose, then, that you disagree with Microsoft.
I didn't say that ignoring the AsyncResult s doesn't incur a certain performance hit with memory consumption, I said it didn't incur any memory leaks. There is a difference. The very fact that the GC was able to collect the unused references proves that the objects where indeed tracked. The GC would've collected them eventually.
Memory leaks are when memory is lost and unreferenced, so it cannot be freed again, like when a variable references an alloc'd region of memory which is not freed. Once that variable goes out of scope it's practically impossible to free that memory again.
The fact remains that calling methods or setting properties (often getting as well) on controls from a different thread may cause problems. This is what's documented well in the .NET Framework if you read the right topics. Sometimes things may work. Other times they may not. Often times it is certain functionality that doesn't work as expected. It call comes down to the synchronization of threads, like it or not.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Hi,
I have two clients installed on my PC.
Q1: How do I test/investigate (generally) a workstation to find out what email clients are available on a PC ?
I have a Class called OutlookConnector.CS that I use to retrieve the emails from my Outlook Client.
Q2: Is there a similar class for Outlook Express ?
Thanks in advance ! 
|
|
|
|
|
wfe wrote:
How do I test/investigate (generally) a workstation to find out what email clients are available on a PC ?
Nothing in the Windows API will supply you with this info. You'll problably have to search through the installed applications list, looking for specific application names, or go through the registry, or just ask the user what they use.
wfe wrote:
Is there a similar class for Outlook Express ?
Don't know. What does this class do? Where did it come from? If the class you have is pretty general in nature, then the same class might work for Outlook Express since you programatically use both of them the same way.
RageInTheMachine9532
|
|
|
|
|
 Thanks Dave,
Q1a: How do I search 'installed applications list' on a local PC from C#/.NET ?
Q1b: How do I search the registry ?
If I ask the user for what they use, I still have the problem of addressing the mailboxes locally on Outlook Express. Also, I would like to learn the Windows API and general environment by making the application 'fool proof'.
I don't know where the class came from - probably a former colleaque of mine.
I have enclosed the class below.
Thanks for your help
William
<br />
using System;<br />
using System.Data;<br />
using System.Diagnostics;<br />
using System.Windows.Forms;<br />
<br />
namespace test<br />
{<br />
public delegate void OutlookItemProcessed();<br />
<br />
public class OutlookConnector : IDisposable<br />
{<br />
private Outlook.Application objOutlook = null;<br />
private Outlook.NameSpace objNamespace = null;<br />
private Outlook.MAPIFolder objFolder = null;<br />
private Outlook.Items objItems = null;<br />
public event OutlookItemProcessed ItemProcessed;<br />
<br />
public OutlookConnector()<br />
{<br />
objOutlook = new Outlook.ApplicationClass();<br />
objNamespace = objOutlook.GetNamespace("MAPI");<br />
}<br />
<br />
public void Dispose()<br />
{<br />
if (objOutlook != null) objOutlook.Quit();<br />
}<br />
<br />
public int getFolderCount(Outlook.OlDefaultFolders folder)<br />
{<br />
objFolder = objNamespace.GetDefaultFolder(folder);<br />
return objFolder.Items.Count;<br />
}<br />
<br />
public DataSet getCalendarDataSet()<br />
{<br />
Outlook.AppointmentItem item;<br />
DataSet rv = new DataSet();<br />
rv.DataSetName = "Calendar";<br />
rv.Tables.Add("Appointment");<br />
rv.Tables[0].Columns.Add("Subject");<br />
rv.Tables[0].Columns.Add("Location");<br />
rv.Tables[0].Columns.Add("Start");<br />
rv.Tables[0].Columns.Add("End");<br />
rv.Tables[0].Columns.Add("AllDayEvent");<br />
rv.Tables[0].Columns.Add("Duration");<br />
rv.Tables[0].Columns.Add("Organizer");<br />
rv.Tables[0].Columns.Add("Importance");<br />
rv.Tables[0].Columns.Add("Sensitivity");<br />
rv.Tables[0].Columns.Add("Body");<br />
<br />
try<br />
{<br />
objFolder = objNamespace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderCalendar);<br />
Debug.WriteLine(objFolder.Items.Count + " Appointments found.");<br />
for (int i=0; i < objFolder.Items.Count; i++) <br />
{<br />
item = (Outlook.AppointmentItem)objFolder.Items.Item(i);<br />
rv.Tables[0].Rows.Add(new object[] {<br />
item.Subject,<br />
item.Location,<br />
item.Start,<br />
item.End,<br />
item.AllDayEvent,<br />
item.Duration,<br />
item.Organizer,<br />
item.Importance,<br />
item.Sensitivity,<br />
item.Body<br />
});<br />
this.ItemProcessed();<br />
}<br />
Debug.WriteLine(rv.Tables[0].Rows.Count + " Appointments exported.");<br />
}<br />
catch (System.Exception e)<br />
{<br />
Console.WriteLine(e);<br />
}<br />
return rv;<br />
}<br />
<br />
public DataSet getContactDataSet()<br />
{<br />
Outlook.ContactItem item;<br />
DataSet rv = new DataSet();<br />
rv.DataSetName = "Contacts";<br />
rv.Tables.Add("Contact");<br />
rv.Tables[0].Columns.Add("FirstName");<br />
rv.Tables[0].Columns.Add("LastName");<br />
rv.Tables[0].Columns.Add("CompanyName");<br />
rv.Tables[0].Columns.Add("Email");<br />
rv.Tables[0].Columns.Add("HomePhone");<br />
rv.Tables[0].Columns.Add("WorkPhone");<br />
<br />
try<br />
{<br />
objFolder = objNamespace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts);<br />
Debug.WriteLine(objFolder.Items.Count + " Contacts found.");<br />
for (int i=0; i < objFolder.Items.Count; i++) <br />
{<br />
item = (Outlook.ContactItem)objFolder.Items.Item(i);<br />
rv.Tables[0].Rows.Add(new object[] {<br />
item.FirstName,<br />
item.LastName,<br />
item.CompanyName,<br />
item.Email1Address,<br />
item.HomeTelephoneNumber,<br />
item.BusinessTelephoneNumber<br />
});<br />
this.ItemProcessed();<br />
}<br />
Debug.WriteLine(rv.Tables[0].Rows.Count + " Contacts exported.");<br />
}<br />
catch (System.Exception e)<br />
{<br />
Console.WriteLine(e);<br />
}<br />
return rv;<br />
}<br />
<br />
public DataSet getInboxDataSet()<br />
{<br />
Outlook.MailItem item;<br />
DataSet rv = new DataSet();<br />
rv.DataSetName = "InboxEmails";<br />
rv.Tables.Add("Email");<br />
rv.Tables[0].Columns.Add("Name");<br />
rv.Tables[0].Columns.Add("To");<br />
rv.Tables[0].Columns.Add("Cc");<br />
rv.Tables[0].Columns.Add("Subject");<br />
rv.Tables[0].Columns.Add("Received");<br />
rv.Tables[0].Columns.Add("Message");<br />
<br />
<br />
try<br />
{<br />
objFolder = objNamespace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox); <br />
objItems = objFolder.Items.Restrict("[MessageClass]='IPM.Note'");<br />
<br />
<br />
Debug.WriteLine(objItems.Count + " E-Mails found.");<br />
for (int i=1; i <= objItems.Count; i++) <br />
{<br />
item = (Outlook.MailItem)objItems.Item(i); <br />
{<br />
rv.Tables[0].Rows.Add(new object[] {<br />
item.SenderName,<br />
item.To,<br />
item.CC,<br />
item.Subject,<br />
item.ReceivedTime,<br />
item.Body<br />
});<br />
<br />
}<br />
this.ItemProcessed();<br />
}<br />
Debug.WriteLine(rv.Tables[0].Rows.Count + " E-Mails exported.");<br />
<br />
}<br />
catch (System.Exception e)<br />
{<br />
Console.WriteLine(e);<br />
}<br />
return rv;<br />
}<br />
<br />
public DataSet getNoteDataSet()<br />
{<br />
Outlook.NoteItem item;<br />
DataSet rv = new DataSet();<br />
rv.DataSetName = "Notes";<br />
rv.Tables.Add("Note");<br />
rv.Tables[0].Columns.Add("Subject");<br />
rv.Tables[0].Columns.Add("Categories");<br />
rv.Tables[0].Columns.Add("CreationTime");<br />
rv.Tables[0].Columns.Add("LastModificationTime");<br />
rv.Tables[0].Columns.Add("Contents");<br />
<br />
try<br />
{<br />
objFolder = objNamespace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderNotes);<br />
Debug.WriteLine(objFolder.Items.Count + " Notes found.");<br />
for (int i=0; i < objFolder.Items.Count; i++) <br />
{<br />
item = (Outlook.NoteItem)objFolder.Items.Item(i);<br />
rv.Tables[0].Rows.Add(new object[] {<br />
item.Subject,<br />
item.Categories,<br />
item.CreationTime,<br />
item.LastModificationTime,<br />
item.Body<br />
});<br />
this.ItemProcessed();<br />
}<br />
Debug.WriteLine(rv.Tables[0].Rows.Count + " Notes exported.");<br />
}<br />
catch (System.Exception e)<br />
{<br />
Console.WriteLine(e);<br />
}<br />
return rv;<br />
}<br />
<br />
public DataSet getTaskDataSet()<br />
{<br />
Outlook.TaskItem item;<br />
DataSet rv = new DataSet();<br />
rv.DataSetName = "Tasks";<br />
rv.Tables.Add("Task");<br />
rv.Tables[0].Columns.Add("Subject");<br />
rv.Tables[0].Columns.Add("StartDate");<br />
rv.Tables[0].Columns.Add("DueDate");<br />
rv.Tables[0].Columns.Add("Status");<br />
rv.Tables[0].Columns.Add("Contents");<br />
<br />
try<br />
{<br />
objFolder = objNamespace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderTasks);<br />
Debug.WriteLine(objFolder.Items.Count + " Tasks found.");<br />
for (int i=0; i < objFolder.Items.Count; i++) <br />
{<br />
item = (Outlook.TaskItem)objFolder.Items.Item(i);<br />
rv.Tables[0].Rows.Add(new object[] {<br />
item.Subject,<br />
item.StartDate,<br />
item.DueDate,<br />
item.Status,<br />
item.Body<br />
});<br />
this.ItemProcessed();<br />
}<br />
Debug.WriteLine(rv.Tables[0].Rows.Count + " Tasks exported.");<br />
}<br />
catch (System.Exception e)<br />
{<br />
Console.WriteLine(e);<br />
}<br />
return rv;<br />
}<br />
}<br />
}<br />
<br />
|
|
|
|
|
wfe wrote:
Q1a: How do I search 'installed applications list' on a local PC from C#/.NET ?
The easiest way is using WMI. See the System.Management namespace in the clas library documentation of the .NET Framework SDK. Make a request on the remote machine (or even your local machine, which you can refer to as "." or just don't specify a machine at all) for the Win32_Product CIMv2 class.
See System.Management Lets You Take Advantage of WMI APIs within Managed Code[^] in MSDN Magazine online for more information, sample code, and a link to an add-in for VS.NET 2002 (and if you search, for 2003) that lets you browse the WMI repository on any machine and to create managed wrapper classes just by dragging and dropping classes into your project.
wfe wrote:
Q1b: How do I search the registry ?
The .NET FCL (Framework Class Library) does not let you access the registry of a remote machine. You either need to P/Invoke the registry APIs yourself or find a project that already does this for you. I'd recommend the method above, though, since it's far more robust and less error-prone (messing with the registry is dangerous, especially if you don't know what you're doing).
As far as the connector goes, both Outlook and Outlook Express are MAPI clients so you can use MAPI wrappers, like Simple MAPI.NET[^]. There are many restrictions in the MAPI implementations these days, however, because of script kiddies (responsible for all those malicious worms you hear about). The basic stuff should work fine, however, like sending a mail message. Accessing the address book using MAPI (which is scriptable, where Extended MAPI is not) will either fail or prompt the user that some program is trying to access their address book and prompt them to allow it and for how long, or to simply deny the request. There is plenty of documentation about this subject online. Just google for MAPI or something and you'll find a lot of information. Another good place is to search on MSDN[^].
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Thanks for your reply.
I know your intentions are good but I am not getting much help from this.
All I need is a SPECIFIC and CONCRETE code description, not references to millions of linked articles that I do not yet understand as I am not yet familiar with the underlying development environment under Windows.
Heath Stewart wrote:
Make a request on the remote machine (or even your local machine, which you can refer to as "." or just don't specify a machine at all) for the Win32_Product CIMv2 class.
Q1: How do I 'make a request' ? I have read your references in the SDK but cannot find anything relating to Win32_Product class. All I get is a list of classes, delegates and enumerations ?
Please, can you provide specific help ?
Heath Stewart wrote:
As far as the connector goes, both Outlook and Outlook Express are MAPI clients so you can use MAPI wrappers
Q2: Good, then why does it pick the emails from Outlook and not from Outlook Express and how do I change it ?
Thanks (and sorry for the panic !)
William
|
|
|
|
|
That's the point - learn. Read the article I linked, which shows how to make a request. The Win32_Product is not a .NET class, but a WMI CIMv2 class. If you read the article, it shows you how to make a query (albeit against a different WMI class).
The default MAPI client is used when you make calls to MAPI. This can be changed in WinXP through the Start properties. MAPI clients like Outlook, Outlook Express, Mozilla Mail, etc. also typically have a setting in their preference to make that application the default MAPI client. You as a developer should not change this. Only the user should make that change.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Don't get me wrong - I am learning. But I keep being sent of on tangents that make me spend a lot more time than necessary to get minor obstacles out of the way for achieving my goals.
Right now, for instance, I am spending my second day on finding out what concepts like WMI, CIM etc. REALLY mean and whether they are important at all for anyone outside the 'nerd community' (excuse the expression it is not meant for you).
I also think it is an extremely inefficient way of learning when you have to guess 90% of the idea behind an answer and not even be able to do that before reading (a range of) articles that also do not provide the answer specifically.
I usually learn the other way around - by extrapolation: I ask a specific question, get a specific answer and then work my way out from there by investigating what other methods in the same class do and what other classes in the same namespace do. I relate.
On the MAPI client question: The default client for email is Outlook Express, but the class picks up contents from the Outlook Inbox folder locally and NOT the Outlook Express folder.
The point of my excersise is not to change anything on the users behalf but to be able to know what is going on in the application.
I do hope you can help.
In the meantime, I shall return to my lair and devote myself to studying.
Best regards
William
|
|
|
|
|
Did you actually read the article? Understanding WMI is simple: it's script-based access to information on remote machines. You don't have to understand CIM, which is like WMI standard classes.
A simple way to query a remote client for products is like so:
public void EnumProducts(string machine)
{
string scope = "root\\cimv2";
if (machine != null && machine.Length > 0) scope = string.Format(
"\\\\{0}\\{1}", machine, scope);
ManagementObjectSearcher searcher = new ManagementObjectSearcher(
scope,
"SELECT * FROM Win32_Product");
ManagementObjectCollection products = searcher.Get();
foreach (ManagementObject product in products)
Console.WriteLine(product["Name"]);
} Note that this will only enumerator products installed via Windows Installer.
If you read the article, you'll see a link to a VS.NET add-in that creates a typed class for the Win32_Product class (or whatever class you use). This makes it much easier to use and enumerate.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Good morning Heath,
Your code works fine thanks and gives me a good idea of the mechanics.
I have read the article again (I am not sure I understand all of it yet, though) and have a few questions:
Q1: Where can I find possible values for values in 'Product["NAME"]'. (In the article we have 'Product["CAPTION"]' which also works fine'). I have searched the SDK 1.1.
Q2: Same question for Win32_??; I have seen Win32_Product and Win32_Service. Where can I find the rest ?
Q3: What does ATL stand for ?
I have been developing for 15 years but in a different environment which is why both the development environment and the vocabulary is strange to me and causes big problems for me understanding the core issues.
I don't think I am stupid - I just need the concepts re-phrased.
So, what does...
Q4: it mean to 'Instrument an application', and what is instrumentation ? (Playing the guitar ? )
I will proceed with the VS.NET add-in and see if I can get that to work.
Thanks again
William
|
|
|
|
|
A1: Why are you looking in the .NET Framework SDK? These properties are for WMI objects. WMI != .NET. WMI is just a standard for accessing data on a machine. There are WMI classes - which define properties and methods - and instances of those classes, just like any OO development framework (like .NET). If you want to find out what properties are defined on an object, why not simply enumerate the Properties collection property? This would be the logical conclusion if you read the documentation for the ManagementObject .
A2: As I said before, the article has a link toward the bottom for a VS.NET add-in that adds management classes and event to your Server Explorer tab in VS.NET. I recommend downloading that for VS.NET 2003 (which I assume you have since you mentioned the 1.1 SDK) from here[^]. This installs with a default set of classes but you can add more. The best way, however, is to use the CIM Studio mentioned in the article.
A3: Active Template Libraries - a set of templated C++ classes for creating COM components more easily. A quick search for "ATL" on google would've told you as much.
A4: As the article discussed throughout it's entirety, instrumenting an application is making management data available and firing management events. You can also just simply consume management data and handle management events to instrument your application as you're attempting to do now.
When you need to learn something, I suggest researching it on MSDN or some other site. I have to / want to learn new things all the time. Researching is just part of development, and MSDN contains plenty of Microsoft-related developer documentation, being that it is the Microsoft Developer Network.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Hi everybody,
please try to solve me a mysterious problem .
I opened a new C# console Application and I wrote this code in the Main function:
//-----------------------------------------
//Create new HashTable
Hashtable ht = new Hashtable(100000);
//Add 100,000 elements
for (int i =0 ; i < 100000 ; i++)
ht.Add(i.ToString() , i);
//wait for user
Console.Read();
//-----------------------------------------
Well then I opened the Task Manager and I saw that the memory usage of my app is about 14,256K, then I did something very simple, I just minimized the app and then restored to normal, then I took another look in the Task Manager and saw that the memory usage decreased to 132K.
Can you tell me why this happens?
|
|
|
|
|
I don't have time to go research it, but you shouldn't have anything to worry about. As an exercise, try this:
1) Open taskman
2) Note the memory usage for IEXPLORE.EXE
3) Minimize this browser, and note the memory
4) Maximize again, and note the memory
It's just Windows doing its thing, flushing memory to disk and trimming the working set for applications when it feels necessary. I believe that if your application has allocated more memory than it needs, and some other memory-hogging application starts needing more memory, Windows will free up some of that 14 megs without you doing anything at all. Also, I've noticed that the .NET runtime likes to give around fifteen megs on my own machine to a simple "Hello, world!" app.
I imagine you're trying to gauge the impact to users with wimpy machines, yes? Well, I think that there's no substitute for actually deploying and testing on a wimpy machine. Sorry I can't be of more help.
-Jeff
here, bloggy bloggy
|
|
|
|
|
.NET is garbage collected. The garbage collector (GC) runs when the application is idle (like when it's minimized) or when memory consumption is high and it'd determined that more memory will be needed soon, or when memory is not available (in some cases). You can force garbage collection by running GC.Collect , but you should not do this in most cases. The GC runs when it needs to and very rarely should you force it (and GC.Collect is a synchronous call, so your thread of execution will block until the GC finishes collecting).
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
I want to drag a window from one point to other with the help of mouse,is there any built-in event for it or some other method,please help
mughalali
|
|
|
|
|
Overriden MouseDown and MouseMove . In the first one set the variable which indicate mouse button pressed and in second one check if that valiable is true then set the Location propoerty of your form. Then in MouseUp set that variable to false,
Mazy
"One who dives deep gets the pearls,the burning desire for realization brings the goal nearer." - Babuji
|
|
|
|
|
Hey There!
I'm using the following code to get the free space on my disks:
string[] DriveLetters = {"C:","D:","E:","F:","O:","S:","_Total"};
const int DriveCount = 7;
PerformanceCounter[] DriveSpaceCount = new PerformanceCounter[DriveCount];
float[] FreeSpace = new float[DriveCount];
void ReadFreeDiskSpace()
{
for (int i = 0; i < DriveCount - 1; i++)
{
FreeSpace[i] = DriveSpaceCount[i].NextValue();
}
}
It works once, but the values do not change when I recall the function,
even when the Counter is recreated (DriveSpaceCount[i] = new PerformanceCounter("LogicalDisk","Free Megabytes",DriveLetters[i]); in the loop)
The only way to get new values is to restart the program.
Why?
Thanks in advance.
----------------------
I think war is a dangerous place.
George W. Bush - Washington DC, May 7th 2003
|
|
|
|
|