GitHub    Download    Forum
Overview
How to start
Download
Concepts
Detailed concepts
Tutorial
C++ API
C# API
WinRT API
DTDL
DADL
Setup
Download projects from GitHub

How to use DataFS

After installing DataFS and creating a new instance (see DataFS setup), you need to prepare the instance by extending the schema and create some named objects that your application can use as an entry point.

Create a DTDL file

A DTDL file defines the data types of your application. Those types form the 'schema' of a domain. You can share types with other applications (e.g. in common files and #include them in your project). But every application should bring its own schema extension in the form of a BDTD file that contains the full set of types it needs. Duplicated types are detected and reused during the schema extension process.
You can create a DTDL file in a text editor or in Visual Studio. If you use Visual Studio, create a C++ or C# project and then add a new item. Then select 'DTDL file'. This will add a file that will be compiled when the project compiles (or by right-clicking the file and selecting 'compile' in C++ projects). If you build the file in a text editor, you can also call the DTDL compiler yourself.
Sample DTDL file:
DTDL – DataDefinition.dtdl
["root object"]
class TestRoot [id({1B013DB1-5219-4363-9E02-BD85D7E24413})]
{
	wstring			RootName;
	TestObjectList	AllObjects;
};

["object list"]
list TestObjectList [id({3F96FB26-623E-4C52-86AF-2CBC89F5C23A}), ck]
{
	object			anObject;
	int32			theType;
};

/*
	the idea is to store objects of type 'TestObject'
	in the 'anObject' variable of the 'TestObjectList'
	items

	remark: it is no restriction!
*/
objecttype TestObjectList.anObject(TestObject);

// this class has no description
class TestObject [id({B06E97E6-15D7-4B70-B94F-679F858E0FE8})]
{
	wstring			Text;
	int32			Number;
};
This sample DTDL file defines 2 classes and a list. The idea is to build an object of type 'TestRoot' and then create multiple objects of type 'TestObject' and add them to the 'AllObjects' list attribute.

Extending the schema

After compiling the DTDL file, you receive a BDTD file, which can be used to extend the schema of the domain. To do that, you can either use DataFS_Tools or you can write a program that does it for you.
Remarks: The following sample program catches next to no errors. This is done to make it easier to see the main function. It is not advisable to work this way in production.
Example – SchemaPrep.cpp
Example – SchemaPrep.cs
C++
C#
#include "pch.h"

#include "resource.h"

#include <DataFS\Client\DataFS Client.h>
//using namespace DataFS;

int _tmain(int argc, wchar_t* argv[])
{
	const wchar_t* strServerAddress = argv[1];

	UINT16 usServerPort = (UINT16)_wtoi(argv[2]);

	GUID guidDomainId;
	::CLSIDFromString(argv[3], &guidDomainId);

	// connect

	DataFS::InitializeThread();

	DataFS::Connection* pConnection;
	DataFS::Connection_Create(&pConnection);

	if(FAILED(pConnection->ConnectW(strServerAddress, usServerPort, NULL)))
	{
		DataFS::Connection_Destroy(pConnection);
		DataFS::UninitializeThread();
		return -1;
	}

	// extend schema

	HRSRC hBdtd = ::FindResource(::GetModuleHandle(NULL), MAKEINTRESOURCE(IDR_RT_BDTD1), L"RT_BDTD");
	void* pBdtd = ::LockResource(::LoadResource(::GetModuleHandle(NULL), hBdtd));
	int iBdtdSize = ::SizeofResource(::GetModuleHandle(NULL), hBdtd);

	DataFS::USchemaEdit* pSchema;

	if(SUCCEEDED(pConnection->QuerySchemaEdit(&pSchema, &guidDomainId)))
	{
		pSchema->CreateFromBinary(pBdtd, iBdtdSize);
		pSchema->Commit();
		pSchema->Release();
	}

	pConnection->Disconnect();
	DataFS::Connection_Destroy(pConnection);
	DataFS::UninitializeThread();

	return 0;
}
using System;
using System.IO;

namespace SchemaPrep
{
	class SchemaPrep
	{
		static void Main(string[] args)
		{
			String strServerAddress = args[0];
			UInt16 usServerPort = UInt16.Parse(args[1]);
			Guid guidDomainId = Guid.Parse(args[2]);

			// connect

			DataFS.ThreadInit.InitializeThread();

			DataFS.Connection pConnection = DataFS.Connection.Create();

			if (0 > (pConnection.Connect(strServerAddress, usServerPort, null)))
			{
				DataFS.Connection.Destroy(pConnection);
				DataFS.ThreadInit.UninitializeThread();
				return;
			}

			// extend schema

			Stream sBdtd = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("DataDefinition");

			Byte[] pBdtd = new Byte[sBdtd.Length];
			sBdtd.Read(pBdtd, 0, (int)sBdtd.Length);

			DataFS.USchemaEdit pSchema;

			if (0 <= (pConnection.QuerySchemaEdit(out pSchema, guidDomainId)))
			{
				pSchema.CreateFromBinary(pBdtd);
				pSchema.Commit();
				pSchema.Dispose();
			}

			pConnection.Disconnect();
			DataFS.Connection.Destroy(pConnection);
			DataFS.ThreadInit.UninitializeThread();
		}
	}
}

Create a DADL file

A DADL file defines how you use the data types that you defined in the DTDL file. DADL files are specific to every application. Even when using the same DTDL types, you can use different DADL files and definitions. The DADL file is a way of generating access classes for your application so that you don’t have to write them by hand.
In theory, you don’t need DADL to work with DataFS. But it makes it much easier, because a lot of functions are generated.
You can create a DADL file in a text editor or in Visual Studio. If you use Visual Studio, create a C++ or C# project and then add a new item. Then select 'DADL file'. This will add a file that will be compiled when the project compiles (or by right-clicking the file and selecting 'compile' in C++ projects). If you build the file in a text editor, you can also call the DADL compiler yourself.

Preparing the database

After compiling the DADL file, you can use the classes it generated. The first step involves creating all the objects that your application will need as entry points in normal operation.
Remarks: The following sample program catches next to no errors. This is done to make it easier to see the main function. It is not advisable to work this way in production.
DADL – PrepareDefinition.dadl
#import <DataDefinition.bdtd>

object TestRoot
{
	TestRoot
	{
		RootName			[ get, set ];
	}
};

Example – StoragePrep.cpp
Example – StoragePrep.cs
C++
C#
#include "pch.h"

#include <DataFS\Access\DataFS Access.h>
using namespace DataFSAccess;

#include "_data\PrepareDefinition.h"

// {56F8EB44-B7E3-4564-B9A6-22E5E1B9110C}
const GUID guidRootName =
{ 0x56f8eb44, 0xb7e3, 0x4564, { 0xb9, 0xa6, 0x22, 0xe5, 0xe1, 0xb9, 0x11, 0xc } };

int _tmain(int argc, wchar_t* argv[])
{
	const wchar_t* strServerAddress = argv[1];

	UINT16 usServerPort = (UINT16)_wtoi(argv[2]);

	GUID guidDomainId;
	::CLSIDFromString(argv[3], &guidDomainId);

	UINT32 ulStorageId = 0;

	// connect

	InitializeThread();

	Connection* pConnection = Connection_Create();

	if(FAILED(pConnection->Initialize(&guidDomainId)))
	{
		Connection_Destroy(pConnection);
		UninitializeThread();
		return -1;
	}

	if(FAILED(pConnection->Connect(strServerAddress, usServerPort, NULL)))
	{
		pConnection->Uninitialize();
		Connection_Destroy(pConnection);
		UninitializeThread();
		return -1;
	}

	if(FAILED(pConnection->QueryStorage(ulStorageId, false)))
	{
		pConnection->DisconnectAll();
		pConnection->Uninitialize();
		Connection_Destroy(pConnection);
		UninitializeThread();
		return -1;
	}

	// build domain

	WDomain* pWDomain = Domain_Create();
	if(FAILED(pWDomain->Initialize(pConnection, 0)))
	{
		Domain_Destroy(pWDomain);
		pConnection->ReleaseAllStorages();
		pConnection->DisconnectAll();
		pConnection->Uninitialize();
		Connection_Destroy(pConnection);
		UninitializeThread();
		return -1;
	}

	// bind types

	PrepareDefinition::Bind(pWDomain);

	// create named object

	TestRoot* pRootObject;
	TestRoot::Create(&pRootObject, pWDomain, &DataFS::OBJECTID_NULL);

	pRootObject->SetRootName(L"first test root");

	pRootObject->Store();

	pWDomain->InsertNamedLink(&pRootObject->BuildLink(true), &guidRootName, L"first entry point");

	pWDomain->Execute(Transaction::Store, NULL);

	pRootObject->Release();

	// unbind types

	PrepareDefinition::Unbind();

	// destroy domain

	pWDomain->Uninitialize();
	Domain_Destroy(pWDomain);

	// disconnect

	pConnection->ReleaseAllStorages();
	pConnection->DisconnectAll();
	pConnection->Uninitialize();
	Connection_Destroy(pConnection);
	UninitializeThread();

	return 0;
}
using System;

using DataFSAccess;

namespace StoragePrep
{
	class StoragePrep
	{
		static readonly Guid guidRootName = new Guid("{56F8EB44-B7E3-4564-B9A6-22E5E1B9110C}");

		static void Main(string[] args)
		{
			String strServerAddress = args[0];
			UInt16 usServerPort = UInt16.Parse(args[1]);
			Guid guidDomainId = Guid.Parse(args[2]);

			UInt32 ulStorageId = 0;

			// connect

			ThreadInit.InitializeThread();

			Connection pConnection = Connection.Create();

			if (0 > pConnection.Initialize(guidDomainId))
			{
				Connection.Destroy(pConnection);
				ThreadInit.UninitializeThread();
				return;
			}

			if (0 > pConnection.Connect(strServerAddress, usServerPort, null, null))
			{
				pConnection.Uninitialize();
				Connection.Destroy(pConnection);
				ThreadInit.UninitializeThread();
				return;
			}

			if (0 > pConnection.QueryStorage(ulStorageId, false, null))
			{
				pConnection.DisconnectAll();
				pConnection.Uninitialize();
				Connection.Destroy(pConnection);
				ThreadInit.UninitializeThread();
				return;
			}

			// build domain

			WDomain pWDomain = WDomain.Create();
			if (0 > pWDomain.Initialize(pConnection, 0))
			{
				WDomain.Destroy(pWDomain);
				pConnection.ReleaseAllStorages();
				pConnection.DisconnectAll();
				pConnection.Uninitialize();
				Connection.Destroy(pConnection);
				ThreadInit.UninitializeThread();
				return;
			}

			// bind types

			PrepareDefinition.Bind(pWDomain);

			// create named object

			TestRoot pRootObject;
			TestRoot.Create(out pRootObject, pWDomain, DataFS.ObjectId.OBJECTID_NULL);

			pRootObject.SetRootName("first test root");

			pRootObject.StoreData(Transaction.Store);

			pWDomain.InsertNamedLink(pRootObject.BuildLink(true), guidRootName, "first entry point", Transaction.Store);

			pWDomain.Execute(Transaction.Store, null);

			pRootObject.Dispose();

			// unbind types

			PrepareDefinition.Unbind();

			// destroy domain

			pWDomain.Uninitialize();
			WDomain.Destroy(pWDomain);

			// disconnect

			pConnection.ReleaseAllStorages();
			pConnection.DisconnectAll();
			pConnection.Uninitialize();
			Connection.Destroy(pConnection);
			ThreadInit.UninitializeThread();
		}
	}
}

Using the database

After the database is built, you can use it by simply working with the generated W-Classes.
Remarks: The following sample program catches next to no errors. This is done to make it easier to see the main function. It is not advisable to work this way in production.
DADL – AccessDefinition.dadl
#import <DataDefinition.bdtd>

object TestRoot
{
	TestRoot
	{
		RootName			[ get, set ];
		AllObjects			[ get, set ];
	}
};

object TestObject
{
	TestObject
	{
		Text				[ get, set ];
		Number				[ get, set ];
	}
};

Example – SimpleObject.cpp
Example – SimpleObject.cs
C++
C#
#include "pch.h"

#include <DataFS\Access\DataFS Access.h>
using namespace DataFSAccess;

#include "_data\AccessDefinition.h"

// {56F8EB44-B7E3-4564-B9A6-22E5E1B9110C}
const GUID guidRootName =
{ 0x56f8eb44, 0xb7e3, 0x4564, { 0xb9, 0xa6, 0x22, 0xe5, 0xe1, 0xb9, 0x11, 0xc } };

int _tmain(int argc, wchar_t* argv[])
{
	const wchar_t* strServerAddress = argv[1];

	UINT16 usServerPort = (UINT16)_wtoi(argv[2]);

	GUID guidDomainId;
	::CLSIDFromString(argv[3], &guidDomainId);

	UINT32 ulStorageId = 0;

	// connect

	InitializeThread();

	Connection* pConnection = Connection_Create();

	if(FAILED(pConnection->Initialize(&guidDomainId)))
	{
		Connection_Destroy(pConnection);
		UninitializeThread();
		return -1;
	}

	if(FAILED(pConnection->Connect(strServerAddress, usServerPort, NULL)))
	{
		pConnection->Uninitialize();
		Connection_Destroy(pConnection);
		UninitializeThread();
		return -1;
	}

	if(FAILED(pConnection->QueryStorage(ulStorageId, false)))
	{
		pConnection->DisconnectAll();
		pConnection->Uninitialize();
		Connection_Destroy(pConnection);
		UninitializeThread();
		return -1;
	}

	// build domain

	WDomain* pWDomain = Domain_Create();
	if(FAILED(pWDomain->Initialize(pConnection, 0)))
	{
		Domain_Destroy(pWDomain);
		pConnection->ReleaseAllStorages();
		pConnection->DisconnectAll();
		pConnection->Uninitialize();
		Connection_Destroy(pConnection);
		UninitializeThread();
		return -1;
	}

	// bind types

	AccessDefinition::Bind(pWDomain);

	// open named object

	DataFS::ObjectId oiRootObject;

	pWDomain->QueryNamedLinkId(&guidRootName, 1, &oiRootObject, NULL);

	TestRoot* pRootObject;
	TestRoot::Open(&pRootObject, pWDomain, &oiRootObject);

	pRootObject->Load();
	pWDomain->Execute(Transaction::Load, NULL);

	// open the list for writing

	TestObjectList* pList;
	pRootObject->SetAllObjects(&pList);

	// create an add a new object

	TestObject* pTestObject;
	TestObject::Create(&pTestObject, pRootObject->GetObject());

	TestObjectListItem itm;
	itm.anObject = pTestObject->BuildLink(true);
	itm.theType = 12;

	pList->Insert(NULL, &itm);

	pTestObject->SetText(L"something");
	pTestObject->SetNumber(343);

	pTestObject->Store();
	pRootObject->Store();

	pWDomain->Execute(Transaction::Store, NULL);

	pTestObject->Release();
	pRootObject->Release();

	// unbind types

	AccessDefinition::Unbind();

	// destroy domain

	pWDomain->Uninitialize();
	Domain_Destroy(pWDomain);

	// disconnect

	pConnection->ReleaseAllStorages();
	pConnection->DisconnectAll();
	pConnection->Uninitialize();
	Connection_Destroy(pConnection);
	UninitializeThread();

	return 0;
}
using System;

using DataFSAccess;

namespace SimpleObjectCs
{
	class SimpleObject
	{
		static readonly Guid guidRootName = new Guid("{56F8EB44-B7E3-4564-B9A6-22E5E1B9110C}");

		static void Main(string[] args)
		{
			String strServerAddress = args[0];
			UInt16 usServerPort = UInt16.Parse(args[1]);
			Guid guidDomainId = Guid.Parse(args[2]);

			UInt32 ulStorageId = 0;

			// connect

			ThreadInit.InitializeThread();

			Connection pConnection = Connection.Create();

			if (0 > pConnection.Initialize(guidDomainId))
			{
				Connection.Destroy(pConnection);
				ThreadInit.UninitializeThread();
				return;
			}

			if (0 > pConnection.Connect(strServerAddress, usServerPort, null, null))
			{
				pConnection.Uninitialize();
				Connection.Destroy(pConnection);
				ThreadInit.UninitializeThread();
				return;
			}

			if (0 > pConnection.QueryStorage(ulStorageId, false, null))
			{
				pConnection.DisconnectAll();
				pConnection.Uninitialize();
				Connection.Destroy(pConnection);
				ThreadInit.UninitializeThread();
				return;
			}

			// build domain

			WDomain pWDomain = WDomain.Create();
			if (0 > pWDomain.Initialize(pConnection, 0))
			{
				WDomain.Destroy(pWDomain);
				pConnection.ReleaseAllStorages();
				pConnection.DisconnectAll();
				pConnection.Uninitialize();
				Connection.Destroy(pConnection);
				ThreadInit.UninitializeThread();
				return;
			}

			// bind types

			AccessDefinition.Bind(pWDomain);

			// open named object

			DataFS.Array<DataFS.ObjectId> aoiRootObject = new DataFS.Array<DataFS.ObjectId>();
			pWDomain.QueryNamedLinkId(new Guid[] { guidRootName }, aoiRootObject, null);

			TestRoot pRootObject;
			TestRoot.Open(out pRootObject, pWDomain, aoiRootObject.pData[0], 0, Transaction.Load);

			pRootObject.Load(_TestRoot.ALL_ATTRIBUTES, Transaction.Load);
			pWDomain.Execute(Transaction.Load, null);

			// open the list for writing

			TestObjectList pList;
			pRootObject.SetAllObjects(out pList);

			// create an add a new object

			TestObject pTestObject;
			TestObject.Create(out pTestObject, pRootObject.GetObject());

			TestObjectListItem itm = new TestObjectListItem();
			itm.anObject = pTestObject.BuildLink(true);
			itm.theType = 12;

			uint idx;
			pList.Insert(out idx, itm);

			pTestObject.SetText("something");
			pTestObject.SetNumber(343);

			pTestObject.StoreData(Transaction.Store);
			pRootObject.StoreData(Transaction.Store);

			pWDomain.Execute(Transaction.Store, null);

			pTestObject.Dispose();
			pRootObject.Dispose();

			// unbind types

			AccessDefinition.Unbind();

			// destroy domain

			pWDomain.Uninitialize();
			WDomain.Destroy(pWDomain);

			// disconnect

			pConnection.ReleaseAllStorages();
			pConnection.DisconnectAll();
			pConnection.Uninitialize();
			Connection.Destroy(pConnection);
			ThreadInit.UninitializeThread();
		}
	}
}
© 2025 Mobiland AG