打印调用堆栈

原文地址:http://blog.csdn.net/chief1985/article/details/4618492

java里面可以使用Throwable类来获取堆栈,示例代码如下:


package name.xu;
public class CallStack {
	public static void printCallStatck() {
		Throwable ex = new Throwable();
		StackTraceElement[] stackElements = ex.getStackTrace();
		if (stackElements != null) {
			for (int i = 0; i < stackElements.length; i++) {
				System.out.print(stackElements[i].getClassName()+"/t");
				System.out.print(stackElements[i].getFileName()+"/t");
				System.out.print(stackElements[i].getLineNumber()+"/t");
				System.out.println(stackElements[i].getMethodName());
				System.out.println("-----------------------------------");
			}
		}
	}
	
}

 

C#里面使用与java类似的方法,示例代码如下:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace TestProjectCSharp
{
    class CallStack
    {
        public static void printCallStack()
        {
            StackTrace ss = new StackTrace(true);
            String flName = ss.GetFrame(1).GetFileName();// GetMethod().DeclaringType; 
            int lineNo = ss.GetFrame(1).GetFileLineNumber();
            String methodName = ss.GetFrame(1).GetMethod().Name;
            Console.WriteLine(flName+"---"+lineNo+"---"+methodName);
        }
    }
}

 

c里面获取堆栈跟系统有关(主要是获取函数名称不一致,获取地址是一致的),
linux下使用backtrace和backtrace_symbols函数,示例代码如下:(编译方法:gcc -o funstack -rdynamic -ldl funstack.c)


//funstack.c
#define _GNU_SOURCE
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#if defined(REG_RIP)
# define SIGSEGV_STACK_IA64
# define REGFORMAT "%016lx"
#elif defined(REG_EIP)
# define SIGSEGV_STACK_X86
# define REGFORMAT "%08x"
#else
# define SIGSEGV_STACK_GENERIC
# define REGFORMAT "%x"
#endif
static void signal_segv(int signum, siginfo_t* info, void*ptr) {
        static const char *si_codes[3] = {"", "SEGV_MAPERR", "SEGV_ACCERR"};
        size_t i;
        ucontext_t *ucontext = (ucontext_t*)ptr;
#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)
        int f = 0;
        Dl_info dlinfo;
        void **bp = 0;
        void *ip = 0;
#else
        void *bt[20];
        char **strings;
        size_t sz;
#endif
#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)
# if defined(SIGSEGV_STACK_IA64)
        ip = (void*)ucontext->uc_mcontext.gregs[REG_RIP];
        bp = (void**)ucontext->uc_mcontext.gregs[REG_RBP];
# elif defined(SIGSEGV_STACK_X86)
        ip = (void*)ucontext->uc_mcontext.gregs[REG_EIP];
        bp = (void**)ucontext->uc_mcontext.gregs[REG_EBP];
# endif
        fprintf(stderr, "Stack trace:/n");
        while(bp && ip) {
                if(!dladdr(ip, &dlinfo))
                        break;
                const char *symname = dlinfo.dli_sname;
                fprintf(stderr, "% 2d: %p %s+%u (%s)/n",
                                ++f,
                                ip,
                                symname,
                                (unsigned)(ip - dlinfo.dli_saddr),
                                dlinfo.dli_fname);
                if(dlinfo.dli_sname && !strcmp(dlinfo.dli_sname, "main"))
                        break;
                ip = bp[1];
                bp = (void**)bp[0];
        }
#else
        fprintf(stderr, "Stack trace (non-dedicated):/n");
        sz = backtrace(bt, 20);
        strings = backtrace_symbols(bt, sz);
        for(i = 0; i < sz; ++i)
                fprintf(stderr, "%s/n", strings[i]);
#endif
        fprintf(stderr, "End of stack trace/n");
        return;
}
int setup_sigsegv() {
        struct sigaction action;
        memset(&action, 0, sizeof(action));
        action.sa_sigaction = signal_segv;
        action.sa_flags = SA_SIGINFO;
        if(sigaction(SIGUSR1, &action, NULL) < 0) {
                perror("sigaction");
                return 0;
        }
        return 1;
}

void func1()
{
        raise(SIGUSR1);
        return ;
}
void func2()
{
        raise(SIGUSR1);
        return ;
}
void entry()
{
        func1();
        func2();
        return;
}
int main()
{
        setup_sigsegv();
        entry();
}

 

windows下使用GetThreadContext ,StackWalk,SymGetOptions ,SymFunctionTableAccess,示例代码如下:


#include "SimpleSymbolEngine.h"
#include 
#include 
#include 
#include 
#include 
#include 
#pragma comment( lib, "dbghelp" )
static char const szRCSID[] = "$Id: SimpleSymbolEngine.cpp,v 1.4 2005/05/04 21:52:05 Eleanor Exp $";
//////////////////////////////////////////////////////////////////////////////////////
// Singleton for the engine (SymInitialize doesn't support multiple calls)
SimpleSymbolEngine& SimpleSymbolEngine::instance()
{
static SimpleSymbolEngine theEngine;
    return theEngine;
}
/////////////////////////////////////////////////////////////////////////////////////
SimpleSymbolEngine::SimpleSymbolEngine()
{
    hProcess = GetCurrentProcess();
    DWORD dwOpts = SymGetOptions();
    dwOpts |= SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS;
    SymSetOptions ( dwOpts );
    ::SymInitialize( hProcess, 0, true );
}
/////////////////////////////////////////////////////////////////////////////////////
SimpleSymbolEngine::~SimpleSymbolEngine()
{
    ::SymCleanup( hProcess );
}
/////////////////////////////////////////////////////////////////////////////////////
std::string SimpleSymbolEngine::addressToString( PVOID address )
{
    std::ostringstream oss;
    // First the raw address
    oss << "0x" <
MaxNameLength = sizeof( SymInfo ) – offsetof( tagSymInfo, symInfo.Name ); DWORD dwDisplacement; if ( SymGetSymFromAddr( hProcess, (DWORD)address, &dwDisplacement, pSym) ) { oss << ” ” <Name; if ( dwDisplacement != 0 ) oss << “+0x” << std::hex << dwDisplacement << std::dec; } // Finally any file/line number IMAGEHLP_LINE lineInfo = { sizeof( IMAGEHLP_LINE ) }; if ( SymGetLineFromAddr( hProcess, (DWORD)address, &dwDisplacement, &lineInfo ) ) { char const *pDelim = strrchr( lineInfo.FileName, ‘//’ ); oss << ” at ” << ( pDelim ? pDelim + 1 : lineInfo.FileName ) << “(” << lineInfo.LineNumber << “)”; } return oss.str(); } ///////////////////////////////////////////////////////////////////////////////////// // StackTrace: try to trace the stack to the given output void SimpleSymbolEngine::StackTrace( PCONTEXT pContext, std::ostream & os ) { os <Eip; stackFrame.AddrPC.Mode = AddrModeFlat; stackFrame.AddrFrame.Offset = pContext->Ebp; stackFrame.AddrFrame.Mode = AddrModeFlat; stackFrame.AddrStack.Offset = pContext->Esp; stackFrame.AddrStack.Mode = AddrModeFlat; while ( ::StackWalk( IMAGE_FILE_MACHINE_I386, hProcess, GetCurrentThread(), // this value doesn’t matter much if previous one is a real handle &stackFrame, pContext, NULL, ::SymFunctionTableAccess, ::SymGetModuleBase, NULL ) ) { os << ” 0x” << (PVOID) stackFrame.AddrFrame.Offset << ” ” << addressToString( (PVOID)stackFrame.AddrPC.Offset ) << “/n”; } os.flush(); }

 

完整的代码到http://www.howzatt.demon.co.uk/articles/SimpleSymbolEngine.zip下载。http://www.codeproject.com/KB/threads/StackWalker.aspx里面也有例子。

参考:

http://www.diybl.com/course/3_program/java/javashl/2008119/96739.html

http://topic.csdn.net/u/20090618/11/7c19832a-975e-4be6-987b-e61d789b31b5.html

http://bbs3.chinaunix.net/viewthread.php?tid=950357&extra=&page=2

http://www.codeproject.com/KB/threads/StackWalker.aspx

http://topic.csdn.net/u/20070515/21/fc3ebc11-b871-4761-90ae-3c6ddc7b4248.html

http://www.diybl.com/course/3_program/c++/cppjs/20090403/163752_2.html

http://accu.org/index.php/journals/276

http://blog.thepimp.net/archives/how-to-generate-backtraces-on-windows-without-compiler.html

———-淡定的分割线———-

codeproject的例子可以编译通过,但是运行报错。又找到第二个更简洁的可行例子。

原文地址:http://blog.csdn.net/jfyy/article/details/6759243


BOOL WINAPI StackWalk64(
    __in      DWORD MachineType,
    __in      HANDLE hProcess,
    __in      HANDLE hThread,
    __inout   LPSTACKFRAME64 StackFrame,
    __inout   PVOID ContextRecord,
    __in_opt  PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
    __in_opt  PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
    __in_opt  PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
    __in_opt  PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
    );

而后将原文中的的方法简单做了修改和封装。

调用方法: vector CallStack::GetCallStack();

#include 
#include 
#include 
#include 

#define MAX_ADDRESS_LENGTH 32
#define MAX_NAME_LENGTH 1024
using namespace std;

struct CrashInfo
{
    char ErrorCode[MAX_ADDRESS_LENGTH];
    char Address[MAX_ADDRESS_LENGTH];
    char Flags[MAX_ADDRESS_LENGTH];
};

// CallStack信息
//
struct CallStackInfo
{
    char ModuleName[MAX_NAME_LENGTH];
    char MethodName[MAX_NAME_LENGTH];
    char FileName[MAX_NAME_LENGTH];
    char LineNumber[MAX_NAME_LENGTH];
};


class CallStack
{
public:
    CallStack(void);
    ~CallStack(void);
    static vector GetCallStack();

protected:
    static void SafeStrCpy(char* szDest, size_t nMaxDestSize, const char* szSrc);
    static vector GetCallStack(const CONTEXT *pContext);
    static CrashInfo GetCrashInfo(const EXCEPTION_RECORD *pRecord);
};


#include "StdAfx.h"
#include "CallStackInfo.h"


// 添加对dbghelp.lib的编译依赖   
//   
#pragma comment(lib, "dbghelp.lib")
#pragma once


CallStack::CallStack(void)
{
}

CallStack::~CallStack(void)
{
}

// 安全拷贝字符串函数
//   
void CallStack::SafeStrCpy(char* szDest, size_t nMaxDestSize, const char* szSrc)
{
    if (nMaxDestSize <= 0)
        return;
    if (strlen(szSrc) ExceptionAddress);
    sprintf_s(crashinfo.ErrorCode, "%08X", pRecord->ExceptionCode);
    sprintf_s(crashinfo.Flags, "%08X", pRecord->ExceptionFlags);

    return crashinfo;
}


vector CallStack::GetCallStack()
{
    CONTEXT context;
    HANDLE hThread = GetCurrentThread();

    // get context
    context.ContextFlags = (CONTEXT_FULL);
    if (GetThreadContext(hThread, &context))
    {
        return GetCallStack(&context);
    }
    else{
        vector arrCallStackInfo;
        return arrCallStackInfo;
    }

}

// 得到CallStack信息
//   
vector CallStack::GetCallStack(const CONTEXT *pContext)
{
    HANDLE hProcess = GetCurrentProcess();

    SymInitialize(hProcess, NULL, TRUE);

    vector arrCallStackInfo;

    CONTEXT c = *pContext;

    STACKFRAME64 sf;
    memset(&sf, 0, sizeof(STACKFRAME64));
    DWORD dwImageType = IMAGE_FILE_MACHINE_I386;

    // 不同的CPU类型,具体信息可查询MSDN
    //
#ifdef _M_IX86   
    sf.AddrPC.Offset = c.Eip;
    sf.AddrPC.Mode = AddrModeFlat;
    sf.AddrStack.Offset = c.Esp;
    sf.AddrStack.Mode = AddrModeFlat;
    sf.AddrFrame.Offset = c.Ebp;
    sf.AddrFrame.Mode = AddrModeFlat;
#elif _M_X64   
    dwImageType = IMAGE_FILE_MACHINE_AMD64;
    sf.AddrPC.Offset = c.Rip;
    sf.AddrPC.Mode = AddrModeFlat;
    sf.AddrFrame.Offset = c.Rsp;
    sf.AddrFrame.Mode = AddrModeFlat;
    sf.AddrStack.Offset = c.Rsp;
    sf.AddrStack.Mode = AddrModeFlat;
#elif _M_IA64   
    dwImageType = IMAGE_FILE_MACHINE_IA64;
    sf.AddrPC.Offset = c.StIIP;
    sf.AddrPC.Mode = AddrModeFlat;
    sf.AddrFrame.Offset = c.IntSp;
    sf.AddrFrame.Mode = AddrModeFlat;
    sf.AddrBStore.Offset = c.RsBSP;
    sf.AddrBStore.Mode = AddrModeFlat;
    sf.AddrStack.Offset = c.IntSp;
    sf.AddrStack.Mode = AddrModeFlat;
#else   
#error "Platform not supported!"
#endif   

    HANDLE hThread = GetCurrentThread();

    while (true)
    {
        // 该函数是实现这个功能的最重要的一个函数
        // 函数的用法以及参数和返回值的具体解释可以查询MSDN
        //   
        if (!StackWalk64(dwImageType, hProcess, hThread, &sf, &c, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
        {
            break;
        }

        if (sf.AddrFrame.Offset == 0)
        {
            break;
        }

        CallStackInfo callstackinfo;
        SafeStrCpy(callstackinfo.MethodName, MAX_NAME_LENGTH, "N/A");
        SafeStrCpy(callstackinfo.FileName, MAX_NAME_LENGTH, "N/A");
        SafeStrCpy(callstackinfo.ModuleName, MAX_NAME_LENGTH, "N/A");
        SafeStrCpy(callstackinfo.LineNumber, MAX_NAME_LENGTH, "N/A");

        BYTE symbolBuffer[sizeof(IMAGEHLP_SYMBOL64)+MAX_NAME_LENGTH];
        IMAGEHLP_SYMBOL64 *pSymbol = (IMAGEHLP_SYMBOL64*)symbolBuffer;
        memset(pSymbol, 0, sizeof(IMAGEHLP_SYMBOL64)+MAX_NAME_LENGTH);

        pSymbol->SizeOfStruct = sizeof(symbolBuffer);
        pSymbol->MaxNameLength = MAX_NAME_LENGTH;

        DWORD symDisplacement = 0;

        BOOL bGetFileName = FALSE;
        // 得到函数名
        //   
        if (SymGetSymFromAddr64(hProcess, sf.AddrPC.Offset, NULL, pSymbol))
        {
            SafeStrCpy(callstackinfo.MethodName, MAX_NAME_LENGTH, pSymbol->Name);
        }

        IMAGEHLP_LINE64 lineInfo;
        memset(&lineInfo, 0, sizeof(IMAGEHLP_LINE64));

        lineInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64);

        DWORD dwLineDisplacement;

        // 得到文件名和所在的代码行
        //
        if (SymGetLineFromAddr64(hProcess, sf.AddrPC.Offset, &dwLineDisplacement, &lineInfo))
        {
            //该类本身不需要记载
            if (strcmp(lineInfo.FileName, __FILE__))
                bGetFileName = TRUE;

            SafeStrCpy(callstackinfo.FileName, MAX_NAME_LENGTH, lineInfo.FileName);
            sprintf_s(callstackinfo.LineNumber, "%d", lineInfo.LineNumber);//后文中有改动——亦忧
        }

        IMAGEHLP_MODULE64 moduleInfo;
        memset(&moduleInfo, 0, sizeof(IMAGEHLP_MODULE64));

        moduleInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);

        // 得到模块名
        //
        if (SymGetModuleInfo64(hProcess, sf.AddrPC.Offset, &moduleInfo))
        {
            SafeStrCpy(callstackinfo.ModuleName, MAX_NAME_LENGTH, moduleInfo.ModuleName);
        }

        if (bGetFileName)
            arrCallStackInfo.push_back(callstackinfo);
    }

    SymCleanup(hProcess);

    return arrCallStackInfo;
}

 

———-淡定的分割线———-

运行发现除了调用堆栈的行号除了第一句外,其他都不准确。http://www.codeproject.com/KB/threads/StackWalker.aspx的例子讨论中有解决方法。


This is solvable as follows:
 
Add this to the StackWalkerInternal

//pSGLFA != NULL )
    { // yes, we have SymGetLineFromAddr64()
        if (this->pSGLFA(hProcess, dwAddr, pdwDisplacement, pLine) != FALSE)
        {
            csEntry.lineNumber = pLine->LineNumber;
            // TODO: Mache dies sicher...!
            strcpy_s(csEntry.lineFileName, sizeof(csEntry.lineFileName), pLine->FileName);
            success = TRUE;
        }
        else
        {
            this->m_parent->OnDbgHelpErr("SymGetLineFromAddr64", GetLastError(), dwAddr);
        }
    } // yes, we have SymGetLineFromAddr64()
    return success;
}
//pSGLFA != NULL )
    { // yes, we have SymGetLineFromAddr64()
        if (this->pSGLFA(hProcess, dwAddr, pdwDisplacement, pLine) != FALSE)
        {
            csEntry.lineNumber = pLine->LineNumber;
            // TODO: Mache dies sicher...!
            strcpy_s(csEntry.lineFileName, sizeof(csEntry.lineFileName), pLine->FileName);
            success = TRUE;
        }
        else
        {
            this->m_parent->OnDbgHelpErr("SymGetLineFromAddr64", GetLastError(), dwAddr);
        }
    } // yes, we have SymGetLineFromAddr64()

NEW:

    if (this->m_sw->FindLine(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromLine), &Line, csEntry))
    {
        this->m_sw->FindPreviousLine(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromLine), &Line, csEntry);	// ignore return status
    }

 

再次测试发现,应该除去第一次的情况。即调用堆栈第一句不适合FindPreviousLine。结合几家所言,终于完美了。

第二个例子获得文件名和行号的部分改为以下:


        if (SymGetLineFromAddr64(hProcess, sf.AddrPC.Offset, &dwLineDisplacement, &lineInfo))
        {
            SafeStrCpy(callstackinfo.FileName, MAX_NAME_LENGTH, lineInfo.FileName);

            // Get correct line number including return status
            if (arrCallStackInfo.size() > 0)
            {
                DWORD64 qwAddr = sf.AddrPC.Offset;
                DWORD pdwDisplacement = dwLineDisplacement;
                IMAGEHLP_LINE64 Line64 = lineInfo;
                DWORD nextLine = lineInfo.LineNumber;
                BOOL bOk = FALSE;
                do
                {
                    --qwAddr;
                    bOk = SymGetLineFromAddr64(hProcess, qwAddr, &pdwDisplacement, &lineInfo);
                } while (bOk && (nextLine == lineInfo.LineNumber));
                if (!bOk)
                {
                    dwLineDisplacement = pdwDisplacement;
                    lineInfo = Line64;
                }
            }

            sprintf_s(callstackinfo.LineNumber, "%d", lineInfo.LineNumber);
        }

 

Advertisements

wxHTTP and HTTP 1.1

用wxWidgets的wxHTTP下载文件时遇到了一些问题,记录在此。

1、wxHTTP目前处于停滞状态,版本相当老(追溯到97年),且只支持HTTP 1.0。找到源文件http.cpp可以看到BuildRequest()里HTTP报头设定为HTTP 1.0。

2、官方示例http://wiki.wxwidgets.org/WxHTTP使用wxStringOutputStream只能适用纯文本HTML,不适用于文件,哪怕是XML文件。下载文件需要用wxFileOutputStream。

3、用GET命令下载脚本产生的动态网页时,HTTP协议头中Content-Length是-1。因为服务器一边产生HTML一边传送,所以无法确定准确的HTML文件大小。这也意味着,SeekI()无法作用于wxHTTPStream,即GET返回的文件流。这点在wxWidgets的源文件里也注释了。因此下载脚本产生的动态网页时,无法让wxHTTPStream使用SeekI()跳过一些字节并下载其余字节。每次都是完整下载。

4、HTTP协议头中的Range参数是实现断点续传的基础。Range头在HTTP 1.1中加入,HTTP 1.0是没有的。所以wxHTTP原生就不支持Range。另外,脚本产生的动态网页不支持Range头下载,即不支持断点续传。即便将其加入请求的HTTP报头中,服务器也会忽略它。

5、想用HTTP 1.1,可以继承wxHTTP类,自己重写GetInputStream()和BuildRequest(),并在BuildRequest()中设定HTTP为1.1(如下),将HTTP请求升级为1.1版。但对HTTP响应的工作要自己做。
buf.Printf(wxT(“%s %s HTTP/1.1\r\n”), request, path.c_str());

6、上述中的工作,其中之一就是:当下载脚本产生的动态网页时,服务器会根据HTTP协议的版本来做不同的响应。HTTP1.0版,服务器照常发送文件,在发送完毕或者出现错误的时候断开连接。HTTP 1.1版,讲究TCP连接的复用。报头中Connection参数设为close时,在发送完毕或者出现错误的时候断开连接;设为keep-alive时,服务器不主动断开连接。此时,脚本产生的动态网页文件被分块发送,报头中含有Transfer-Encoding:chunked。当从wxHTTPStream读取时,第一行是文件块的字符数(不是字节数),第二行起至文件块的字符数是真正的文件块数据(如果数据中包含回车换行,则每个回车换行算两个字符)。然后回车换行重复上面的格式,直至文件结束。再回车换行以0作为文件块结束标识。其后跟一些尾部标示(一般没有,且一般可以忽略),最后再以回车换行结束。

7、如果没有收到长度为0的文件块,则表明传输出现了错误。

8、在计算文件块数据的长度时,要注意编码。UTF-8编码的字符的长度是不定长的。

Howto: Using wxSocket in a secondary thread

Trackback:  http://www.litwindow.com/Knowhow/wxSocket/wxsocket.html

Howto: Using wxSocket in a secondary thread.

If you have tried this, you will have stumbled across the following problem(s):

100% CPU usage by wxWidgets application
All socket operations such as Read/Write time out.
Things work if you put them in the main thread.

Note: This information is valid for wxMSW (Microsoft Windows Platforms).

I have not tested this on Linux or other platforms.

To use wxSockets in a secondary thread, you must

call wxSocketBase::Initialize from the main thread before creating any sockets. The best place to do this is in wxApp::OnInit.
make sure that the main thread is running always. Do not sleep or use semaphores to block the main thread.

Here is a little background: This is an excerpt from my post on wx-users…

for wxWidgetsMSW (which also explains the
odd requirement to call wxSocketBase::Initialize in the main thread):
When Initialize is called for the first time, it creates a hidden
window. Socket operations do not block. Instead they use an
asynchronous model. All internal socket operation will return
immediately. When a write is completed, the OS will send a windows
message to the window created by Initialize.

What happens in your case is:

a) If you don’t call Initialize in the main thread, the window will be
created in the secondary thread, which under wxWidgets has no message
loop. The main message loop will only handle windows created in the
main thread. So the events sent to this window will get lost.

b) If you do call Initialize in the main thread: When you call Write
in a secondary thread, the wxWidgets socket code waits in a busy loop.
It will call write once and then call a ‘getstatus’ method which loops
until an internal flag has been set. The code looks somewhat like:

while (!flag) {
sleep(0); // give up timeslice
}

If you block the main thread with sleep or wxCondition, the event sent
by the operating system cannot be processed and will never reach the
hidden socket sink window and so cannot set the flag.

It is my impression that the socket classes seem to be not very well
integrated into wxWidgets and – at least in part – not very well
written. IMHO busy loops really should be avoided.

wxWidgets Contributing

Original URL: http://ftp.sunet.se/wmirror/wxwidgets.org/develop2.htm

The wxWidgets Community

Built with wxWidgets These pages are for people involved in, or thinking of becoming involved in, contributing code or other effort to wxWidgets. If you’re a satisfied wxWidgets user, please help spread the word by adding a ‘Built with wxWidgets’ icon to your site, linking to http://www.wxwidgets.org.

Communicating

Mailing lists and how to subscribe
Searchable wx-users archive
The message board, an alternative to the lists
wxWiki: user-editable pages
Feedback from happy users
Meetings: arrange meetings with other users

Contributing

The wxWidgets web site and downloadable files are hosted at SourceForge. However, the wxWidgets CVS archive, the main mechanism for collaboration, is hosted separately at SunSITE. Please see Using CVS below for further information. If you don’t have CVS write access and want to submit a patch, contribution or sample, please use the Patch Manager. Using CVS
Google Summer of Code projects: apply for project funding at code.google.com/soc
Contributions from users
wxCode, a place to host contributed wxWidgets classes
Coding standards
Bounties: earn or advertise
Report or view bugs
How to submit patches
Submit patches
Docpatcher: test documentation patches online

Downloading

Official releases
Browse the sources
Daily snapshots of CVS at SF; see also UK mirror
Daily makefile builds for eVC++, DMC++ and others

Strategy

Project suggestions
wxWidgets roadmap
wxWidgets, SPI, and donating
Name change information
Funding for contributors
wxPalmOS contest

Further information

Users and their applications
Applications built with wxWidgets
Reviews and articles
The wxWidgets Team
Internationalization volunteers
Daily builds
Supported platforms
Public distros with wxWidgets
Making a wxWidgets distribution
Credits

Related projects

Bakefile, the tool that generates our makefiles
wxCode, a place to host contributed wxWidgets classes
wxEmbedded, the wxWidgets embedded initiative
wxPython, a Python binding
wxPerl, a Perl binding
wxBasic, a Basic binding
wxLua, a Lua binding
wxJavaScript, a JavaScript binding
wxJava, a Java binding by Steve Perkins
wx4j, a Java binding by Dave Dribin
wxRuby, a Ruby binding
wxEiffel, an Eiffel binding
wxHaskell, a Haskell binding
wx.NET, a C# binding for .NET/Mono
wxEuphoria, a Euphoria binding
wxAda, an Ada binding for wxWidgets
wxDesigner, dialog editor/RAD tool
DialogBlocks, a dialog editor generating C++ and XRC
wxWorkshop, IDE for wxWidgets
wxHatch, IDE for wxWidgets
wxSSL, SSL versions of wxWidgets IPC and socket classes
wxGuide, design guidelines by Otto Wyss
port of wxBase to Novell
wx-devcpp, a wxWidgets form designer plugin for Dev-C++
Code::Blocks, a free C++ IDE based on wxWidgets
wxDockIt, a library to support docking windows
wxUniversal, generic wxWidgets widgets
poEdit, a message catalog editor
wxMozilla, code to embed the Mozilla web browser into wxWidgets applications
XML for wxWidgets, a wxWidgets-compatible XML parser library
Tex2RTF, documentation converter
Accessibility: work in progress to add accessibility support
Experiments in converting wxWidgets reference to XML, by Arnout Engelen

VC++中与.Net RijndaelManaged等价的加密解密算法

.Net中定义RijndaelManaged的key和iv
Public ReadOnly key As Byte() = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
Public ReadOnly IV As Byte() = {17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}

.Net这么做
Dim Buf As Byte()//函数传人参数,加密的二进制数据
Imports System.Security.Cryptography
Dim _ms As New MemoryStream(Buf)
Dim _RMCrypto As New RijndaelManaged
Dim _decryptStream As New CryptoStream(_ms, _RMCrypto.CreateDecryptor(key, IV), CryptoStreamMode.Read)

看VC++怎么做:

1、定义类型


typedef struct AKeyBlob
{
    BLOBHEADER header;
    DWORD cbKeySize;
    BYTE rgbKeyData[16];
} A_KEY_BLOB;

2、定义变量


A_KEY_BLOB m_blobAKey =
{
    {PLAINTEXTKEYBLOB, CUR_BLOB_VERSION, 0, CALG_AES_128},
    16,
    {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}//key
};

3、解密


HCRYPTPROV hProv;
DWORD dwError;

if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
{
    dwError = ::GetLastError();
    if (NTE_BAD_KEYSET == dwError)
    {
        if (!CryptAcquireContext(&hProv, "NVCryptoTestContainer", MS_ENHANCED_PROV, PROV_RSA_AES, CRYPT_NEWKEYSET | CRYPT_VERIFYCONTEXT))
        {
            dwError = ::GetLastError();
            strError = "CryptAcquireContext() failed.";
            return false;  // error
        }
    }
}
else
{
    HCRYPTKEY hPubKey;
    if (CryptImportKey(hProv, (const LPBYTE)&m_blobAKey, sizeof(m_blobAKey), 0, 0, &hPubKey))
    {
        const BYTE iv[] = {17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32};

        if (!CryptSetKeyParam(hPubKey, KP_IV, iv, 0))
        {
            strError = "CryptSetKeyParam() failed.";
            return false;  // error
        }
        else
        {
            char btBuffer[4096];
            memset(btBuffer, 0, sizeof(btBuffer));
            memcpy(btBuffer, pBuffer, lLength);
            if (!CryptDecrypt(hPubKey, 0, TRUE, 0, reinterpret_cast(btBuffer), &lLength))
            {
                strError = "CryptDecrypt() failed.";
                // got error, still continue
            }
            _strlwr_s(btBuffer);//解密得到全小写的明文

            //以下为加密算法,未测试
            //char szClearText[32];
            //strcpy(szClearText, "String To Encrypt");
            //DWORD dwDataLen = (DWORD)strlen(szClearText);
            //DWORD dwBufferSize = sizeof(szClearText);
            //if(!CryptEncrypt(hPubKey, 0, TRUE, 0, (LPBYTE)szClearText, &dwDataLen, dwBufferSize))
            //{
            //    strError = "CryptEncrypt() failed.";
            //    return "";  // error
            //}
            //else
            //{
            //    printf("encrypted looks like:  %s", szClearText);
            //    dwBufferSize = sizeof(szClearText);
            //    if(!CryptDecrypt(hPubKey, 0, TRUE, 0, (LPBYTE)szClearText, &dwBufferSize))
            //    {
            //        strError = "CryptDecrypt() failed.";
            //        return "";  // error
            //    }
            //    else
            //    {
            //        printf("decrypted looks like: %s", szClearText);
            //    }
            //}
        }

        if(!CryptDestroyKey(hPubKey))
        {
            strError = "CryptDestroyKey() failed.";
            return false;  // error
        }
    }
    else
    {
        strError = "CryptImportKey() failed.";
        return false;  // error
    }
}

VC++用ADO读写二进制数据

读:


long lDataSize = RS->GetFields()->GetItem("AField")->ActualSize;
char* pBuffer;
if (lDataSize > 0)
{
    _variant_t var = RS->GetFields()->GetItem("AField")->GetChunk(lDataSize);
    if (var.vt == (VT_ARRAY | VT_UI1))
    {
        if (pBuffer = new char[lDataSize + 1])
        {
            char *p = NULL;
            SafeArrayAccessData(var.parray, reinterpret_cast(&p));
            memcpy(pBuffer, p, lDataSize);
            SafeArrayUnaccessData(var.parray);
            // Do something
            delete []pBuffer;
        }
    }
    var.Detach();
}

写:


CString strExt("PDF File (*.pdf)|*.pdf|All Files (*.*)|*.*|");
CFileDialog dlg(TRUE, "", "", OFN_FILEMUSTEXIST | OFN_HIDEREADONLY, strExt, NULL);
dlg.m_ofn.lpstrInitialDir = "C:\";

if (dlg.DoModal() == IDOK)
{
    CFile file;
    if (file.Open(dlg.GetPathName(), CFile::modeRead))
    {
        const long lSize = static_cast(file.GetLength());
        void* pBuffer = new char[lSize + 1];
        memset(pBuffer, 0, lSize + 1);

        if (file.Read(pBuffer, lSize) == lSize)
        {
            file.Close();
            _variant_t var;
            SAFEARRAY* sa;
            SAFEARRAYBOUND sab[1];
            if (pBuffer)
            {
                sab[0].lLbound = 0;
                sab[0].cElements = lSize;
                sa = SafeArrayCreate(VT_UI1, 1, sab);
                char* p = static_cast(pBuffer);
                for (long i = 0; i < lSize; i++)
                    SafeArrayPutElement(sa, &i, p++);
                var.vt = VT_ARRAY | VT_UI1;
                var.parray = sa;

                try
                {
                    /*RsOpenWrite(pRS, Q);
                    pRS->AddNew();
                    pRS->Fields->GetItem("FileName")->Value = _variant_t(dlg.GetFileName());
                    pRS->Fields->GetItem("Data")->AppendChunk(var);
                    pRS->Update();
                    pRS->Close();
                    */
                }
                catch (_com_error e)
                {
                    CatchComExp(e);
                }
            }
        }

        delete []pBuffer;
    }
}

Fix Crystal Report ActiveX in VS2010

Linker>Command Line

/FORCE:MULTIPLE
/NXCOMPAT:NO