2009年5月15日星期五

A wonderful tool - DebugView

A wonderful tool - DebugView

Recently I am writing a HTA (Html application) program as below:
 

The black window above is an ActiveX control, which is designed to simulate the cmd window. Then I can make GUIs easily for some console programs and scripts.  Whiling writing such a program, I find the tool DebugView very useful.  In general we get the debug information from the output window of VS. The debugged program had to be attached to VS.

Now DebugView make it unnecessary. It can grasp the output strings without attaching. Following is the debug information in my own work.




2009年4月21日星期二

发现一个文件上传的好网站

发现一个文件上传的好网站

http://www.uploadmirrors.com/

这个网站不错,以后可以将一些源代码传上去share

2009年4月13日星期一

最简单的WIN32多线程程序

最简单的WIN32多线程程序

这个例子来自MSDN







    1 // crt_begthrdex.cpp
    2 // compile with: /MT
    3 #include <windows.h>
    4 #include <stdio.h>
    5 #include <process.h>
    6 
    7 unsigned Counter; 
    8 unsigned __stdcall SecondThreadFunc( void* pArguments )
    9 {
   10     printf( "In second thread...\n" );
   11 
   12     while ( Counter < 1000000 )
   13         Counter++;
   14 
   15     _endthreadex( 0 );
   16     return 0;
   17 } 
   18 
   19 int main()
   20 { 
   21     HANDLE hThread;
   22     unsigned threadID;
   23 
   24     printf( "Creating second thread...\n" );
   25 
   26     // Create the second thread.
   27     hThread = (HANDLE)_beginthreadex( NULL, 0, &SecondThreadFunc, NULL, 0, &threadID );
   28 
   29     // Wait until second thread terminates. If you comment out the line
   30     // below, Counter will not be correct because the thread has not
   31     // terminated, and Counter most likely has not been incremented to
   32     // 1000000 yet.
   33     WaitForSingleObject( hThread, INFINITE );
   34     printf( "Counter should be 1000000; it is-> %d\n", Counter );
   35     // Destroy the thread object.
   36     CloseHandle( hThread );
   37 }


2009年4月10日星期五

Enum Registry SubKeys in JScript

Enum Registry SubKeys in JScript

I have searched for a good solution to enum the registries with JScript for a long time. Today I got it. The original url is http://www.msghelp.net/showthread.php?tid=65331&page=1 .

The two functions are as below:

 
function EnumSubKeys(RegKey) {
    var RootKey = new Object()
    RootKey["HKCR"] = RootKey["HKEY_CLASSES_ROOT"] = 0x80000000;
    RootKey["HKCU"] = RootKey["HKEY_CURRENT_USER"] = 0x80000001;
    RootKey["HKLM"] = RootKey["HKEY_LOCAL_MACHINE"] = 0x80000002;
    RootKey["HKUS"] = RootKey["HKEY_USERS"] = 0x80000003;
    RootKey["HKCC"] = RootKey["HKEY_CURRENT_CONFIG"] = 0x80000005;
    var RootVal = RootKey[RegKey.substr(0, RegKey.indexOf("\\"))]
    if (RootVal != undefined) {
        Locator = new ActiveXObject("WbemScripting.SWbemLocator");
        ServerConn = Locator.ConnectServer(null, "root\\default");
        Registry = ServerConn.Get("StdRegProv");
        Method = Registry.Methods_.Item("EnumKey");
        p_In = Method.InParameters.SpawnInstance_();
        p_In.hDefKey = RootVal;
        p_In.sSubKeyName = RegKey.substr(RegKey.indexOf("\\") + 1)
        p_Out = Registry.ExecMethod_(Method.Name, p_In);
        return p_Out.sNames.toArray();
    }
}
 
 
function EnumValues(RegKey) {
    var RootKey = new Object()
    RootKey["HKCR"] = RootKey["HKEY_CLASSES_ROOT"] = 0x80000000;
    RootKey["HKCU"] = RootKey["HKEY_CURRENT_USER"] = 0x80000001;
    RootKey["HKLM"] = RootKey["HKEY_LOCAL_MACHINE"] = 0x80000002;
    RootKey["HKUS"] = RootKey["HKEY_USERS"] = 0x80000003;
    RootKey["HKCC"] = RootKey["HKEY_CURRENT_CONFIG"] = 0x80000005;
    var RootVal = RootKey[RegKey.substr(0, RegKey.indexOf("\\"))]
    if (RootVal != undefined) {
        Locator = new ActiveXObject("WbemScripting.SWbemLocator");
        ServerConn = Locator.ConnectServer(null, "root\\default");
        Registry = ServerConn.Get("StdRegProv");
        Method = Registry.Methods_.Item("EnumValues");
        p_In = Method.InParameters.SpawnInstance_();
        p_In.hDefKey = RootVal;
        p_In.sSubKeyName = RegKey.substr(RegKey.indexOf("\\") + 1)
        p_Out = Registry.ExecMethod_(Method.Name, p_In);
        return p_Out.sNames.toArray();
    }
}



The test code is following


var
Shell = new ActiveXObject("WScript.Shell")
var Key = "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\Run"
var ValuesArray = EnumValues(Key);
WScript.StdOut.WriteLine("=== Global startup ===")
for (Index in ValuesArray) {
    var ValueName = ValuesArray[Index]
    ValueValue = Shell.RegRead(Key + "\\" + ValueName)
    WScript.StdOut.WriteLine(ValueName + " = " + ValueValue)
}
var Key = "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
var ValuesArray = EnumSubKeys(Key);
WScript.StdOut.WriteLine("=== Uninstall startup ===")
for (Index in ValuesArray) {
    var ValueName = ValuesArray[Index]
    WScript.StdOut.WriteLine(ValueName);
}



2009年4月8日星期三

Edit控件的字体和颜色











Edit控件的字体和颜色

字体可以采用函数CreateFont来创建,如下面的例子所示


        CFont fnt;
        fnt.CreateFont(12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET, 
OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, _T("Lucida Console"));
        m_Edit.SetFont(fnt);
        fnt.Detach();


Edit控件的字体颜色,背景颜色需要在父窗口中处理消息WM_CTLCOLOREDIT,如下面的函数所示:


    LRESULT OnCtlColorEdit(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
    {
        CDC  dc((HDC)wParam);
        HWND hwnd = (HWND)lParam;
        HBRUSH hbr = 0;
 
        if (m_Edit.m_hWnd == hwnd)
        {
            dc.SetTextColor(RGB(192,192,192));
            dc.SetBkColor(RGB(0,0,0));
            hbr = CreateSolidBrush(RGB(0,0,0));
            bHandled = TRUE;
        }
        else
            bHandled = FALSE;
 
        dc.Detach();
 
        return (LRESULT)hbr;
    }


参考:http://forums.devx.com/showthread.php?t=83993

2009年4月2日星期四

WriteFile,WriteConsole和_tprintf的一些差别
















WriteFile,WriteConsole和_tprintf的一些差别

这几个API都是用于输出的,但都有各自的特点:
1. _tprintf的实现利用了WriteFile和WideCharToMultiByte。
2. WriteFile只接受字节流,没有UNICODE的概念,WriteFile可以实现重定向。
3. WriteConsole有两个版本WriteConsoleA和WriteConsoleW, 可以分别接收ANSI和UNICODE字符串,不支持重定向。


看下面这个简单的程序,编译后再用eXeScope分析一下Import

    1 #include <stdio.h>
    2 
    3 void wmain(int argc, wchar_t* argv[])
    4 {
    5     wprintf(L"Hello World\n");
    6 }

看了eXeScope的输出后,发现wprintf的实现利用了WideCharToMultiByte和WriteFile等API,在写入文件前首先是将UNICODE转换成多字节的。


然后本人试着直接调用API进行输出,分别使用了API WriteConsole和WriteFile
 
    1 #include <windows.h>
    2 
    3 #pragma comment(lib, "User32")
    4 #pragma comment(lib, "Kernel32")
    5 #pragma comment(linker, "/Entry:wmain")
    6 #pragma comment(linker, "/Merge:.rdata=.text")
    7 
    8 void *operator new[](unsigned int size){
    9     return HeapAlloc (GetProcessHeap(), NULL, size);
   10 }
   11 
   12 void operator delete[] (void* memblock){
   13     HeapFree (GetProcessHeap(), NULL, memblock);
   14 }
   15 
   16 bool WINAPI StdOut( wchar_t* lpString)
   17 {
   18     HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
   19     DWORD numOfCharsWritten=0;
   20     WriteConsole(hStdOut, lpString, lstrlen(lpString), &numOfCharsWritten, NULL);
   21 
   22     DWORD dwNum = WideCharToMultiByte(CP_OEMCP,NULL,lpString, -1, NULL, 0, NULL, false);
   23     char *pText = new char[dwNum];
   24     WideCharToMultiByte(CP_OEMCP,NULL,lpString,-1,pText,dwNum,NULL,false);
   25     BOOL bRet = WriteFile(hStdOut, pText, dwNum, &numOfCharsWritten, NULL);
   26     delete[] pText;
   27     return bRet;
   28 }
   29 
   30 void wmain()
   31 {
   32     wchar_t *pChar = L"Hello World!\n";
   33     StdOut(pChar);
   34 }

命令行编译 cl client.cpp /DUNICODE /D_UNICODE /LINK /ALIGN:16
程序执行结果为:
Hello World!
Hello World!


下面的程序Parent.cpp用于输出重定向


    1 #include "stdafx.h"
    2 #include <windows.h>
    3 #include <tchar.h>
    4 #include <stdio.h>
    5 
    6 HANDLE SpawnAndRedirect(LPCTSTR commandLine, HANDLE *hStdOutputReadPipe, LPCTSTR lpCurrentDirectory);
    7 
    8 int _tmain()
    9 {
   10     HANDLE hOutput, hProcess;
   11     hProcess = SpawnAndRedirect(_T("client.exe"), &hOutput, NULL);
   12     if (!hProcess){
   13         _tprintf(_T("Failed to spawn the thread\n"));
   14         return 1;
   15     }
   16 
   17     char buffer[129];
   18     DWORD read;
   19     while(ReadFile(hOutput, buffer, 128, &read, NULL))
   20     {
   21         buffer[read] = '\0';
   22         printf("%s\n", buffer);
   23     }
   24 
   25     CloseHandle(hOutput);
   26     CloseHandle(hProcess);
   27 
   28     return 0;
   29 }
   30 
   31 
   32 // The following function is a shortened variant of Q190351 - HOWTO: Spawn Console Processes with Redirected Standard Handles
   33 // There is no special magic here, and this version doesn't address issues like:
   34 // - redirecting Input handle
   35 // - spawning 16-bits process 
   36 // - command-line limitations (unsafe 1024-char buffer)
   37 // So you might want to use more advanced versions such as the ones you can find on CodeProject
   38 HANDLE SpawnAndRedirect(LPCTSTR commandLine, HANDLE *hStdOutputReadPipe, LPCTSTR lpCurrentDirectory)
   39 {
   40     HANDLE hStdOutputWritePipe, hStdOutput, hStdError;
   41     CreatePipe(hStdOutputReadPipe, &hStdOutputWritePipe, NULL, 0);  // create a non-inheritable pipe
   42     DuplicateHandle(GetCurrentProcess(), hStdOutputWritePipe,
   43         GetCurrentProcess(), &hStdOutput,                           // duplicate the "write" end as inheritable stdout
   44         0, TRUE, DUPLICATE_SAME_ACCESS);
   45     DuplicateHandle(GetCurrentProcess(), hStdOutput,
   46         GetCurrentProcess(), &hStdError,                            // duplicate stdout as inheritable stderr
   47         0, TRUE, DUPLICATE_SAME_ACCESS);
   48     CloseHandle(hStdOutputWritePipe);                               // no longer need the non-inheritable "write" end of the pipe
   49 
   50     PROCESS_INFORMATION pi;
   51     STARTUPINFO si;
   52     ZeroMemory(&si, sizeof(STARTUPINFO));
   53     si.cb = sizeof(STARTUPINFO);
   54     si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
   55     si.hStdInput  = GetStdHandle(STD_INPUT_HANDLE); // (this is bad on a GUI app)
   56     si.hStdOutput = hStdOutput;
   57     si.hStdError  = hStdError;
   58     si.wShowWindow = SW_HIDE;                       // IMPORTANT: hide subprocess console window
   59     TCHAR commandLineCopy[1024];                    // CreateProcess requires a modifiable buffer
   60     _tcscpy(commandLineCopy, commandLine);
   61     if (!CreateProcess(    NULL, commandLineCopy, NULL, NULL, TRUE,
   62         CREATE_NEW_CONSOLE, NULL, lpCurrentDirectory, &si, &pi))
   63     {
   64         CloseHandle(hStdOutput);
   65         CloseHandle(hStdError);
   66         CloseHandle(*hStdOutputReadPipe);
   67         *hStdOutputReadPipe = INVALID_HANDLE_VALUE;
   68         return NULL;
   69     }
   70 
   71     CloseHandle(pi.hThread);
   72     CloseHandle(hStdOutput);
   73     CloseHandle(hStdError);
   74     return pi.hProcess;
   75 }


调用Parent,这个程序会创建子进程Client,并且通过pipe将Client的输出定向为Parent的输出,程序的执行结果为
Hello World!
在Client中WriteConsole的输出没有重定向过来!





2009年3月31日星期二

有趣的HTA程序






有趣的HTA程序

下面的脚本是采用Javascript

    1 <head>
    2 <title>Hello World</title>
    3 <hta:application 
    4      applicationname="helloworld"
    5      scroll="no"
    6      border="5pt"
    7      borderstyle="raised"
    8      maximizebutton="yes"
    9      minimizebutton="yes"
   10      showintaskbar="yes"
   11      caption="yes"
   12      sysmenu="yes"
   13      singleinstance="yes"
   14 >
   15 </head>
   16 
   17 <script>
   18     function test(){
   19         alert ("Hello World");
   20     }
   21 </script>
   22 
   23 <body>
   24 <input type="button" value="Run Script" onClick="test()"><p> 
   25 </body>

这里的脚本采用vbscript

    1 <head>
    2 <title>Hello World</title>
    3 <hta:application 
    4      applicationname="helloworld"
    5      scroll="no"
    6      border="5pt"
    7      borderstyle="raised"
    8      maximizebutton="yes"
    9      minimizebutton="yes"
   10      showintaskbar="yes"
   11      caption="yes"
   12      sysmenu="yes"
   13      singleinstance="yes"
   14 >
   15 </head>
   16 
   17 <script language="VBScript">
   18     sub test
   19         msgbox "Hello World", vbExclamation, "Hello World"
   20     end sub
   21 </script>
   22 
   23 <body>
   24 <input type="button" value="Run Script" onClick="test"><p> 
   25 </body>

程序运行后的界面


2009年3月26日星期四

构造微小的EXE程序






构造微小的EXE程序

本文参考了网上的帖子《VC++下编译极小的程序》,《VC8中打造512字节超小应用程序》。废话不用说,直接上两个例子:

例子一: 一个Console程序


    1 #include <windows.h>
    2 
    3 #pragma comment(lib, "User32")
    4 #pragma comment(lib, "Kernel32")
    5 #pragma comment(linker, "/Entry:main")
    6 #pragma comment(linker, "/Merge:.rdata=.text")
    7 
    8 bool WINAPI StdOut( LPCTSTR lpString)
    9 {
   10     HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
   11     DWORD numOfCharsWritten=0;
   12     return WriteConsole(hStdOut, lpString, lstrlen(lpString), &numOfCharsWritten, NULL);
   13 }
   14 
   15 int main()
   16 {
   17     TCHAR *pChar = TEXT("Hello World!\n");
   18     StdOut(pChar);
   19 }


采用VC9命令行编译 cl minic.cpp /link /align:16,编译后大小为768 byte。


例子二: 一个窗口程序


    1 #include <windows.h>
    2 
    3 #pragma comment (lib,"user32.lib")
    4 #pragma comment (lib,"kernel32.lib")
    5 #pragma comment(linker, "/Entry:main")
    6 #pragma comment(linker, "/Merge:.rdata=.text")
    7 #pragma comment(linker, "/Subsystem:windows")
    8 
    9 void *operator new[](unsigned int size){
   10     return HeapAlloc (GetProcessHeap(), NULL, size);
   11 }
   12 
   13 void operator delete[] (void* memblock){
   14     HeapFree (GetProcessHeap(), NULL, memblock);
   15 }
   16 
   17 void main ()
   18 {
   19     TCHAR* str = new TCHAR[250];
   20     wsprintf (str, TEXT("The system has run %d\n"), GetTickCount());
   21     MessageBox (NULL,str,str,MB_ICONINFORMATION);
   22     delete[] str;
   23 }


采用VC9命令行编译 cl msgbox.cpp /link /align:16,编译后大小为944 byte。