myBase C/C++/JavaScript API

myBase software is built with our cross-platform free-form database engine (SSG.DLL), and provides a set of API for developing plug-in and add-on programs. On this webpage, We prepared several code snippets for demonstrating usage of myBase API and the way of how to make myBase plug-ins and add-ons.

myBase exposes its API in both C/C++ and JavaScript programming language, so that developers can choose one familiar language to extend/customize myBase functionality.

Note that myBase JavaScript API is provided by the nyfjs.dll plug-in, which binds myBase API with JavaScript programming language. In order to run plug-ins written in JavaScript, the nyfjs.dll plug-in must be properly installed into myBase add-ons folder. The nyfjs.dll plugin can be freely downloaded from on our download site.

JavaScript API Demo

JS Demo #1: Importing a .nyf database as sub branch

Using the 'plugin' interface in Javascript, it's so easy to import a specified .nyf file into the currently working .nyf database from within your script plugin.

var sSrcFn=platform.getOpenFileName('Insert .nyf file', 'nyf files|*.nyf|all files|*.*', false);
if(sSrcFn){
	plugin.importFromNyfFile(sSrcFn, '/Organizer/data/');
	plugin.refreshWhenDone(3);
}

JS Demo #2: Loading a .nyf database and traversing outline tree

This script demonstrates how to load a specific .nyf database, and traverse the outline tree, and make the indented outline text.

var f=new CLocalFile(plugin.getScriptFilePath()).getParent();
f.append('2009.nyf');
var nyf=new CNyfDb(f.getPath(), false);
var sTxt='';
nyf.traverseOutline('/Organizer/data', false, function(sPath, iLevel){
	var sHint=nyf.getFolderHint(sPath);
	if(sHint=='') sHint='new item ...'; else if(sHint==undefined) sHint='secured item ...';
	var sIndent=''; while(iLevel-->0) sIndent+='\t';
	sTxt+=(sIndent+sHint+'\n');
});
alert(sTxt);

JS Demo #3: Retrieving current note text

Use the currently working .nyf database, and display the current RTF note.

var nyf=new CNyfDb(-1);
var f=new CLocalFile(plugin.getCurPath(), '_~_~_notes.rtf');
var sRtf=nyf.loadAnsi(f);
alert(sRtf);
var sTxt=platform.extractTextFromRtf(sRtf);
alert(sTxt);

JS Demo #4: Exporting current branch as a new .nyf file

This script demonstrates how to export the current branch ans save in a new .nyf file.

var sCurPath=plugin.getCurPath();
if(sCurPath){
	//Prompt to select a filename to save the content;
	var sDstFn=platform.getSaveFileName('Export branch as file...', 'myBase .Nyf Files|*.nyf|All Files|*.*', '.nyf');
	if(sDstFn){
		//indicates myBase 5 to export the current branch, and save it in the specified target file;
		//as matter of fact, it appends the branch to the target .nyf database if it's already existing.
		if(plugin.exportBranchToNyfFile(sDstFn)){
			//indicates Windows Shell to open the newly generated .nyf file;
			//last parameter 'false' indicates not to wait for the process exit;
			if(confirm('Successfully generated the .nyf file. Do you want to open it now?')){
				platform.shellExecute('open', sDstFn, '', '', false);
			}
		}else{
			alert('Failed to export the branch.');
		}
	}
}else{
	alert('No database opened, or no content available to export.');
}

JS Demo #5: Providing two methods traversing the outline tree

This script demonstrates two methods traversing the outline tree. The method #1: traversing the outline tree by calling to the native function 'CNyfDb::traverseOutline'; The method #2: traversing the outline tree using the pure javascript code.

try{
	//First create an instance of CNyfDb, so we can retrieve info through SSG engine;
	//Parameter: -1 indicates to use the currently working database within myBase main window;

	var nyf=new CNyfDb(-1);

	var sTxt='';

	//'_act_on_treeitem' is a callback function which is passed into the 'traversal function' below.
	//the 'action' here is just to make a text tree during the tree traversal, and keep it in 'sTxt';

	var _act_on_treeitem=function(sPath, iLevel){

		var sHint=nyf.getFolderHint(sPath);
		if(sHint=='') sHint='new item ...'; else if(sHint==undefined) sHint='secured item ...';

		var sIndent=''; while(iLevel-->0) sIndent+='\t';

		sTxt+=(sIndent+sHint+'\n');

		//Uncommenting the below code may add 'attachments' into the text tree;

		//var v=nyf.enumFiles(sPath);
		//for(var i in v){
		//	var sName=v[i];
		//	sTxt+=(sIndent+'\t');
		//	sTxt+='<'+sName+'>';
		//	sTxt+='\n';
		//}

	};

	{
		sTxt='Method #1: traverse tree using the native C++ function\n';

		nyf.traverseOutline(plugin.getCurPath(), true, _act_on_treeitem);
		alert(sTxt);
	}

	{
		sTxt='Method #2: traverse tree using javascript code\n';

		var _traverseBranch=function(sPath, iLevel, _act){
			if(nyf.folderExists(sPath)){
				_act(sPath, iLevel);
				_traverseChildren(sPath, iLevel+1, _act);
			}
		};

		var _traverseChildren=function(sPath, iLevel, _act){
			var v=nyf.enumFolders(sPath);
			for(var i in v){
				var sName=v[i];
				if(sName) _traverseBranch(sPath+'/'+sName, iLevel, _act);
			}
		};

		_traverseBranch(plugin.getCurPath(), 0, _act_on_treeitem);
		alert(sTxt);
	}

}catch(e){
	alert(e);
}

JS Demo #6: Extracting all Email addresses from within RTF notes

This script demonstrates a way to extract all Email addresses from within the RTF notes under the current branch, results are saved in a specified text file.

try{
	var nyf=new CNyfDb(-1); //uses the currently working .nyf database.

	//counts how many info items under the current branch, for indicating progress.
	var nFolders=0;
	nyf.traverseOutline(plugin.getCurPath(), true, function(){
		nFolders++;
	});

	//initializes the progress bar with a message and a range;
	plugin.initProgressRange('Traversing...', nFolders);

	var _isDigit=function(ch){return (ch >= '0' && ch <= '9');};
	var _isAlpha=function(ch){return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');};

	var mAddrs={};

	var _act_on_treeitem=function(sPath, iLevel){
		var sRtf=nyf.loadAnsi(sPath+'/'+'_~_~_notes.rtf');
		var sTxt=platform.extractTextFromRtf(sRtf);
		var vLines=sTxt.split('\n');
		for(var i=0; i < vLines.length; ++i){
			var s=(vLines[i]||'').toLowerCase();
			while(s){
				var p=s.indexOf('@');
				if(p == 0){
					s=s.substr(1);
				}else if(p > 0){
					var p1=p-1, p2=p+1;
					while(p1 >= 0){
						var ch=s.charAt(p1);
						if( _isDigit(ch) || _isAlpha(ch) || ch=='-' || ch=='_' || ch=='+' ){
							p1--;
							continue;
						}else{
							break;
						}
					}
					while(p2 < s.length){
						var ch=s.charAt(p2);
						if( _isDigit(ch) || _isAlpha(ch) || ch=='-' || ch=='_' || ch=='.' ){
							p2++;
							continue;
						}else{
							break;
						}
					}
					var email=s.substring(p1+1, p2); s=s.substring(p2);

					//TODO: validating the email address using RegExp;

					var n=mAddrs[email]||0;
					mAddrs[email]=n+1;
				}else{
					break;
				}
			}
		}
		plugin.ctrlProgressBar(nyf.getFolderHint(sPath), 1);
	};

	var sFn=platform.getSaveFileName('Save email addresses as file'
		, 'Text files (*.txt)|*.txt|All files(*.*)|*.*', '.txt');

	if(sFn){

		nyf.traverseOutline(plugin.getCurPath(), true, _act_on_treeitem);

		var s='', nAddr=0;
		for(var a in mAddrs){
			if(s) s+='\r\n';
			s+=a;
			//s+=(' ('+mAddrs[a]+')'); //occurrance num;
			nAddr++;
		}

		if(s){
			var f=new CLocalFile(sFn);
			f.saveAnsi(s);
			if(confirm('Total '+nAddr+' Email addresses extracted and saved in: '
				+sFn+'\n\nDo you want to view the resulting file?')){
				f.launch('open');
			}
		}else{
			alert('No Email addresses found.');
		}
	}

}catch(e){
	alert(e);
}

JS Demo #7: Extracting possible data records and saving with Microsoft Excel

This script demonstrates a way to extract possible data records from within the RTF notes under the current branch, results are transferred into Microsoft Excel and saved in a specified .xls file. The data records in RTF text are formatted in the form 'key=val', and each field takes a separate line, like this:
Last Name =
First Name =
Company =
Street =
ZIP =
City =
FullCity =
Country =
State / Province =
Phone =
Fax =
E-Mail =

//This is the definition for field names, that you can customize to suit your needs.
var vFieldNames='Last Name|First Name|Company|Street|ZIP|City|FullCity|Country|State / Province|Phone|Fax|E-Mail'.split('|');

//To trim begining and trailing blank spaces from a string;
var trim=function(s){return (s||'').replace(/^\s+|\s+$/g, '');};

//To determine index of an element in an Array;
Array.prototype._indexOf=function(xPred)
{
	if(typeof(xPred)=='function'){
		for(var i=0; i < this.length; ++i){
			if(xPred(i, this[i])) return i;
		}
	}else{
		for(var i=0; i < this.length; ++i){
			if(this[i]==xPred) return i;
		}
	}
	return -1;
};

try{

	var xls=new CAppExcel(); //Launches Microsoft Excel through OLE Automation;

	var wbs=xls.getWorkbooks(), wb=wbs.add(), wss=wb.getWorksheets(), ws=wss.getItem(1), rng=ws.getCells();;

	ws.setName("Resulting Records");

	//The first row displays the field names;
	var iRow=1;
	for(var i=0; i < vFieldNames.length; ++i){
		var sName=vFieldNames[i];
		rng.setItem(iRow, i+1, sName);
	};

	iRow++;

	var nyf=new CNyfDb(-1); //uses the currently working .nyf database;

	//counts how may info items under the current branch, for indicating progress;
	var nFolders=0;
	nyf.traverseOutline(plugin.getCurPath(), true, function(){
		nFolders++;
	});

	//initializes the progress bar with a message and a range number;
	plugin.initProgressRange('Traversing...', nFolders);

	var _act_on_treeitem=function(sPath, iLevel){
		var sRtf=nyf.loadAnsi(sPath+'/'+'_~_~_notes.rtf');
		var sTxt=platform.extractTextFromRtf(sRtf);
		var bFound=false;
		var vLines=sTxt.split('\n');
		for(var i=0; i < vLines.length; ++i){
			var sLine=vLines[i];
			var p=sLine.indexOf('=');
			if(p>0){
				var sKey=trim(sLine.substring(0, p)), sVal=trim(sLine.substring(p+1));
				p=vFieldNames._indexOf(sKey);
				if(p>=0 && sVal){
					rng.setItem(iRow, p+1, sVal);
					bFound=true;
				}
			}
		}
		if(bFound) iRow++;
		plugin.ctrlProgressBar(nyf.getFolderHint(sPath), 1);
	};

	//var sFn=new CLocalFile(plugin.getScriptFilePath()).getParent(); sFn.append('123.xls');
	var sFn=platform.getSaveFileName('Save data records as file', 'MS-Excel spreadsheets (*.xls)|*.xls|All files(*.*)|*.*', '.txt');

	if(sFn){

		nyf.traverseOutline(plugin.getCurPath(), true, _act_on_treeitem);

		var f=new CLocalFile(sFn);

		//You might want to revise this line, in case an important file is accidentally deleted;
		if(f.exists()) f.remove();

		wb.saveAs(f);

		_gc(); //lets js perform garbage collection, optionally;

		if(confirm('Total '+(iRow-1)+' data records extracted and saved in: '+f+'.\n\nDo you want to view the spreadsheet?')){
			xls.setVisible(true); //f.launch('open', '', '', false);
		}else{
			xls.quit();
		}
	}

}catch(e){
	alert(e);
}

C/C++ API Demo

C++ Demo #1: Opening a .nyf database

The code snippet listed below demonstrates how to open an SSG based database file to obtain a database handle, and then save changes, and finally close it.

#include <io.h>
#include <iostream>
#include "ssg_dll.h"

_CWrapperSSGDLL ssgdll("ssg.dll"); //load the ssg.dll and import API functions.

static char* __stdcall _GetPasswdCallback(const char* fullpath, const char* hint, int id)
{
	//you may give a popup window here, so end-users can supply a password if required.
	//if you do, you should give a different prompt message for either database or ssg folders;
	//if you don't use the password option, simply return NULL;
	return NULL;
}

int main(void)
{
	const char* dbfile="./dbfile0.nyf"; //the file must exist;

	if(access(dbfile, 0)<0){
		//first create the new file if it doesn't exist;
		FILE* pf=fopen( dbfile, "w+" );
		if(pf){
			fclose(pf);
		}
	}

	H_DB hdb=ssgdll.ssg_open(dbfile, false, ::_GetPasswdCallback);
	if(hdb!=NULL){

		//do something here ...

		//if you made changes to the database, save the changes here;
		ssgdll.ssg_save(hdb);

		//should close the database before exiting;
		ssgdll.ssg_close(hdb);

		std::cout << "Successfully opened the database " << dbfile << std::endl;

	}else{
		std::cout << "Failed to open the database " << dbfile << std::endl;
	}

	return 0;
}

C++ Demo #2: Getting properties of a database

The code snippet listed below demonstrates how to query for states/properties of an open SSG database.

#include <io.h>
#include <iostream>
#include "ssg_dll.h"

_CWrapperSSGDLL ssgdll("ssg.dll"); //load the ssg.dll and import API functions.

int main(void)
{
	const char* dbfile="./dbfile0.nyf"; //the file must exist;

	if(access(dbfile, 0)<0){
		//first create the new file if it doesn't exist;
		FILE* pf=fopen( dbfile, "w+" );
		if(pf){
			fclose(pf);
		}
	}

	H_DB hdb=ssgdll.ssg_open(dbfile, false, NULL);
	if(hdb!=NULL){

		bool bModified=ssgdll.ssg_ismodified(hdb);
		std::cout << "The DB is " << (bModified ? "Dirty" : "Clean") << ".\n";

		bool bReadonly=ssgdll.ssg_isreadonly(hdb);
		std::cout << "The DB is open as " << (bReadonly ? "ReadOnly" : "Writable") << ".\n";

		//do something else here ...

		//if the database changed, save the changes;
		if(bModified) ssgdll.ssg_save(hdb);

		//should close the database before exiting;
		ssgdll.ssg_close(hdb);
	}

	return 0;
}

C++ Demo #3: Manipulating folders and files within a database

The code snippet listed below demonstrates how to create SSG folders and import/export SSG files. The sample code creates a SSG database file and inserts a file, and then export the file. After the file is inserted, you might want to try opening the generated database file with myBase, to see if the SSG file is inserted correctly.

#include <io.h>
#include <iostream>
#include "ssg_dll.h"

_CWrapperSSGDLL ssgdll("ssg.dll"); //load the ssg.dll and import API functions.

int main(void)
{
	const char* dbfile="./dbfile0.nyf"; //the file must exist;

	if(access(dbfile, 0)<0){
		//first create the new file if it doesn't exist;
		FILE* pf=fopen( dbfile, "w+" );
		if(pf){
			fclose(pf);
		}
	}

	H_DB hdb=ssgdll.ssg_open(dbfile, false, NULL);
	if(hdb){
		const char* ssgpath="\\organizer\\data\\item0\\";
		H_FOLDER hfolder=ssgdll.ssg_get_folder(hdb, ssgpath, true);
		if(hfolder){
			const char* ssgfile="\\Organizer\\data\\item0\\test_ssg_file.ini";
			const char* winfile="C:\\windows\\win.ini";
			int nBytes=ssgdll.ssg_import_file(hdb, ssgfile, winfile);
			if(nBytes<0) std::cout << "Failed to import the disk file\n";

			//after this, you'll see the 'win.ini' file when you load it with myBase.

			//now try to export the SSG file and save as another disk file;
			winfile="./win-0.ini";
			nBytes=ssgdll.ssg_export_file(hdb, ssgfile, winfile);
			if(nBytes<0) std::cout << "Failed to export the SSG file\n";

			//after this, you'll see the 'win-0.ini' file.
		}

		//do something else here ...

		//save the changes if modified;
		if(ssgdll.ssg_ismodified(hdb)) ssgdll.ssg_save(hdb);

		//close the database before exiting;
		ssgdll.ssg_close(hdb);
	}
	return 0;
}

C++ Demo #4: Listing folders and files

The code snippet listed below demonstrates how to enumerate child entries under a specified SSG folder. This Demo simply prints all child entries of a specific folder on the screen. The next Demo gives a more complex code which enumerates child entries recursively.

#include <io.h>
#include <iostream>
#include "ssg_dll.h"

_CWrapperSSGDLL ssgdll("ssg.dll"); //load the ssg.dll and import API functions.

static bool __stdcall _EnumEntryCallback(bool bFolder, const char* ssgname, const char* hint
	, __TEntryAttr attr, void* userdata)
{
	std::cout << (bFolder ? "Folder Entry:" : "File Entry:");
	std::cout << "  name=" << ssgname;
	std::cout << "  hint=" << hint;
	std::cout << "  attr=" << (int)attr;
	std::cout << "  data=" << (void*)userdata;
	std::cout << std::endl;
	return true;
}

int main(void)
{
	const char* dbfile="./dbfile0.nyf"; //the file must exist;

	if(access(dbfile, 0)<0){
		//first create the new file if it doesn't exist;
		FILE* pf=fopen( dbfile, "w+" );
		if(pf){
			fclose(pf);
		}
	}

	H_DB hdb=ssgdll.ssg_open(dbfile, true, NULL); //open as readonly here;
	if(hdb!=NULL){
		const char* ssgpath="\\organizer\\data\\item0\\";
		bool bSucc=ssgdll.ssg_enum_entries(hdb, ssgpath
				, ::_EnumEntryCallback, false, (void*)NULL);

		//do something here ...

		//should close the database before exiting;
		ssgdll.ssg_close(hdb);
	}
	return 0;
}

C++ Demo #5: Traversing folder tree

This example gives a a little bit more complex code which enumerates child entries recursively and prints all entries on console. In order to enumerate all child entries recursively, we prepared a few helper classes. The CSsgEntryInfo class describes attributes of an SSG entry. The _CSsgEntries is a container class, each item of which is an instance of the class 'CSsgEntryInfo'.

We first have all sub folders under a specific SSG folder temporarily saved in an Array (instance of the class '_CSsgEntries'), then iterate through the Array and print each folder's caption on the console. The folder's caption text are indented with 4 blank spaces. And then go on with next sub folder.

#include <io.h>
#include <iostream>
#include "ssg_dll.h"

_CWrapperSSGDLL ssgdll("ssg.dll"); //load the ssg.dll and import API functions.

struct _CSsgEntryInfo{

	bool		m_bFolder;
	std::string	m_sName;
	std::string	m_sHint;
	__TEntryAttr	m_iAttr;

	_CSsgEntryInfo(bool bFolder=FALSE
		, const char* name=NULL
		, const char* hint=NULL
		, __TEntryAttr attr=0)
		: m_bFolder(false)
		, m_sName(name?name:"")
		, m_sHint(hint?hint:"")
		, m_iAttr(attr)
	{
	}

	_CSsgEntryInfo(const _CSsgEntryInfo& d){*this=d;}

	const _CSsgEntryInfo& operator=(const _CSsgEntryInfo& d)
	{
		m_bFolder=d.m_bFolder;
		m_sName=d.m_sName;
		m_sHint=d.m_sHint;
		m_iAttr=d.m_iAttr;
		return *this;
	}

};

class _CSsgEntries : public std::vector<_CSsgEntryInfo>{

private:

	unsigned		m_iEntryType;

public:

	enum{
		  file=1
		, folder=2
		, any=file|folder
		, all=any
	};

	unsigned _gettype(void)const{return m_iEntryType;}

public:

	_CSsgEntries(unsigned iEntryType=any) : m_iEntryType(iEntryType){return;}

};

static bool __stdcall _EnumEntryCallback(bool bFolder, const char* ssgname, const char* hint
	, __TEntryAttr attr, void* userdata)
{
	_CSsgEntries* pvItems=(_CSsgEntries*)userdata;
	if(pvItems){
		bool bAdd=false;
		unsigned type=pvItems->_gettype();
		if(bFolder){
			if( type & _CSsgEntries::folder ) bAdd=TRUE;
		}else{
			if( type & _CSsgEntries::file ) bAdd=TRUE;
		}
		if(bAdd){
			pvItems->push_back(_CSsgEntryInfo(bFolder, ssgname, hint, attr));
		}
	}
	return true;
}

void _print_sub_entries(H_DB hdb, const char* ssgpath, const std::string& sIndent)
{
	_CSsgEntries vItems(_CSsgEntries::folder);
	ssgdll.ssg_enum_entries(hdb, ssgpath , ::_EnumEntryCallback, false, (void*)&vItems);
	_CSsgEntries::const_iterator it;
	for(it=vItems.begin(); it!=vItems.end(); ++it){
		std::string title=it->m_sHint; if(title.empty()) title="New Info Item...";
		std::cout << sIndent << title << std::endl;
		std::string subpath=std::string(ssgpath) + std::string("\\") + it->m_sName;
		::_print_sub_entries(hdb, subpath.c_str(), sIndent+"    "); //recursively...
	}
}

int main(void)
{
	const char* dbfile="./dbfile0.nyf"; //the file must exist;

	if(access(dbfile, 0)<0){
		//first create the new file if it doesn't exist;
		FILE* pf=fopen( dbfile, "w+" );
		if(pf){
			fclose(pf);
		}
	}

	H_DB hdb=ssgdll.ssg_open(dbfile, true, NULL); //open as readonly here;
	if(hdb!=NULL){
		const char* ssgpath="\\Organizer\\data";
		::_print_sub_entries(hdb, ssgpath, "");

		//do something here ...

		//should close the database before exiting;
		ssgdll.ssg_close(hdb);
	}
	return 0;
}

C++ Demo #6: A basic framework creating myBase plugin DLLs

This sample code gives a basic framework creating a plugin DLL. It tries to add two menu items onto myBase's main menu.

#include <windows.h>

BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
					 )
{
    switch (ul_reason_for_call)
	{
		case DLL_PROCESS_ATTACH:
		case DLL_THREAD_ATTACH:
		case DLL_THREAD_DETACH:
		case DLL_PROCESS_DETACH:
			break;
    }
    return TRUE;
}

int __stdcall _nyf_addon_validate(int a,int b)
{
	//must export this function, for myBase to examine the plugin DLL;
	return a+b+1; //+1 for nyf5 API Specs.
}

int __stdcall _nyf_addon_query_menuitems(char* buf, int max)
{
	//2006.8.5 prepare description text for the menu layout;
	
	char* entries=

	"\nmenu[0].PopupMenu=MAINMENU.FILE"
	"\nmenu[0].Caption=Sample1 ..."
	"\nmenu[0].Hint=This is a sample plugin for myBase"
	"\nmenu[0].ProcName=_nyf_addon_sample1_func"
	"\nmenu[0].Shortcut=Ctrl+Shift+Alt+1"

	"\nmenu[1].PopupMenu=MAINMENU.HELP"
	"\nmenu[1].Caption=About Sample1 ..."
	"\nmenu[1].Hint=Display info about the sample"
	"\nmenu[1].ProcName=_nyf_addon_sample1_about"
	"\nmenu[1].Shortcut=Ctrl+Shift+Alt+2"

	;

	//put into the return buffer, which receives up to 32KB text;
	::strcpy(buf, entries);

	//total 2 menu items being implemented in this DLL;
	return 2;
}

int __stdcall _nyf_addon_sample1_func(const char* param, char* ret)
{
	::MessageBox(::GetDesktopWindow()
		, "this is a sample plugin"
		, "sample1"
		, MB_OK|MB_ICONINFORMATION);

	return 0;
}

int __stdcall _nyf_addon_sample1_about(const char* param, char* ret)
{
	::MessageBox(::GetDesktopWindow()
		, "Sample Plugin version 1.0\nCopyright 2006 Wjjsoft.com"
		, "about sample1"
		, MB_OK|MB_ICONINFORMATION);

	return 0;
}

C++ Demo #7: A method extracting plugin parameters

This Demo gives a method extracting parameter values from the plugin parameters text. The plugin parameter text consists of several lines, each lines are formatted in the 'key=val' form, and separated with the linefeed '\n'.

#include <string>
#include <map>
#include <iterator>
#include <algorithm>
#include <windows.h>

class _CPluginParams{

public:

	std::string				m_sParams;
	std::map<std::string, std::string>	m_mParams;

protected:

	void _split_params(const char* lpszParam)
	{
		std::string params=lpszParam ? lpszParam : "";
		std::string::size_type p;
		do{
			p=params.find("\n");
			if(p!=std::string::npos){
				std::string line=params.substr(0, p);
				params=params.substr(p+1);
				if(!line.empty()){
					std::string::size_type x=line.find("=");
					if(x!=std::string::npos){
						std::string key=line.substr(0, x);
						std::string val=line.substr(x+1);
						if(!key.empty()){
							m_mParams[key]=val;
						}
					}
				}
			}
		}while(p!=std::string::npos);
	}

	std::string _find(const std::string& key)const
	{
		std::map<std::string, std::string>::const_iterator it=
		m_mParams.find(key);
		return (it!=m_mParams.end()) ? it->second : "";
	}

	struct __ansi_case_conv{
	 private:
		bool bUpper;
	 public:
		__ansi_case_conv(bool b):bUpper(b){return;}
		void operator()(char& c)const{c = bUpper ? ::toupper(c) : ::tolower(c);}
	};

	static std::string __upper(const std::string& str)
	{std::string s=str; std::for_each(s.begin(), s.end(), __ansi_case_conv(true)); return s;}
	static std::string __lower(const std::string& str)
	{std::string s=str; std::for_each(s.begin(), s.end(), __ansi_case_conv(false)); return s;}

public:

	_CPluginParams(const char* param) : m_sParams(param)
	{
		_split_params(param);
	}

	std::string _get_str(const std::string& key)const{return _find(key);}

	int _get_int(const std::string& key, int defval)const
	{
		std::string str=_get_str(key);
		if(!str.empty()){
			if(__lower(str).find("0x")==0){
				int val=0;
				if(1==::sscanf(str.c_str()+2,"%x",&val)){
					return val;
				}
			}else{
				return ::atoi(str.c_str());
			}
		}
		return defval;
	}

	HWND _get_hwnd(const std::string& key)const
	{
		return (HWND)_get_int(key, 0);
	}

};

int __stdcall _nyf_addon_validate(int a,int b)
{
	//must export this function, for myBase to examine the plugin DLL;
	return a+b+1; //+1 for nyf5 API Specs.
}

int __stdcall _nyf_addon_query_menuitems(char* buf, int max)
{
	//2006.8.5 prepare description text for the menu layout;
	
	char* entries=

	"\nmenu[0].PopupMenu=MAINMENU.FILE"
	"\nmenu[0].Caption=Sample2 ..."
	"\nmenu[0].Hint=This is a sample plugin for myBase"
	"\nmenu[0].ProcName=_nyf_addon_sample2_func"
	"\nmenu[0].Shortcut=Ctrl+Shift+Alt+3"

	"\nmenu[1].PopupMenu=MAINMENU.HELP"
	"\nmenu[1].Caption=About Sample2 ..."
	"\nmenu[1].Hint=Display info about the sample"
	"\nmenu[1].ProcName=_nyf_addon_sample2_about"
	"\nmenu[1].Shortcut=Ctrl+Shift+Alt+4"

	;

	//put into the return buffer, which receives up to 32KB text;
	::strcpy(buf, entries);

	//total 2 menu items being implemented in this DLL;
	return 2;
}

int __stdcall _nyf_addon_sample2_func(const char* param, char* ret)
{
	_CPluginParams xParams(param);

	//extracts the main frame's Windows Handle;
	HWND hWndParent=xParams._get_hwnd("MainFrame.hWnd");

	//extracts the index of the currently selected database;
	int iCurDb=xParams._get_int("RunningDB.iCurDB", -1);

	//converts the index into a string;
	char sTmp[32]; ::memset(sTmp, 0, sizeof(sTmp));
	::sprintf(sTmp, "%d", iCurDb);

	//make the database's key, like this: RunningDB[0].
	std::string dbkey="RunningDB[" + std::string(sTmp) + "].";

	//extracts the database's file path;
	std::string dbfile=xParams._get_str(dbkey+"sFilePath");

	std::string msg="Current DB File: " + dbfile;

	::MessageBox(hWndParent
		, msg.c_str() 
		, "sample2"
		, MB_OK|MB_ICONINFORMATION);

	return 0;
}

int __stdcall _nyf_addon_sample2_about(const char* param, char* ret)
{
	_CPluginParams xParams(param);

	HWND hWndParent=xParams._get_hwnd("MainFrame.hWnd");

	::MessageBox(hWndParent
		, "Sample Plugin version 1.0\nCopyright 2006 Wjjsoft.com"
		, "about sample2"
		, MB_OK|MB_ICONINFORMATION);

	return 0;
}

C++ Demo #8: Detecting myBase instances from within addons

There's another particular type of programs which would cooperate with myBase Desktop but will be running standalone. They're usually invoked from within other applications and can instruct myBase Desktop to perform certain operations. For this purpose, myBase Desktop provided a few API, which allows third-party programs to comminucate with myBase Desktop. We called this kind of programs 'Addons'. This term is used to distinguish them from 'Plugins' in case of confusion. For example, the WebCollect addon is based on the addon API, and is invoked from within web browsers and then will be running standalone. WebCollect gives a list of detected myBase instances so end-users can choose one to save the webpages. In order for an addon program to communiate with myBase Desktop, it needs to first detect instances of myBase Desktop and its frame window handle, then the addon program can send specific messages to myBase window. This section includes the sample C++ code which tries to demonstrate how to detect myBase instances.

#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <algorithm>
#include <windows.h>

#define		__NYFCLIENT_MAINWINDOW_CLASSNAME	"wjjsoft::nyfclient::mainform"
#define		__NYFEDIT_MAINWINDOW_CLASSNAME		"wjjsoft::nyfedit::mainform"

BOOL CALLBACK _EnumWindowsProc_myBase(HWND hWnd, LPARAM lParam)
{
	std::pair< std::string, std::vector<HWND>* >* pData=(std::pair< std::string, std::vector<HWND>* >*)lParam;

	std::string sClsName=pData ? pData->first : "";
	std::vector<HWND>* pvItems=(std::vector<HWND>*)(pData ? pData->second : NULL);

	if(!pvItems|| !hWnd || sClsName.empty()) return false;

	const int size=64;
	std::vector<TCHAR> buf(size+1, '\0');
	int x=::GetClassName(hWnd, &(buf[0]), size);
	if(x>0){
		if( sClsName == &buf[0] )
		pvItems->push_back(hWnd);
	}
	return true;
}

int _detect_myBase_windows(std::vector<HWND>& vItems)
{
	{
		//detect nyfedit.exe instances
		std::pair< std::string, std::vector<HWND>* > d0(__NYFEDIT_MAINWINDOW_CLASSNAME, &vItems);
		::EnumWindows((WNDENUMPROC)::_EnumWindowsProc_myBase, (LPARAM)&d0);
	}

	{
		//detect nyfclient.exe instances
		std::pair< std::string, std::vector<HWND>* > d0(__NYFCLIENT_MAINWINDOW_CLASSNAME, &vItems);
		::EnumWindows((WNDENUMPROC)::_EnumWindowsProc_myBase, (LPARAM)&d0);
	}
	return vItems.size();
}

struct _CPred_PrintWindowCaption{
	void operator()(HWND hWnd)
	{
		if(::IsWindow(hWnd)){
			int len=1024*4;
			std::vector<char> buf(len+1, '\0');
			::SendMessage(hWnd, WM_GETTEXT, (WPARAM)len, (LPARAM)(&(buf[0])));
			std::string title=&buf[0];
			std::cout << title << std::endl;
		}
	}

};

int main(void)
{
	std::vector<HWND> vItems;
	::_detect_myBase_windows(vItems);

	std::cout << "The following myBase instances detected:" << std::endl << std::endl;

	std::for_each(vItems.begin(), vItems.end(), _CPred_PrintWindowCaption());

	std::cout << std::endl;

	return 0;
}

Any Questions

If you're interested in making plug-ins/add-ons to extend myBase functionality, and having any questions please contact us.