Tuesday, February 10, 2009

A problem of forward declaration in C++/CLI

Today while I started debugging my program, the programmed stopped at
Assembly assembly=Assembly.Load(name)
foreach(Type type in assembly.GetTypes()
{
...
}
and the output window showed:
First-chance exception at 0x7c81eb33 (kernel32.dll) in myprogramm.exe: Microsoft C++ exception: EETypeLoadException at memory location 0x0012d324..
First-chance exception at 0x7c81eb33 (kernel32.dll) in myprogramm.exe: Microsoft C++ exception: [rethrow] at memory location 0x00000000..
A first chance exception of type 'System.Reflection.ReflectionTypeLoadException' occurred in mscorlib.dll
Later I found that all these happens due to a unresolved forward declaration of a ref class. but the unresolved native class will not cause the problem.

So be caution when you are using the forward declaration for a ref class.

Tuesday, January 13, 2009

Create console for nonconsole application.

First we need to create a console:
BOOL result=AllocConsole();
assert(result);
Then we need to get the handle to the console, and associate the console to the standard output stream:
HANDLE hOutput=CreateFile(L"CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
SetStdHandle(STD_OUTPUT_HANDLE,hOutput);
In CRT, we also need make the stdout usable:
#include
#include
int hCrt=_open_osfhandle((intptr_t)hOutput,_O_TEXT);
FILE* hf=_fdopen(hCrt,"w");
*stdout=*hf
If in C++/CLI, We also need to replace System::Console::Out:
ref class __ConsoleWriter : public TextWriter
{
private:
HANDLE handle;
__ConsoleWriter(HANDLE handle):handle(handle){}
public:
virtual property System::Text::Encoding^ Encoding
{
System::Text::Encoding^ get()override
{
return System::Text::Encoding::UTF8;
}
}
virtual void Write(array^ buffer, int index, int count)override
{
array^ bytes=Encoding->GetBytes(buffer, index, count);
pin_ptr p=&bytes[0];
DWORD n;
WriteFile(handle, (LPVOID)p, bytes->Length, &n, NULL);
}
};
//Redirect the CLR output
Console::SetOut(gcnew __ConsoleWriter(hOutput));

That's it, quite simple.

Monday, December 08, 2008

The buggy .net framework 2.0

I've been using the .net framework for years, my work didn't involved with the UI development for the most time, right now I'm developing a game editor for our game, in the months developing, I found some problems about the framework, and I'm sure they are bugs, I didn't tried them on .net framework 3.5, I don't know if these bugs have been resolved.

1st bug, the framework handles the shortcut keys incorrectly.
Associate a context menu strip to a control like TextBox, or place a MainMenuStrip on the form will take the same effect, make sure there is a menu item which have a shortcut key that could get conflicted with the textbox, like a Delete key. ok, run the program and press the key like Delete, you will find the key takes no effects in the control, this is a big problem that can not be ignored, you never need a standard text box that can only use Backspace but not the Delete key(if you have a shortcut with Backspace, you will only able to remove characters by using mouse's context menu), this problem quite sucks.
Hack Solution: Uses reflection to retrieve the FieldInfo shortcuts in type ToolStrip, overrides the control or the form's ProcessCmdKey, use the FieldInfo to access the private field of the context menu strip or main menu strip, it is a System.Collections.HashTable, if the hash table contains the shortcut(you need cast the wParam to type Keys), resend the message to the control that you wish to recieve the message.


2nd bug, the ScrollableControl resets the scrollbars' position when they get the focus again.
This bug happens if a ScrollableControl like Panel contains a child control which size is larger than the container and the ScrollableControl have AutoScroll assigned to true. If the ScrollbarControl have the none zero scrollbar's position, either the horizontal scrollbar or the vertical scrollbar, when it gains the focus, both the horizontal and vertical scrollbar's position will reset to zero.
Hack Solution: A really damn shit way to solve this, back up the AutoScrollPosition value of the ScrollableControl when the child control lost focus, when the child control gains the focus again, multiply the X and Y of the backed up value with -1, assign the result to the AutoScrollPosition.

Wednesday, July 18, 2007

v1.4.3 ogre-based application failed to execute

Windows doesn't provide any useful information, and the debugger only told one:
LDR: LdrpWalkImportDescriptor() failed to probe for its manifest, ntstatus 0xc0150002

This is a very rusty problem, later I found how to solve it.
The v1.4.3 ogre sdk require VS2005 SP1, you only need deploy your system with a directory, <vs>\vc\redist\x86\Microsoft.VC80.CRT
now the dialog will no longer pop up. enjoy your ogre time!

if another error dialog about directx poped up, just update to the newest directx redist.

Monday, June 25, 2007

Functional Lua

This article is written in the time I just learnt the lua.

Lua is a widely used embeded script language, and it supports almost all the modern features. although it does not integrated functional programming support, but it's features like built-in table type, stack-based vm, high order function and etcs makes functional possible.

First, look at an example about how high-order function is used in lua
function double(a)
return a*2;
end;
function add(a,b)
return a+b;
end;

function make_f(unop,binop)
return function(a,b) return unop(binop(a,b)); end
end;

f=make_f(double,add);
print(f(1,2))
Here we have three functions, their prototypes are
double: R->R
add: R*R->R
make_f: (R*R->R) * (R->R) ->R*R
We use function as variant and do algorithm on them.

With how to use high-order function in lua, now let's see how to implement the most commonly used functional operators, like map, filter and reduce( as an explanation, therefore I only use foldl), after we've done these fundamentals, we can try some *advanced* tricks to implement some interesting stuff, like function currying.

Before implement the elemental operators, we shall see the definition of them.

The map is defined as: for each number i in a range, there always exists V[i]=f(D[i]), then we use operator map to describe this behavior as V=map(f,D);
So we have a corresponding code like:
fps={}; -- abbreviation for functional programming support
fps.map=function(fn,list)
local result={}
local i;
for i=1,table.getn(list) do
result[i]=fn(list[i]);
end
return result;
end
The filter is defined as: for a sequence of numbers D, any of them will exists in a sequence V if and only if f(d) is true, here d is a item in the sequence D, abbreviated as V=filter(f,D)
The code is:
fps.filter=function(fn,list)
local result={}
local c=1;
local i;
for i=1,table.getn(list) do
if(fn(list[i])) then
result[c]=list[i];
c=c+
1;
end
end
return result;
end
And the last reduce have two forms, fold left and fold right. the fold left looks like:
operator {operand_1 operand_2 operand_3 ... ...operand_n}
->
{(operand_1 operator operand_2) operand_3 ... ...operand_n}
->
{((operand_1 operator operand_2) operator operand_3) ... ...operand_n}
->
((....((operand_1 operator operand_2) operator operand_3) operator... ) operator operand_n)
and the fold right is totally reversed, from right to left to reduce.
The foldl is:
fps.foldl=function(fn,init,list)
local ret=init;
local i;
for i=1,table.getn(list) do
ret=fn(ret,list[i])
end
return ret
end
After these definition is clear, the implementation of them is now wisable.

Now we want to caculate f(x)=x/(x+1) with x in range [1,7]:
function fps.range(lower,upper) -- we use this to create a ranged interval
local ret={}
local c=lower;
for i=1,upper-lower+1 do
ret[i]=c;
c=c+
1;
end;
return ret
end;

f=
function(x) return x/(x+1) end; --define the function f
f2=fps.map(f,fps.range(1,10));--caculate
for i=1,table.getn(f2) do --display them
print(f2[i])
end;
now we got the expected result. here we can simplify the output statements by using map operator:
fps.map(print,f2);

ok, let's combine these operators to see how strong functional programming is, now I give you an question, caculate Σ(Σ(1 to x)+3) for x in interval [1,1000] and x is even, you can try this in imperative style language, how long will you take it and ensure correctness?
By using these operator, the final code in lua would like:
add=function(a,b) return a+b;end;
is_even=
function(v) return math.mod(v,2)==0; end;
sum_add_3=
function(v) return foldl(add,0,range(1,v))+3; end;

print (
foldl (add,
0,
map(sum_add_3,
filter (is_even,
range(
1,1000)
) ) ) )
The result is 83710250.
Many parentheses, looks like lisp o(*^-^*)o

Ok, now we know much about these operators and their power, let's see a more powerful weapon. function currying.

Before begin implementing the function currying, we need to prepare some concepts, function closure. you can get the details of closures in lua in online ebook Programming in Lua.

First, let me explain what is function currying, so far as I know, that's the theory of a man called Haskell Brooks Curry #-_-, yeah, there's an great functional language Haskell, it's named after this brilliant logician.

Assume there is a function f with prototype ΠR^n->R (notation Π here indicates the R appears for n times in the domain), curry function f with ΠR^m (0<m<=n) will generate an high order function ΠR^m ->ΠR^(n-m)->R, or represent as prototype: (ΠR^n->R)*(ΠR^m) -> (ΠR^m ->ΠR^(n-m)->R)

This is my understand, may be it's not mathematically right :P

For a simple example, f(x,y,z)=x+y+z, curry this function with parameter 1 and 2, this will become f'(z)=1+2+z, the parameter x and y are reduced by the curry parameters, it becomes another function.

So we can imagine, implement a currying function, is actually stored the curry parameters in the function closure, and returns an high order function that accept the rest parameters to makes it looks like mathematically curried.

The lua has a stack based vm, all the operations are done via stack, what ever parameter passing or returnning values. and lua provides a function unpack, this function accept a table type parameter, and put all elements on the stack, so we can invoke a function like this:
function test(a,b,c,d,e,f,g)
print('a='..a);
print('b='..b);
print('c='..c);
print('d='..d);
print('e='..e);
print('f='..f);
print('g='..g);
end
test(unpack({1,2,3,4,5,6,7})) ;
The unpack returns data in the array parameter by pushing them on stack, and immediately call test, then the data in the array become the parameters of function test;
This is a very good mechanism to implement currying function, merge the curry parameters stored in the closure and passing parameters of the currying function into one array, unpack the array to stack and call the function being curried.

It seems the lua doesn't provide a direct function to merge two array into single one, so I wrote one:
table.merge=function(array1,array2)
local ret={}
local c=1;
for i=1,table.getn(array1) do
ret[c]=array1[i];
c=c+
1;
end
for i=1,table.getn(array2) do
ret[c]=array2[i];
c=c+
1;
end
return ret;
end;
With previous works, now write a curry procedure is no more difficult, only merge two kinds of parameters into one, and pass it to the original function and call it:
-- this curry function accepts a packed sequence of parameters
fps.curry2=function(fn,args)
local i;
return function(...)
local a=table.merge(args,arg);
local ret=fn(unpack(a));
return ret
end;
end;
-- this curry function accepts general passing parameters
fps.curry=function(fn,...)
return fps.curry2(fn,arg)
end;
Because this kind of implementation dont care the original function, the curry procedure can be nested.
How does this work? see some examples.
Sum numbers from 1 to 1000:

add=function(a,b) return a+b; end;--used to add two number
sum=curry(foldl,add,0);--make a curried function
print(sum(range(1,1000)))--caculate and display result
The code is pretty beautiful :) How does this done? the second parameter and nexts are stored in the closure sum as function foldl did, when applying the closure sum with parameter range(1,1000), the closure combine the previous parameters and the new incoming pararmeters together, and invoke the original function with them, return the function result.
This is how the magic is done, it's amazing and attractive, isn't it?

Does the currying will effect the performance? Yes, but the costs definitely can be ignore.
The curry version of previous complex caculation is:
add=function(a,b) return a+b;end;
is_even=
function(v) return math.mod(v,2)==0; end;
sum=curry(foldl,add,
0);
sum_add_3=
function(v) return sum(range(1,v))+3; end;

print(
sum(
map(sum_add_3,
filter (is_even,
range(
1,1000)
))))

Compare the caculation time with previous clean version, the curry version doesn't bring down too much, almost the same time with that.

After two weeks, my examinations will be done, I will have enough time to write technical articles on my blog, yeah~~~ there were almost for four months I ain't have time to write blog.

Thursday, February 15, 2007

China's New Year

It says that in the ancient age, there was a monster call Nian(or Year), with two acuminate horns, very ferocious, it lives in deep see, only crawl to the land every last night of the year, hurt people and animals. So every in that night, all the villagers will hide inside the mountains, to get away from Nian's hurt.
One last night of the year, villagers were preparing to leave like every years before, here comes a old man with all white hairs, he told a old woman, if she allowed to let him stay one night in her house, he can definitely can drive Nian away, but nobody give him a shit, they left as usual, the old man insisted to stay.
When the Nian rushed into the village that night, suddenly the old man fired firecrackers, Nian got frighten, and dare not to move forward even one step, Nian has fear with red color, fire flash and explodents. One gate opened, inside the yard, a old man in red laughed in a big voice, Nian left as much as it could while it saw the old man.
In the second day, villagers returned to the village, they found everything are still what they was. So they knew the old man with white hair is a god, he came to help them to drive Nian away, and they knew the three issues to drive Nian away. From that day on, in each last night of the year, every home stick red papers with nice words on them beside their gates, and every home fire firecrackers, keep light for a whole night, wait to the next year's first day.
This custom go round, now it becames china traditional most important and most ceremonious festival. And this day we called in chinese "Guo Nian", means the Nian past(Year past).

Wednesday, February 14, 2007

ASP.NET 2.0 returns a HTTP 404 Error

ASP.NET 2.0 support a new feature, when you need to maintaince your web site, you can put a empty file named app_offline.htm to the site's folder, if this file's size is less than 512 bytes, all request will get a HTTP 404 error, or redirect to app_offline.htm.

I met a problem, I didn't have such a app_offline.htm file, but I always get a http 404 error under .net 2.0(Server OS: Win2003), later i know, the IIS6 prohibited .net 2.0, if you want to reenable it, you need to run "aspnet_regiis -i -enable" under C:\windows\Microsoft.NET\Framework\v2.0.50727, this simple trick spend me hours to solve
#- -

Today is Valentine's Day, I'm single, I have nothing to do except doing my work, four days later, that will be Chinese traditional festival, Sprint Festival, all of us are busy preparing for that.

Tonight I want to write something about chinese new year.