Page 1 of 1

How to read the font size from AkelPad.ini file?

Posted: Wed Oct 20, 2010 8:39 pm
by KDJ
Hi, I have this problem.
AkelPad.ini contains an entry:
Font=F1FFFFFF000000000000000000000000900100000000000003020131
How to interpret this?
How to read font size (in point), style and others?
I mean the general principle.

Posted: Wed Oct 20, 2010 10:52 pm
by FeyFre
KDJ, in general case you will be not able to decode values in this option, because in easy to understand form they available only on graphics layer(i.e in Win GDI).

Read this article LOGFONT and you will understand whole thing(this option is actually dumped LOGFONT structure without last field lfFaceName, which have separate option in AkelPad).

Posted: Thu Oct 21, 2010 9:19 am
by Instructor
KDJ
AKD_GETFONTW?

Posted: Thu Oct 21, 2010 9:52 am
by FeyFre
Instructor
Думаю KDJ всё-таки желал разобраться как оно представляется в настроечном файле(значении реестра), а не через скрипты. Врочем одно-другому не мешает. :)

Posted: Thu Oct 21, 2010 5:32 pm
by KDJ
FeyFre, Instructor
Gentlemen, thank you very much for your help.
I'm trying to read the font size in the script.

Code: Select all

var hMainWnd = AkelPad.GetMainWnd();
var oSys = AkelPad.SystemFunction();
var hDC  = oSys.Call("user32::GetDC", hMainWnd);
var nDevCap = oSys.Call("gdi32::GetDeviceCaps" , hDC, 90 /*LOGPIXELSY*/);
var nFontSize = oSys.Call("kernel32::MulDiv", 0xF1FFFFFF, 72, nDevCap);
The result is nFontSize = -176160769.
In fact, the font size is 11 pt.
I do not understand this.

Posted: Thu Oct 21, 2010 5:58 pm
by Instructor
You were close :)

Code: Select all

var hMainWnd=AkelPad.GetMainWnd();
var hWndEdit=AkelPad.GetEditWnd();
var oSys=AkelPad.SystemFunction();

WScript.Echo("" + GetFontPoint(hWndEdit));

function GetFontPoint(hWndEdit)
{
  var lpLogFont;
  var lfHeight;
  var hDC;
  var nDevCap;
  var nPointSize=0;

  if (lpLogFont=AkelPad.MemAlloc(92 /*sizeof(LOGFONTW)*/))
  {
    AkelPad.SendMessage(hMainWnd, 1233 /*AKD_GETFONTW*/, hWndEdit, lpLogFont);
    lfHeight=AkelPad.MemRead(lpLogFont + 0 /*offsetof(LOGFONTW, lfHeight)*/, 3 /*DT_DWORD*/);

    if (hDC=oSys.Call("user32::GetDC", hWndEdit))
    {
      nDevCap=oSys.Call("gdi32::GetDeviceCaps", hDC, 90 /*LOGPIXELSY*/);
      nPointSize=-oSys.Call("kernel32::MulDiv", lfHeight, 72, nDevCap);
      oSys.Call("user32::ReleaseDC", hWndEdit, hDC);
    }
    AkelPad.MemFree(lpLogFont);
  }
  return nPointSize;
}

Posted: Thu Oct 21, 2010 8:17 pm
by KDJ
Thanks Instructor.
I suppose I understand.
In AklePad.ini file, the bytes are in reverse order. And lfHeight is negative.
Instead 0xF1FFFFFF, I should write 0xFFFFFFF1.

Code: Select all

var nFontSize = -oSys.Call("kernel32::MulDiv", 0xFFFFFFF1, 72, nDevCap);

Posted: Fri Oct 22, 2010 10:36 pm
by KDJ
I wrote the script FontIniSize.js, which sets the initial font size from AkelPad.ini file.
I was unable to load the font settings using the functions AKD_INIOPEN and AKD_INIGETVALUE. Problem solved otherwise.
The following code generates this error: type mismatch.

Code: Select all

var hMainWnd = AkelPad.GetMainWnd();
var pIniFile = AkelPad.GetAkelDir() + "\\AkelPad.ini";
var hIniFile = AkelPad.SendMessage(hMainWnd, 1366 /*AKD_INIOPEN*/, 0x1 /*POB_READ*/, pIniFile);

Posted: Fri Oct 22, 2010 10:42 pm
by FeyFre
KDJ
But you also should check if AkelPad stores settings in Registry.
(If, as you said, RegRead does not reads Binary values, you can use native API to read data from registry: advapi32::RegOpenKeyEx advapi32::RegQueryValueEx advapi32::RegCloseKey, etc see MSDN)

Posted: Sat Oct 23, 2010 11:58 am
by KDJ
FeyFre, thank you for the information.
I tried to read data from the registry (REG_BINARY type) using the method ActiveXObject("WScript.Shell").RegRead().
But the return value is "VBArray of integers".
JavaScript does not recognize this value (type=unknown).
Probably should write the script in VBS.
I will try to still do it in JS using Advapi32::RegQueryValueEx.

Posted: Sat Oct 23, 2010 7:49 pm
by KDJ
Unfortunately, I failed to read the registry value "HKLM\Software\ Akelsoft\AkelPad\Options\Font" in JS.
I tried these features:
oSys.Call("Advapi32.dll::RegOpenKeyExW", HKEY_CURRENT_USER, "Software\\Akelsoft\\AkelPad\\Options", 0, KEY_QUERY_VALUE, lphKey);
oSys.Call("Advapi32.dll::RegQueryValueExW", hKey, "Font", 0, lpType, lpData, lpSize);
and
oSys.Call("Advapi32.dll::RegOpenCurrentUser", KEY_QUERY_VALUE, lphKey);
oSys.Call("Advapi32.dll::RegGetValueW", hKey, "Software\\Akelsoft\\AkelPad\\Options", "Font", 0x0000FFFF, lpType, lpData, lpSize);

Posted: Sat Oct 23, 2010 9:02 pm
by FeyFre
KDJ
Probably you missed something.

Code: Select all

function MakeString(str)
{
	var res = AkelPad.MemAlloc((str.length+1)*_TSIZE);
	AkelPad.MemCopy(res, str, _TSTR);
	return res;
}
var HKCU = 0x80000001;
var KEY_QUERY_VALUE = 0x0001;
var DT_DWORD = 3;
var REG_BINARY = 3;
var ERROR_SUCCES = 0;
var ERROR_MORE_DATA = 234;

var SubKey = MakeString("SOFTWARE\\Akelsoft\\AkelPad\\Options");
var Value = MakeString("Font");
var LPKEY = AkelPad.MemAlloc(4);

var result = AkelPad.SystemFunction().Call("advapi32::RegOpenKeyEx"+_TCHAR,
			HKCU,					//! Parent key
			SubKey,					//! Subkey
			0,						//! Reserved. must be 0
			KEY_QUERY_VALUE,		//! Desired access
			LPKEY);					//! Result key
if(result == ERROR_SUCCES)
{
	var KEY = AkelPad.MemRead(LPKEY, DT_DWORD);
	var LPTYPE = AkelPad.MemAlloc(4);
		AkelPad.MemCopy(LPTYPE, REG_BINARY, DT_DWORD); //! I prefer to init this value
	var LPDATASIZE = AkelPad.MemAlloc(4);
		AkelPad.MemCopy(LPDATASIZE, 28, DT_DWORD);
	var BUFFER = AkelPad.MemAlloc(28);
	result = AkelPad.SystemFunction().Call("advapi32::RegQueryValueEx"+_TCHAR,
			KEY,		//! Parent key
			Value,		//! Value name
			0,			//! Must be NULL
			LPTYPE,		//! Value type receiver: will be REG_BINARY
			BUFFER,		//! Buffer
			LPDATASIZE);//! Buffer size
	if(	(result == ERROR_SUCCES || result == ERROR_MORE_DATA) &&
		(AkelPad.MemRead(LPTYPE, DT_DWORD)==REG_BINARY)&&	//! Must be binary
		(AkelPad.MemRead(LPDATASIZE, DT_DWORD)>=4)			//! Must be at least 4 bytes
		)
	{
		var lfHeight  =  AkelPad.MemRead(BUFFER,DT_DWORD);
		var hDC       =  AkelPad.SystemFunction().Call("user32::GetDC", AkelPad.GetMainWnd()); 
		var nDevCap   =  AkelPad.SystemFunction().Call("gdi32::GetDeviceCaps" , hDC, 90 /*LOGPIXELSY*/); 
		var nFontSize = -AkelPad.SystemFunction().Call("kernel32::MulDiv", lfHeight, 72, nDevCap); 
		AkelPad.SystemFunction().Call("user32::ReleaseDC", AkelPad.GetMainWnd(), hDC);
		AkelPad.MessageBox(0, "Size is: "+nFontSize, "Caption", 0);
	}
	AkelPad.SystemFunction().Call("advapi32::RegCloseKey",KEY);
	AkelPad.MemFree(BUFFER);
	AkelPad.MemFree(LPDATASIZE);
	AkelPad.MemFree(LPTYPE);
}
AkelPad.MemFree(LPKEY);
AkelPad.MemFree(Value);
AkelPad.MemFree(SubKey);

Posted: Sun Oct 24, 2010 4:35 pm
by KDJ
FeyFre, thanks.
Actually, I made a few mistakes.
I still have a few questions:
Why do you allocate memory at a string of one byte more?
Why do you initiate LPTYPE value?
Why DATASIZE must be at least 4 bytes?

Posted: Sun Oct 24, 2010 6:33 pm
by FeyFre
Why do you allocate memory at a string of one byte more?
First of all, not one byte bigger, byte one char bigger(1 byte for ANSI, 2 bytes for Unicode).
Because WINAPI works with so called Zero-terminated strings - arrays of chars which last element is zero(if you forget put zero there all functions will continue process string until they meet it).
Why do you initiate LPTYPE value?
It is my personal habit. In most cases I use functions which require pointers to initialized memory and I used to do such initializations whenever presence or absence such requirements.
Why DATASIZE must be at least 4 bytes?
Validation. Because I read 4 bytes from buffer later. In case when this options is broken(manually edited by nasty user) I will be sure I will not try to use invalid data.

Posted: Sun Oct 24, 2010 8:03 pm
by KDJ
For now I solved the problem of reading from the registry in VBS -> FontIniSize.vbs
Later I'll try to do it in JS. According to the lesson from FeyFre.