在 Windows 里 DLL 卸载自身模块是无法通过字节调用 FreeLibrary 自己来实现的。

原因分析

在当前线程中调用 FreeLibrary 后,当前模块就会立即被释放掉,而当前线程还没有运行结束。所以程序就运行到了一块不可访问的内存里,产生异常从而导致程序崩溃。

解决方案

Windows 里面 提供了一条可以用来释放自身模块的函数 FreeLibraryAndExitThread 可以释放自身。

函数

VOID WINAPI FreeLibraryAndExitThread(_In_ HMODULE hLibModule, _In_ DWORD dwExitCode)
#!/usr/env python
"""
:license: MIT

Copyright (C) 2012 HustMoon

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
from __future__ import with_statement

import zlib, sys

def b128encode(buf, escape=False):
    if not buf: return ''
    buf = bytearray(buf)
    res = bytearray((len(buf) * 8 + 6) / 7)
    p, s, i = 0, 1, 0
    for n in buf:
        res[i] = ((p << (8 - s) | (n >> s)) &amp; 0x7F) | 0x80; i += 1
        if s == 7:
            res[i] = n | 0x80; i += 1
            p, s = 0, 1
        else:
            p, s = n, (s + 1) % 8
    if s != 1:
        if s == 2 and p < 0x80:
            i -= 1
        else:
            p = (p << (8 - s)) &amp; 0x7F
        p = chr(p)
        if escape:
            p = p.encode('string-escape')
        res[i:] = p
    return str(res)

def dcode():
    code = r'''def code(__=code):
 (_______)=(globals)();del((_______)['code'])
 if(((_______).get('__doc__'))is((None))):
  (__)=(map)((ord),(__)[(339):]);(______)=[0]*(((((len)((__))+(1))*(7))/(8)));((___),(____),(_____))=((0),(0),(0))
  for((__))in((__)):
   if((__)<(128)):break
   if((____)==(0)):((___),(____))=((__),(1))
   else:
    (______)[(_____)]=((((___)<<(____))|(((__)&amp;(127))>>((7)-(____))))&amp;(255));(_____)+=(1);((___),(____))=((__),(((____)+(1))%(8)))
  if((__)<(128)):
   if((____)!=(0)):
    (__)=((((___)<<(____))|((__)>>((7)-(____))))&amp;(255))
   (______)[(_____):]=[((__))]
  elif((____)!=(0)):del((______)[(_____):])
  exec((''.join((map)((chr),(______))).decode('zlib')))in((_______))
  if(((_______).get('__doc__'))is((None))):(_______)['__doc__']=''
code()
'''
    return ''.join([c.encode('string-escape') if ord(c) < 128 else c
                    for c in zlib.compress(code, 9)])
dcode = dcode()

def encode(infile, outfile):
    with open(infile, 'rU') as fp:
        code = fp.read().rstrip('n') + 'n'
    code = b128encode(zlib.compress(code, 9), True)
    code = r'''# -*- coding: latin-1 -*-
code = '%s'
exec(code.decode('zlib'))
''' % (dcode + code)
    with open(outfile, 'wb') as fp:
        fp.write(code)

def decode(infile, outfile):
    with open(infile, 'rU') as fp:
        code = fp.read().rstrip('n') + 'n'
    code = code.replace("exec(code.decode('zlib'))", "exec(code.decode('zlib')"
        ".replace('exec','fp.write').replace('in((_______))',''))")
    with open(outfile, 'wb') as fp:
        eval(compile(code, 's', 'exec'), {'fp':fp})

def main():
    try:
        if sys.argv[1] == '-d':
            func = decode
            infile, outfile = sys.argv[2:4]
        else:
            func = encode
            infile, outfile = sys.argv[1:3]
    except ValueError:
        print >>sys.stderr, 'Usage: zipcode.py [-d] infile.py outfile.py'
        raise SystemExit(-1)
    func(infile, outfile)

if __name__ == '__main__':
    main()

不再需要导入atl.lib库了,直接包含以下头文件就可以了

#include <atlbase.h>
#include <atlcom.h>
#include <atlctl.h>

要使用 AtlAxAttachControl 等函数的话,则必须初始化ATL模块

CComModule _Module;
_pAtlModule = &_Module;

原本的程序是控制台的。 但最近需要移植到windows下使用。 所以以MFC来做UI,代码照搬。 一面的一处代码使用了如下语句:

boost::split(v, data, boost::is_any_of(_T("n")));

结果编译时出现了如下错误:

error C4996: 'std::_Copy_impl'

而且是无论怎么修改都不认,差点打算重写了。

在网络中搜索了半天未果,只能自己分析。好在被我乱猜给猜对了。

我猜是因为boost的string和std的string产生了冲突而导致的。 所以添加上boost的string引用后,问题得以解决。

#include <boost/algorithm/string.hpp>

在此留字,希望能帮到遇到同样问题的人。

如果socket想使用HTTP代理,需要进行下面步骤:

  1. connect到代理服务器
  2. send(Format(“CONNECT %s:%s HTTP/1.1rnUser-Agent: MyApp/0.1rnrn”, <真正目标IP>, <真正目标端口>)
  3. recv 数据,并且根据数据内容判断CONNECT协议是否成功(是否有返回"HTTP/1.1 200")
  4. 如果第3步成功了,那么这个socket就已经是通过HTTP代理来连接的了,剩下的该怎么发包收包都照旧了

错误1

error LNK2019: unresolved external symbol _deflateEnd@4

原因1: 未使用zlib的链接库

  • 解决:
#pragma comment(lib, "zlibstat.lib") // for static lib
#pragma comment(lib, "zdll.lib") // for dll lib

原因2:在使用静态库时即使包含了zlibstat.lib没有定义宏“ZLIB_WINAPI”

  • 解决: 在项目属性中 C/C++ -> Preprocessor -> Preprocessor Definitions 添加“ZLIB_WINAPI” 注意:这个必须在项目中添加,使用#define来添加是无效的。

错误2

error LNK2026: module unsafe for SAFESEH image

原因:两个项目SAFESEH设置不同

  • 解决: 设置项目属性: Linker -> Advanced -> [Image Has Safe Exception Handlers] = “No” 注意:这个必须在项目中添加,使用#pragma来添加是无效的。

错误3

error LNK2005: __call_reportfault already defined in LIBCMTD.lib(invarg.obj)或类似其他的error LNK2005:

原因:与libcmt库冲突了

  • 解决:
#pragma comment(linker, "/NODEFAULTLIB:libcmt.lib")

概要

有六种类型的可重用的库:

静态单线程库 (调试/发行版) 静态多线程的库 (调试/发行版) 动态链接库 (DLL)(Debug/Release) 注意每个库都有一个调试版本和发布版本。

Reusable Library            Switch    Library    Macro(s) Defined
--------------------------- --------- ---------- ----------------------
Single Threaded             /ML       LIBC       (none)
Static MultiThread          /MT       LIBCMT     _MT
Dynamic Link (DLL)          /MD       MSVCRT     _MT and _DLL
Debug Single Threaded       /MLd      LIBCD      _DEBUG
Debug Static MultiThread    /MTd      LIBCMTD    _DEBUG and _MT
Debug Dynamic Link (DLL)    /MDd      MSVCRTD    _DEBUG, _MT, and _DLL

下面的代码可以使用可重用库的头文件中以确保一致使用正确的编译器开关:

// MyReusableStaticSingleThreadReleaseLibrary.h
#if defined(_MT) || defined(_DEBUG)
    #error The /ML compiler switch is required.
#endif

// MyReusableStaticMultithreadReleaseLibrary.h
#if !defined(_MT) || defined(_DLL) || defined(_DEBUG)
    #error The /MT compiler switch is required.
#endif

// MyReusableDynamicLinkReleaseLibrary.h
#if !defined(_MT) || !defined(_DLL) || defined(_DEBUG)
    #error The /MD compiler switch is required.
#endif

// MyReusableStaticSingleThreadDebugLibrary.h
#if defined(_MT) || !defined(_DEBUG)
    #error The /MLd compiler switch is required.
#endif

// MyReusableStaticMultithreadDebugLibrary.h
#if !defined(_MT) || defined(_DLL) || !defined(_DEBUG)
    #error The /MTd compiler switch is required.
#endif

// MyReusableDynamicLinkDebugLibrary.h
#if !defined(_MT) || !defined(_DLL) || !defined(_DEBUG)
    #error The /MDd compiler switch is required.
#endif

原文:http://support.microsoft.com/kb/140584/zh-cn

压缩

enData = zlib.compress(data)[2:-4]

对应:

compress2(dstbuf, &dstLen, strSrc, srcLen, 6);

解压

deData = zlib.decompress(enData, -zlib.MAX_WBITS)

对应:

bool gzipInflate( const std::string& compressedBytes, std::string& uncompressedBytes ) {
    if ( compressedBytes.size() == 0 ) {
        uncompressedBytes = compressedBytes ;
        return true ;
    }

    uncompressedBytes.clear() ;

    unsigned full_length = compressedBytes.size() ;
    unsigned half_length = compressedBytes.size() / 2;

    unsigned uncompLength = full_length ;
    char* uncomp = (char*) calloc( sizeof(char), uncompLength );

    z_stream strm;
    strm.next_in = (Bytef *) compressedBytes.c_str();
    strm.avail_in = compressedBytes.size() ;
    strm.total_out = 0;
    strm.zalloc = Z_NULL;
    strm.zfree = Z_NULL;

    bool done = false ;

    //if (inflateInit2(&strm, (16+MAX_WBITS)) != Z_OK)
    if (inflateInit2(&strm, -MAX_WBITS) != Z_OK)
    {
        free( uncomp );
        return false;
    }

    while (!done) {
        // If our output buffer is too small
        if (strm.total_out >= uncompLength ) {
            // Increase size of output buffer
            char* uncomp2 = (char*) calloc( sizeof(char), uncompLength + half_length );
            memcpy( uncomp2, uncomp, uncompLength );
            uncompLength += half_length ;
            free( uncomp );
            uncomp = uncomp2 ;
        }

        strm.next_out = (Bytef *) (uncomp + strm.total_out);
        strm.avail_out = uncompLength - strm.total_out;

        // Inflate another chunk.
        int err = inflate (&strm, Z_SYNC_FLUSH);
        if (err == Z_STREAM_END) done = true;
        else if (err != Z_OK)  {
            break;
        }
    }

    if (inflateEnd (&strm) != Z_OK) {
        free( uncomp );
        return false;
    }

    for ( size_t i=0; i<strm.total_out; ++i ) {
        uncompressedBytes += uncomp[ i ];
    }
    free( uncomp );
    return true ;
}