You are currently browsing the Boolog blog archives for April, 2012


How to use VB regex in VC6

1,Open “OLE/COM object viewer” from Tool menu of VC6.
2,Find “Microsoft VBScript Regular Expressions 5.5” under “Type Libraries”.

3, Double click the node to open with “ITypeLib Viewer”.
4, Choose “Save As” and save as “vbscript.IDL”.

5, Run “midl vbscript.idl” in Command Propmt. midl.exe is typically located under “C:\Program Files\Microsoft Visual Studio\VC98\Bin”.

This creates “vbscript.tlb”.
6, Move this file into your VC6’s project directory.

7, By coding #import “vbscript.tlb” in your source file, VB regex will be available.

#include "stdafx.h"
 
#import "vbscript.tlb" no_namespace named_guids
 
_bstr_t vbregReplace(LPCTSTR source,
					 LPCTSTR replace, 
					 LPCTSTR regex,
					 BOOL bGlobal,
					 BOOL bCaseInsensitive)
{
	IRegExpPtr pReg;
	pReg.CreateInstance(CLSID_RegExp);
 
	_bstr_t bstrSource(source);
	_bstr_t bstrReplace(replace);
	_bstr_t bstrRegex(regex);
 
	pReg->put_Global(bGlobal?VARIANT_TRUE:VARIANT_FALSE); 
	pReg->put_IgnoreCase(bCaseInsensitive?VARIANT_TRUE:VARIANT_FALSE); 
	pReg->put_Pattern(bstrRegex); 
 
	_bstr_t bstrRet = pReg->Replace(bstrSource, bstrReplace);
 
	return bstrRet;
}
 
int main(int argc, char* argv[])
{
	CoInitialize(NULL);
	_bstr_t t = vbregReplace(
		"abcdefg",
		"x",
		"[aceg]",
		TRUE,
		TRUE);
 
	puts(t);
	CoUninitialize();
	return 0;
}

How to create a C++ function that can take argment of both char* and wchar_t*

Source.
Create a traits class that is used as specialized template. Specialize it for char and wchar_t. Generic template is not defined because this function is only for char and wchar_t.

#include <wchar.h>
#include <stdio.h>
 
template<typename T> struct kansuu_traits;
template<> struct kansuu_traits<char>
{
	static FILE* open(const char* p)
	{
		return fopen(p, "r");
	}
};
template<> struct kansuu_traits<wchar_t>
{
	static FILE* open(const wchar_t* p)
	{
		return _wfopen(p, L"r");
	}
};
 
template<typename cT> void kansuu(const cT* p)
{
	FILE* f = kansuu_traits<cT>::open(p);
	fclose(f);
}
 
int main(int argc, char* argv[]){
	kansuu(L"C:\\TEST\\Text.txt");
	kansuu("C:\\TEST\\Text.txt");
 
	return 0;
}

How to move file to a trash

Use SHFileOperation().

#include <windows.h>
#include <tchar.h>
#include <assert.h>
#include <malloc.h>
#include "SHDeleteFile.h"
 
BOOL SHDeleteFile(LPCTSTR lpFile)
{
	size_t len = _tcslen(lpFile);
	if(!lpFile || lpFile[0]==0 || len <= 3)
		return FALSE;
 
	// only fullpath allowed
	do
	{
#ifndef UNICODE
		if (IsDBCSLeadByte((BYTE)lpFile[0]))
			return FALSE;
#endif
 
		if( lpFile[0]==_T('\\') && lpFile[1]==_T('\\') )
			break;
 
		if( lpFile[1] == _T(':') && lpFile[2]==_T('\\') )
			break;
 
		return FALSE;
	} while(false);
 
	LPTSTR p = (LPTSTR)_alloca( (len+2)*sizeof(TCHAR) );
	if(!p)
		return FALSE;
	_tcscpy(p, lpFile);
	p[len+1]=0;
 
	SHFILEOPSTRUCT sfo = {0};
	sfo.hwnd = NULL;
	sfo.wFunc = FO_DELETE;
	sfo.pFrom = p;
	sfo.pTo   = NULL;  // ignored
	sfo.fFlags = FOF_ALLOWUNDO;
 
	int ret = SHFileOperation(&sfo);
	return ret==0;
}

This code is for single file. I did not know what happens when a folder is passed. sfo.pFrom and sfo.pTo must be a double-null terminated string.

System global variable in win32

class CSessionGlobalBool  
{
public:
	explicit CSessionGlobalBool(LPCSTR pName) {
		m_pName = (LPSTR)LocalAlloc(LMEM_FIXED, lstrlenA(pName)+sizeof(char));
		lstrcpy(m_pName, pName);
	}
	~CSessionGlobalBool(){
		LocalFree(m_pName);
	}
 
	operator bool() {
		return get();
	}
 
	operator =(const bool b) {
		HANDLE h = CreateEvent(NULL,
			TRUE,
			FALSE,
			m_pName);
 
		if(b)
			SetEvent(h);
		else
			ResetEvent(h);
	}
	operator =(const CSessionGlobalBool& sgb) {
		*this = sgb.get();
	}
private:
	bool get() const {
		HANDLE h = CreateEvent(NULL,
			TRUE,
			FALSE,
			m_pName);
 
		return WaitForSingleObject(h, 0) == WAIT_OBJECT_0;
	}
	LPSTR m_pName;
};

I’m using a manual-set event object. In fact this is not a system global variable but session global which each user have until she/he logged out.

The bool value read from this object is volatile, even the comparison of the same object could become false.

Add a debug console to your windows gui application

Call AllocConsole() at the beginning of your application. Only one console can be allocated for a process.

Next, call WriteConsole to show a text.

void CMyApp::LogDebug(LPCSTR p)
{
	if(m_bAppDebug)
	{
		DWORD d;
		WriteConsoleA(
			GetStdHandle(STD_OUTPUT_HANDLE),
			(CONST VOID *)p,
			strlen(p),
			&d,
			NULL
			);
		WriteConsoleA(
			GetStdHandle(STD_OUTPUT_HANDLE),
			(CONST VOID *)"\r\n",
			2,
			&d,
			NULL
			);
 
	}
}

I don’t know why but WriteConsole has Anscii and Unicode definition. Is there any differences?
I didn’t do a research for that now.
And at the end of your application, call FreeConsole().

You can also call WriteFile instead of WriteConsole, in this case the function can be used for both the console and a file.

In both cases, there is a chance standard handle is not as what you expected because the calling process can inherit or put a security on it. For example, if the application using above code was run from cygwin, the GetStdHandle() would fail.

Show a “We are Busy” page when your server is too busy by using PHP

If you are apache fan. You shold have many virtual host in your apache conf. But after your site getting popular, sometimes your server can not handle all request and your visitor will have to wait in front of the browser.

I could not find a nice solution for that so created one.

First, create a html page that will be shown when your server is busy.

<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<style type="text/css">
  #main  { background-color: #fcc; }
</style>
<title>We are busy</title>
</head>
 
<body>
<div id="main">
<p>
Many visitors are accessing my server or I'm encoding some movies on the server.
</p>
<p>
Wait just a few second and <a ref="javascript:location.reload()">reload</a>.
</p>
</div>
</body>
</html>

Save above file as “/phpGlobal/busy.html”. The directory can be anywhere as you like.

Next, create a php that check whether my server is heavy.

<?php
checkMachineState();
function checkMachineState()
{
        $a = @file_get_contents('/proc/loadavg');
        if(!$a) {
                return;
        }
        $a = explode(' ',$a);
 
        if($a[0] <= 3)
        // if(false)
        {
                return;
        }
        header ('HTTP/1.0 503 Service Temporarily Unavailable');
        require 'busy.html';
        exit();
}
?>

Save above as “/phpGlobal/check.php”
This will show “busy.html” when the load avarage exceeds 3.

Next, add this line on apache2.conf or your conf file.

php_value auto_prepend_file /phpGlobal/check.php

NOw when you restarts apache2. “check.php” will run before any php requests.

check.php uses UTF-8 that will disturb with your character code of your environment.
In that case, try to consider adding these lines to check.php.

@ini_set ( 'default_charset' , '');
header ('Content-Type: text/html; charset=UTF-8');

At last, you can see a current load average by using “top” command. At top right corner of the command output.

phpMyAdmin says “Cannot start session without errors, please check errors given in your PHP and/or webserver log file and configure your PHP installation properly.”

You need to create “tmp” directory where php saves session data. In windows its location is typically same folder as php.exe resides. Open phpinfo() and look for “session.save_path” for the actual path.