Pages

Sunday, January 10, 2010

Launch Internet Explorer programmatically

Here is the easiest way to launch IE:
#include <windows.h>
#include <shellapi.h>

int APIENTRY wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
{
ShellExecuteW(NULL, L"open", L"http://gquangdung.blogspot.com", NULL, NULL, SW_SHOWNORMAL);
}
You can do the same but it will look like a very serious program :)
#include <windows.h>
#include <exdisp.h>

int APIENTRY wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
{
CoInitialize(NULL);
IWebBrowser2* pBrowser = NULL;
HRESULT hr = CoCreateInstance(CLSID_InternetExplorer, NULL,
CLSCTX_SERVER, IID_IWebBrowser2, (LPVOID*)&pBrowser);

if (SUCCEEDED(hr) && (pBrowser != NULL))
{
VARIANT vEmpty;
VariantInit(&vEmpty);

VARIANT vFlags;
V_VT(&vFlags) = VT_I4;
V_I4(&vFlags) = navOpenInNewWindow;

BSTR bstrURL = SysAllocString(L"http://gquangdung.blogspot.com");

pBrowser->Navigate(bstrURL, &vFlags, &vEmpty, &vEmpty, &vEmpty);
pBrowser->Quit();

SysFreeString(bstrURL);
}
if (pBrowser)
pBrowser->Release();
CoUninitialize();
return 0;
}
I've not tested but this way allows to launch IE in a host application:
#include <windows.h>
#include <exdisp.h>

int APIENTRY wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
{
CoInitialize(NULL);
IWebBrowser2* pBrowser = NULL;
HRESULT hr = CoCreateInstance(CLSID_InternetExplorer, NULL,
CLSCTX_SERVER, IID_IWebBrowser2, (LPVOID*)&pBrowser);

if (SUCCEEDED(hr) && (pBrowser != NULL))
{
VARIANT vEmpty;
VariantInit(&vEmpty);

BSTR bstrURL = SysAllocString(L"http://gquangdung.blogspot.com");

hr = pBrowser->Navigate(bstrURL, &vEmpty, &vEmpty, &vEmpty, &vEmpty);
if (SUCCEEDED(hr))
pBrowser->put_Visible(VARIANT_TRUE);
else
pBrowser->Quit();

SysFreeString(bstrURL);
}
if (pBrowser)
pBrowser->Release();
CoUninitialize();
return 0;
}

Detect URL opened in the running Internet Explorer

#include <windows.h>
#include <stdlib.h>
#pragma warning(disable : 4192)

#import <mshtml.tlb>
#import <shdocvw.dll>

int main()
{
CoInitialize(NULL);

SHDocVw::IShellWindowsPtr pShellWindows;
IDispatchPtr pDisp;
HRESULT hr = pShellWindows.CreateInstance(__uuidof(SHDocVw::ShellWindows));
if (SUCCEEDED(hr))
{
long nCount = pShellWindows->GetCount();
for (long i = 0; i < nCount; ++i)
{

_variant_t va(i, VT_I4);
pDisp = pShellWindows->Item(va);

SHDocVw::IWebBrowser2Ptr pBrowser(pDisp);
if (pBrowser != NULL)
{
_bstr_t str = pBrowser->GetLocationName();
wprintf_s(L"%d. %s\n", i, (LPCWSTR)str);
SysFreeString(str);
pBrowser = NULL;
}
pDisp = NULL;
}
}

pShellWindows = NULL;
CoUninitialize();
return 0;
}

I needed this program few days ago but made it only today.
More info in MSDN:
ShellWindows Object
InternetExplorer Object

Wednesday, January 6, 2010

Not "Hello, World!"

I think any expirienced Windows programmer select Win32 application and Empty project in the Visual Studio application wizard. Next few lines should be placed in a cpp-file:
#include <windows.h>

int APIENTRY wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
{
return 0;
}
Add this file manualy through New Item from the popup menu - right click on the Source folder in Solution View.
If you will change the project settings - in C/C++ section, Code Generation->Runtime Libraries set to Multi-Threaded, the executable in the release configuration will be about 50K and will depend on NTDLL.DLL and KERNEL32.DLL. That means it will run on any Windows computer.

Monday, January 4, 2010

Mutable

This the word I already forgot. Or just never knew.
If a constant method is declared which ensure that the state of object or member variable will not be modified inside such const method. One can declare the variable as mutable and it is modified by const method. Basically used for const objects.

Objective-C. Basic Directory Operations

NSFileManager allows to perform the basic operations with directories:
1. Detect current directory
2. Change current directory
3. Create new directory
4. Move directory
5. Delete directory.
6. Enumerate the content.
Here is a simple program demonstrating these basic directory operations:
#import <Foundation/NSObject.h>
#import <Foundation/NSString.h>
#import <Foundation/NSFileManager.h>
#import <Foundation/NSAutoreleasePool.h>

int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

NSString *dirName = @"testDir";
NSString *path;
NSFileManager *fm;
BOOL success;

fm = [NSFileManager defaultManager];

path = [fm currentDirectoryPath];
NSLog(@"Current directory path is %@", path);

success = [fm createDirectoryAtPath: dirName attributes: nil];
if (success == YES)
{
success = [fm movePath: dirName toPath: @"newDir" handler: nil];

if (success == YES)
{
success = [fm changeCurrentDirectoryPath: @"newDir"];

if (success == YES)
{
path = [fm currentDirectoryPath];
NSLog(@"Current directory path is %@", path);
}
else
{
NSLog(@"Couldn't change the current directory");
}
}
else
{
NSLog(@"Couldn't rename the directory");
}
}
else
{
NSLog(@"Couldn't create directory");
}

[pool drain];
return 0;
}

The following program enumerates the directory content:
#import <Foundation/NSString.h>
#import <Foundation/NSFileManager.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSArray.h>

int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString *path;
NSFileManager *fm;
NSDirectoryEnumerator *dirEnum;

fm = [NSFileManager defaultManager];
[fm changeCurrentDirectoryPath: @"/Users/pavelgnatyuk/Documents/Hello"];
path = [fm currentDirectoryPath];
dirEnum = [fm enumeratorAtPath: path];

NSLog(@"Content of %@:", path);

do
{
path = [dirEnum nextObject];
if (path == nil)
break;
NSLog(@"%@", path);
} while(YES);

[pool drain];
return 0;
}

Let's prevent the enumerating of the subfolders:

#import <Foundation/NSString.h>
#import <Foundation/NSFileManager.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSArray.h>

int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString *path;
NSFileManager *fm;
NSDirectoryEnumerator *dirEnum;
BOOL flag;

fm = [NSFileManager defaultManager];
[fm changeCurrentDirectoryPath: @"/Users/pavelgnatyuk"];
path = [fm currentDirectoryPath];
dirEnum = [fm enumeratorAtPath: path];

NSLog(@"Content of %@:", path);

do
{
path = [dirEnum nextObject];
if (path == nil)
break;

NSLog(@"%@", path);

[fm fileExistsAtPath: path isDirectory: &flag];
if (flag == YES)
[dirEnum skipDescendents];

} while(YES);

[pool drain];
return 0;
}
Or just:
#import <Foundation/NSString.h>
#import <Foundation/NSFileManager.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSArray.h>

int main (int argc, const char * argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *path= @"/Users/pavelgnatyuk";
NSFileManager *fm;
NSArray *dirArray;

fm = [NSFileManager defaultManager];
NSLog(@"Content of %@:", path);
dirArray = [fm directoryContentsAtPath: path];
for (path in dirArray)
NSLog(@"%@", path);

[pool drain];
return 0;
}

Sunday, January 3, 2010

Objective-C. Basic File Operations

#import <Foundation/NSObject.h>
#import <Foundation/NSString.h>
#import <Foundation/NSFileManager.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSDictionary.h>

int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

NSFileManager *fm;
NSString *fName = @"testfile";
NSDictionary *attr;

fm = [NSFileManager defaultManager];

if ([fm fileExistsAtPath: fName] == NO)
{
NSLog(@"File does not exist!");
return 1;
}

if ([fm copyPath:fName toPath:@"newFile" handler: nil] == NO)
{
NSLog(@"File copy failed");
return 2;
}

if ([fm movePath: @"newFile" toPath: @"newFile2" handler: nil] == NO)
{
NSLog(@"File rename failed");
return 3;
}

attr = [fm fileAttributesAtPath: @"newFile2" traverseLink: NO];
if (attr == nil)
{
NSLog(@"Couldn't get file attribute");
return 4;
}

NSLog(@"File size is %i bytes", [[attr objectForKey: NSFileSize]
intValue]);

if ([fm removeFileAtPath: fName handler: nil] == NO)
{
NSLog(@"File removal failed");
return 5;
}

NSLog(@"All operations were successfull");

NSLog(@"%@", [NSString stringWithContentsOfFile: @"newFile2"
encoding: NSUTF8StringEncoding
error: nil]);
[pool drain];
return 0;
}
Foundation framework allow to perform a set of basic file operations such as create, rename, move, copy, delete a file. The program above demonstrates NSFileManager class in action.

The program uses testfile - a text file. You can create it in Xcode by selecting New File.. from the File menu. In the left pane that appears, highlight Other, and select Empty file in the right pane. The file should be in Build\Debug folder.

Foundation framework provides a special class NSData (and, of course NSMutableData) that is used as a temporary buffer for file read/write operations. It is used together with the NSFileManager as it is shown below:
#import <Foundation/NSObject.h>
#import <Foundation/NSFileManager.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSData.h>

int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

NSFileManager *fm;
NSData *fileData;

fm = [NSFileManager defaultManager];
fileData = [fm contentsAtPath: @"testFile"];

if (fileData == nil)
{
NSLog(@"File read failed");
return 1;
}

BOOL bCreated = [fm createFileAtPath: @"newFile" contents: fileData attributes: nil];
if (bCreated == YES)
NSLog(@"File newFile created.");

[pool drain];
return 0;
}

Saturday, January 2, 2010

Operator <<

The following program shows how to overload operator <<:
#include <iostream>
using namespace std;

class Test
{
int x, y;

public:
Test() : x(0), y(0) {}

friend void operator << (ostream& out, Test test);
};

void operator << (ostream& out, Test test)
{
out << "overloaded operator <<" << endl;
out << "x = " << test.x << endl;
out << "y = " << test.y << endl;
}

int main()
{
Test test;
cout << test;
}

Operator new

If you are going to implement new operator for your class you need to remember that:
1. new returns void pointer
2. new takes one parameter of type size_t.
Here is an example:
#include <iostream>
using namespace std;

class Test
{
int x;
int y;

public:
Test() : x(100), y(100)
{
cout << "Test constructor" << endl;
}

void* operator new(size_t size)
{
cout << "Test::operator new" << endl;
Test* p = (Test*)malloc(size);
cout << "size is " << size << endl;
return p;
}

void Out()
{
cout << "x = " << x << endl;
cout << "y = " << y << endl;
}
};


int main()
{
Test* test2 = new Test;
test2->Out();
delete test2;
return 0;
}
This program will show that new receives the size of the object as the input parameter. This new function was called before the constructor.

Postfix operator

If we have an object x of a class XClass and we need both statements x++ and ++x be properly executed, we need to overload bot postfix and prefix perators. For example as it is in the following program:
#include <iostream>
using namespace std;

class Test
{
int x;
public:
Test() : x(0) {}

Test operator++()
{
x++;
return *this;
}

Test operator++(int)
{
x++;
return *this;
}

int X() { return x; }

void Out()
{
cout << "x = " << x << endl;
}
};

int main()
{
Test test;
test.Out();

++test;
test.Out();

test++;
test.Out();

return 0;
}

As you see the postfix operator has int in parentheses. It is a signal to the compiler to generate the postfix version of the operator.