在 Windows Vista 以上的操作系统中可以使用pkgmgr对Windows功能的快捷安装
比如想要安装 telnet客户端 时,只需在控制台里面键入以下命令并回车:

1
pkgmgr /iu:"TelnetClient"

等几秒钟后 telnet 命令就可以使用了
就这么简单 :)

问题出现

今天在Windows里使用 Cocos-Quick 创建的项目在使用ADT往Android里面部署的时候遇到了下面的问题

出现上图的情况是这样的操作步骤:

  1. 添加 D:\Tools\Quick-Cocos2dx-Community\cocos\platform\android\java 到 Library 引用里
  2. 点击 OK
  3. 重新打开这个配置界面

问题解决

测试了许久后,无意间发现有次选错了路径后Library正常了

当时我选择的 Quick 是 F:\Quick-Cocos2dx-Community
选择的项目目录是 F:\Code\Cocos\QuickHello

终于发现了解决这个BUG的办法: 将项目和想要引用的Library放在同一个分区内
遂将项目和 Quick 放到同一个分区内后问题解决,效果如下:

引起这个错误的原因是: Eclipse 本身并不是给Windows 这种多分区系统定制的,本身是用来给 MAC 或者 Linux 这种以目录为结构的系统使用的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 拉取最新的代码
git fetch --all
# 恢复到最后一次提交,放弃本地所有修改
git reset --hard

# 列出所有设置
git config -l

# 抛弃对文件的修改
git co -- <filename>
# 抛弃对目录的修改
git co .

# 从版本库中删除文件
git rm <filename>

# 比较差异
git diff

# 查看提交历史
git log

本篇文章后续不定期更新

不能再构造函数内使用 shared_from_this() 函数

1
2
3
4
5
6
7
8
class class_a : public std::enable_shared_from_this<class_a>
{
public:
class_a(void)
{
auto self(shared_from_this());// 这里会报 bad_weak_ptr 错误
}
};

子类无法重复继承

1
2
3
4
5
6
7
class class_a : public std::enable_shared_from_this<class_a>
{
};

class class_b : public class_a, public std::enable_shared_from_this<class_a>
{
};

这段代码将无法通过编译。
如果想返回子类的 shared_from_this 指针,则可以进行如下操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class class_a : public std::enable_shared_from_this<class_a>
{
public:
virtual ~class_a()// 为了确保 dynamic_pointer_cast 可以工作,需要父类拥有虚函数。
{}
};

class class_b : public class_a
{
public:
std::shared_ptr<class_b> shared_from_this(void)
{
return std::dynamic_pointer_cast<class_b>(class_a::shared_from_this());
}
};

通常来说如果定义一个类时,如果这个类可能被继承使用时,将这个类的析构函数定义为虚函数来确保析构的调用顺序

在最近写一些串口操作的程序时使用了 boost::asio::serial_port 来操作串口
但当尝试打开串口的时候出现了错误。下面是我的测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
boost::asio::io_service _io_service;
const std::string devname = "COM3";
try
{
boost::asio::serial_port serial(_io_service);
serial.open(devname);// throw error every times.
if (serial.is_open()) {
std::cout << devname << " serial open successed." << std::endl;
}
else {
std::cout << devname << " serial open failed!" << std::endl;
}
}
catch (const std::exception& ex)
{
std::cout << ex.what() << std::endl;// GetLastError() == 87
}

每次都会出现错误87。即 GetLastError() 的结果为 87
于是跟进代码里面调试追到了 win_iocp_serial_port_service::open 函数里

win_iocp_serial_port_service::open 函数的实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
boost::system::error_code win_iocp_serial_port_service::open(
win_iocp_serial_port_service::implementation_type& impl,
const std::string& device, boost::system::error_code& ec)
{
if (is_open(impl))
{
ec = boost::asio::error::already_open;
return ec;
}

std::string name = (device[0] == '\\') ? device : "\\\\.\\" + device;

::HANDLE handle = ::CreateFileA(name.c_str(),
GENERIC_READ | GENERIC_WRITE, 0, 0,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
if (handle == INVALID_HANDLE_VALUE)
{
DWORD last_error = ::GetLastError();
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
return ec;
}

using namespace std;
::DCB dcb;
memset(&dcb, 0, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
if (!::GetCommState(handle, &dcb))
{
DWORD last_error = ::GetLastError();
::CloseHandle(handle);
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
return ec;
}

dcb.fBinary = TRUE;
dcb.fDsrSensitivity = FALSE;
dcb.fNull = FALSE;
dcb.fAbortOnError = FALSE;

if (!::SetCommState(handle, &dcb))
{
DWORD last_error = ::GetLastError();// lee: error is here!!!
::CloseHandle(handle);
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
return ec;
}

::COMMTIMEOUTS timeouts;
timeouts.ReadIntervalTimeout = 1;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
if (!::SetCommTimeouts(handle, &timeouts))
{
DWORD last_error = ::GetLastError();
::CloseHandle(handle);
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
return ec;
}

if (handle_service_.assign(impl, handle, ec))
::CloseHandle(handle);
return ec;
}

发现每次在第一次 SetCommState 的时候总是会报错并离开。
于是查看了前面通过 GetCommState 获取到的 dcb 的值。
发现 dcb.BaudRate == 0 时无法 SetCommState 成功
也就是说在有些设备中获取不到 dcb.BaudRate 这个值。

下面是我自己的解决办法

在 win_iocp_serial_port_service.ipp 文件的88行左右添加

1
if (dcb.BaudRate == 0) dcb.BaudRate = 115200;

修改后的 win_iocp_serial_port_service::open 函数完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
boost::system::error_code win_iocp_serial_port_service::open(
win_iocp_serial_port_service::implementation_type& impl,
const std::string& device, boost::system::error_code& ec)
{
if (is_open(impl))
{
ec = boost::asio::error::already_open;
return ec;
}

std::string name = (device[0] == '\\') ? device : "\\\\.\\" + device;

::HANDLE handle = ::CreateFileA(name.c_str(),
GENERIC_READ | GENERIC_WRITE, 0, 0,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
if (handle == INVALID_HANDLE_VALUE)
{
DWORD last_error = ::GetLastError();
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
return ec;
}

using namespace std;
::DCB dcb;
memset(&dcb, 0, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
if (!::GetCommState(handle, &dcb))
{
DWORD last_error = ::GetLastError();
::CloseHandle(handle);
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
return ec;
}

dcb.fBinary = TRUE;
dcb.fDsrSensitivity = FALSE;
dcb.fNull = FALSE;
dcb.fAbortOnError = FALSE;
if (dcb.BaudRate == 0) dcb.BaudRate = 115200; // add lee 2015.10.10. 解决dcb.BaudRate为0时无法成功SetCommState的BUG
if (!::SetCommState(handle, &dcb))
{
DWORD last_error = ::GetLastError();
::CloseHandle(handle);
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
return ec;
}

::COMMTIMEOUTS timeouts;
timeouts.ReadIntervalTimeout = 1;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
if (!::SetCommTimeouts(handle, &timeouts))
{
DWORD last_error = ::GetLastError();
::CloseHandle(handle);
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
return ec;
}

if (handle_service_.assign(impl, handle, ec))
::CloseHandle(handle);
return ec;
}

测试环境

说明 参数
操作系统 Windows10 专业版 x64
开发环境 Microsoft Visual Studio Community 2013 Version 12.0.40629.00 Update 5
Boost版本 boost_1.59.0

结束语

以上只是自己的猜测,并不一定是完全正确的。如有任何错误,请联系并告诉我。我将尽快修改,不胜感激。

需求

我有时需要在命令行里对某个VS项目目录进行编译或部署等操作,总是需要以下步骤:

  1. 打开VS的Command Prompt
  2. 进入该项目目录
  3. 进行编译操作

个人觉得这样太浪费时间,于是萌生了添加类似 Command Here 右键菜单的想法。
办法很简单,在注册表添加相关项就可以了

解决方案

Windows7 添加方法

将以下内容修改到自己对应VS目录后以文本形式保存到 VS2013-Command-Prompt-Here-win7.reg 文件,然后双击导入即可

1
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Folder\shell\VS2013 Command Prompt Here]

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Folder\shell\VS2013 Command Prompt Here\command]
@="cmd.exe /s /k pushd \"%1\" & \"C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat\" x86"

Windows10 添加方法

将以下内容修改到自己对应VS目录后以文本形式保存到 VS2013-Command-Prompt-Here-win10.reg 文件,然后双击导入即可

1
Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\Directory\Background\shell\VS2013 Command Prompt Here]

[HKEY_CLASSES_ROOT\Directory\Background\shell\VS2013 Command Prompt Here\command]
@="cmd.exe /s /k pushd \"%V\" & \"C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat\" x86"

为什么区分Windows版本

因为对于Windows来说传参的方式有所改变
pushd %1 是用于Windows7的
pushd %V 是用于Windows10的

下载

for Windows7: VS2013-Command-Prompt-Here-win7.reg
for Windows10: VS2013-Command-Prompt-Here-win10.reg

打开 Visual Studio 2013 Command Prompt

1
2
3
4
5
6
7
8
9
10
11
wget http://www.nasm.us/pub/nasm/releasebuilds/2.11.08/win32/nasm-2.11.08-win32.zip
unzip nasm-2.11.08-win32.zip -d C:/nasm
set PATH=%PATH%;C:/nasm/
wget https://www.openssl.org/source/openssl-1.0.2d.tar.gz
tar xzf openssl-1.0.2d.tar.gz
cd openssl-1.0.2d
perl configure VC-WIN32 --prefix=C:/openssl
ms\do_nasm
nmake -f ms\nt.mak
nmake -f ms\nt.mak install
echo "build successed."

这样编译不会产生 error A2070:invalid instruction operands 这个错误

有时,把旧项目转换成新版本项目时,旧版本项目里使用的 maxmin 宏无法在新版本中正常编译.

原因是: 新版本内有了新的函数 std::maxstd::min 函数来实现这一功能

这时可以尝试使用如下方案解决:

  1. 包含algorithm文件

    1
    #include <algorithm>
  2. 明确使用 std::max(a,b) 而非 max(a,b)

  3. 定义宏 NOMINMAX
    1
    #define NOMINMAX

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

原因分析

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

解决方案

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

函数

VOID WINAPI FreeLibraryAndExitThread(_In_ HMODULE hLibModule, _In_ DWORD dwExitCode)