Click here to Skip to main content
15,868,004 members
Articles / Desktop Programming / MFC
Article

What's New in ACF 0.3

Rate me:
Please Sign up or sign in to vote.
3.39/5 (7 votes)
23 Jun 20043 min read 40.3K   193   8   5
This article introduces what's new in ACF (Another C++ Framework) version 0.3.

Introduction

ACF (Another C++ Framework) is a C++ framework designed to bring the power and RAD of the .NET framework to standard C++. The overall vision of version 0.3 is to deliver a more robust and ready to use Corlib.

1. Type system

Basic RTTI support

ACF 0.3 supports basic RTTI through Type, Object::GetType(), and macro TYPEOF(T). The implementation is based on standard C++ RTTI, namely type_info and typeid. Currently, there is no plan to support advanced reflection functionalities in the .NET framework (e.g., calling a method at runtime).

The following sample code shows how to use GetType and TYPEOF.

ObjectPtr obj = str(L"hello");
bool equals = (obj->GetType() == TYPEOF(String));

Following is the equivalent code in C#:

C#
object obj = "hello";
bool equals = (obj.GetType() == typeof(string));

Value types boxing/unboxing unification

In ACF 0.3, all value types are boxed to type Boxed<T> (e.g.: Boxed<Int32>, Boxed<DateTime>) through template specialization for consistency purpose. For example, the following code checks whether an object is int, and if so, reads its value:

ObjectPtr obj = box(10);
...
Boxed<Int32>* intObj = dynamic_cast<Boxed<Int32>*>(obj.Pointer);
if (intObj != null) {
    int n = intObj->Value;
}

Of course, the example can also be written as follows, if try/catch is preferred and you don't need to change the value of the object:

ObjectPtr obj = box(10);
...
try {
    int n = unbox<int>(obj); // actually calls unbox<Int32>(obj)
}
catch (...) {
}

2. Base types parsing and formatting

Base types parsing and formatting are updated in ACF 0.3 (however, currently there is no support for cultures). For example, the following code shows how to format integers using various formats:

Int32 n = 123456789;
Console::WriteLine(n.ToString(L"C")); // $123,456,789.00
Console::WriteLine(n.ToString(L"E")); // 1.234568E+008
Console::WriteLine(n.ToString(L"P")); // 12,345,678,900.00%
Console::WriteLine(n.ToString(L"N")); // 123,456,789.00
Console::WriteLine(n.ToString(L"F")); // 123456789.00

The following function formats file sizes as shown in Windows Explorer (e.g., "3,012 KB"):

StringPtr FormatFileSize(int64 size) {
    Int64 kb = size / 1024;
    if (size % 1024 != 0)
        kb++;
    return kb.ToString(L"N0") + str(L" KB");
}

3. Arrays and collections

Multi-dimensional arrays

ACF 0.3 supports multi-dimensional arrays. The array class definition is as follows:

template <typename T, int R> // R: array rank, default to 1
class Array : ... {
    Array(int (&lengths)[R]);
    T GetValue(int (&indices)[R]);
    void SetValue(InArgType value, int (&indices)[R]);
    ...
};

// specialization for 1D arrays
template <typename T>
class Array<T, 1> : ... {
    Array(int length);
    T GetValue(int index);
    void SetValue(InArgType value, int index);

    static int BinarySearch(Array<T, 1>* array, InArgType value, 
        IComparer<T>* comparer = null);
    static void Sort(Array<T, 1>* array, 
               IComparer<T>* comparer = null);
    ...
};

// specialization for 2D arrays
template <typename T>
class Array<T, 2> : ... {
    Array(int length1, int length2);
    T GetValue(int index1, int index2);
    void SetValue(InArgType value, int index1, int index2);
    ...
};

...

As you can see, the implementation uses template partial specialization for various array ranks (especially for single dimensional arrays). This is because certain methods, such as BinarySearch, work only on single dimensional arrays. In C#, if you call BinarySearch on a two dimensional array, it compiles OK but will throw a RankException at runtime. In ACF, this will be a compile-time error.

The following sample code shows how to use three dimensional arrays:

RefPtr<Array<int, 3> > array3D = new Array<int, 3>(10, 20, 30);
array3D->SetValue(100, 0, 0, 0);

Following is the equivalent code in C#:

C#
int[,,,] array3D = new int[10, 20, 30];
array3D[0, 0, 0] = 100; // or array3D.SetValue(100, 0, 0, 0);

Comparing and sorting (esp. case insensitive)

ACF 0.3 supports comparing interfaces and classes like IComparer<T>, Comparer<T>, and StringComparer (which are introduced in .NET 2.0). For example, the following sample code sorts a string array using case insensitive invariant culture:

RefPtr<Array<StringPtr> > array = 
  Array<StringPtr>::Build(str(L"hello"), str(L"world"));
Array<StringPtr>::Sort(array, 
  StringComparer::get_InvariantCultureIgnoreCase());

Following is the equivalent code in C#:

C#
string[] array = new string[] { "hello", "world" };
Array.Sort(array, StringComparer.InvariantCultureIgnoreCase);

The following sample code shows how to use case insensitive hash table:

RefPtr<Dictionary<StringPtr, int> > dict = 
  new Dictionary<StringPtr, int>(StringComparer::get_InvariantCultureIgnoreCase());
dict->Item[str(L"Test")] = 10;
int n = dict->Item[str(L"test")];

Following is the equivalent code in C#:

C#
Dictionary<string, int> dict = 
    new Dictionary<string, int>(StringComparer.InvariantCultureIgnoreCase);
dict["Test"] = 10;
int n = dict["test"];

4. Registry support

ACF 0.3 provides support for accessing Windows registry (under namespace Acf::Microsoft::Win32). The RegViewer sample application shows how to use the registry classes.

For example, the following code shows how to respond to TVN_ITEMEXPANDING notification and expand the tree view node (exception handling code omitted):

void CRegViewerDlg::OnTvnItemexpandingTree1(NMHDR *pNMHDR, LRESULT *pResult) {
    LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
    *pResult = 0;

    if (pNMTreeView->action == TVE_EXPAND && 
        (pNMTreeView->itemNew.state & TVIS_EXPANDEDONCE) == 0) {
        RegistryKey* parentKey = 
          reinterpret_cast<RegistryKey*>(pNMTreeView->itemNew.lParam);

        // Get the subkey names and sort them
        RefPtr<Array<StringPtr> > subKeyNames = parentKey->GetSubKeyNames();
        Array<StringPtr>::Sort(subKeyNames, 
            StringComparer::get_InvariantCultureIgnoreCase());

        // Add the subkeys to the tree view
        FOREACH (StringPtr, keyName, subKeyNames) {
            RegistryKeyPtr subKey = parentKey->OpenSubKey(keyName);
            InsertTreeNode(subKey, keyName, 
                             pNMTreeView->itemNew.hItem, TVI_LAST);
        }
    }
}

The following code adds keys to the tree view:

HTREEITEM CRegViewerDlg::InsertTreeNode(RegistryKey* key, String* name, 
                               HTREEITEM hParent, HTREEITEM hInsertAfter) {
    key->AddRef(); // we'll release it in TVN_DELETEITEM

    CW2T nameT(name->GetCString());

    TVINSERTSTRUCT tvi;
    memset(&tvi, 0, sizeof(tvi));
    tvi.hParent = hParent;
    tvi.hInsertAfter = hInsertAfter;
    tvi.item.mask = TVIF_TEXT | TVIF_CHILDREN | TVIF_PARAM;
    tvi.item.pszText = nameT;
    tvi.item.lParam = reinterpret_cast<LPARAM>(key);
    tvi.item.cChildren = key->SubKeyCount;

    return this->_treeCtrl.InsertItem(&tvi);
}

As you can see, we should call AddRef when adding the key to the tree view to comply with our reference counting rules. We should release it in the TVN_DELETEITEM notification:

void CRegViewerDlg::OnTvnDeleteitemTree1(NMHDR* pNMHDR, LRESULT* pResult) {
    LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
    *pResult = 0;

    RegistryKey* key = 
      reinterpret_cast<RegistryKey*>(pNMTreeView->itemOld.lParam);
    key->Release();
}

5. Other minor updates and clean-up

For example, Directory::GetLogicalDrives.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
China China
Yingle Jia is a software engineer located in Beijing, China. He currently works at IBM CSDL (China Software Development Lab). His interests include C++/COM/C#/.NET/XML, etc. He likes coding and writing.

He is the creator of ACF (Another C++ Framework) project. See http://acfproj.sourceforge.net/.

He also has a blog at http://blogs.wwwcoder.com/yljia/

Comments and Discussions

 
GeneralGarbage Collection Pin
geoyar1-Jul-04 6:04
professionalgeoyar1-Jul-04 6:04 
GeneralRe: Garbage Collection Pin
Yingle Jia1-Jul-04 18:04
Yingle Jia1-Jul-04 18:04 
GeneralRe: Garbage Collection Pin
geoyar2-Jul-04 14:03
professionalgeoyar2-Jul-04 14:03 
QuestionWhere is the project zip? Pin
ggerules24-Jun-04 10:00
ggerules24-Jun-04 10:00 
AnswerRe: Where is the project zip? Pin
Dandy Cheung24-Jun-04 15:38
Dandy Cheung24-Jun-04 15:38 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.