How to properly installing Microsoft Visual Studio 2010 and patches under Windows XP properly

Instruction

An update to the Windows SDK for Windows 7 and .NET Framework 4 (Windows SDK 7.1) is now available. This update addresses the issue where Visual C++ Compilers and libraries that are installed with the Windows SDK are removed when Visual Studio 2010 Service Pack 1 is installed.

Our recommended install order is:

  1. Visual Studio 2010 en_visual_studio_2010_ultimate_x86_dvd_509116.iso

  2. Uinstall Microsoft Visual C++ 2010 x86 Redistributable Microsoft Visual C++ 2010 x64 Redistributable Why:

https://stackoverflow.com/questions/19366006/error-when-installing-windows-sdk-7-1 This issue occurs when you install the Windows 7 SDK on a computer that has a newer version of the Visual C++ 2010 Redistributable installed.

  1. Windows SDK 7.1 2010-05-19 https://www.microsoft.com/en-us/download/details.aspx?id=8442 Folder: IDE/Microsoft SDKs/Windows SDK 7.1/ x86 ISO File Name: GRMSDK_EN_DVD.iso CRC#: 0xBD8F1237 SHA1: 0xCDE254E83677C34C8FD509D6B733C32002FE3572 ================================================ x64 ISO File Name: GRMSDKX_EN_DVD.iso CRC#: 0x04F59E55 SHA1: 0x9203529F5F70D556A60C37F118A95214E6D10B5A ================================================ Itanium ISO File Name: GRMSDKIAI_EN_DVD.iso CRC#: 0x50EFE61D SHA1: 0x2093EE439193EF79A1629FD9A826CE8D4DE9A93D

  2. Visual Studio 2010 SP1 mu_visual_studio_2010_sp1_x86_dvd_651704.iso

  3. Microsoft Visual C++ 2010 Service Pack 1 Compiler Update for the Windows SDK 7.1 2011-03-20 https://www.microsoft.com/en-us/download/details.aspx?id=4422 IDE/Microsoft SDKs/Windows SDK 7.1/VC-Compiler-KB2519277.exe

  4. Microsoft Visual Studio 2010 Service Pack 1 MFC Security Update 2011-08-09 https://www.microsoft.com/en-us/download/details.aspx?id=27049 VS10SP1-KB2565057-x86

Visual C++ 2010 SP1 Compiler Update for the Windows SDK 7.1 You must have installed Windows SDK 7.1 in order to install the update. However, you do NOT have to have installed VS 2010 + SP1 – this update is also applicable to the standalone SDK.

Failure recovery

If installing failed, you may uninstall Visual Studio 2010 first. https://blogs.msdn.microsoft.com/heaths/2010/08/23/visual-studio-2010-uninstall-utility/

Fix the very old msys or cygwin under win10.

Introduction

For some very old cygwin/msys toolchain, such as Tornado 2.2 (GCC) or Msys 1.0.11(1000.11.0.0) They may not works properly under Win10. Reporting error such as For msys

      0 [main] us 0 init_cheap: VirtualAlloc pointer is null, Win32 error 487
AllocationBase 0x0, BaseAddress 0x71110000, RegionSize 0x4E0000, State 0x10000
~\msys\bin\make.exe: *** Couldn't reserve space for cygwin's heap, Win32 error 0

or GCC directly failed.

Refering to http://stackoverflow.com/questions/14840572/win32-error-8-during-ccppc-compile-on-windows-7-x86 Opening Visual Studio Command Tools Command Prompt

We can fixes Tornado 2.2(GCC by following command):

cd /d C:\Tornado2.2\host\x86-win32\lib\gcc-lib\i586-wrs-vxworks\2.9-PentiumIII-010221


dumpbin /HEADERS cc1.exe
        17D78400H size of stack reserve
        400 000 000(10进制) size of stack reserve

editbin /STACK:67108864 cc1.exe
changed to be
        400 0000H size of stack reserve (64MB)
        67108864(10进制) size of stack reserve

dumpbin /HEADERS cc1plus.exe
        17D78400H size of stack reserve
        400 000 000(10进制) size of stack reserve

editbin /STACK:67108864 cc1plus.exe
changed to be
        400 0000H size of stack reserve (64MB)
        67108864(10进制) size of stack reserve

And for Msys 1.0.11

We can using following command to fixies issues: Before you rebase dlls, you should make sure it is not in use:

tasklist /m msys-1.0.dll

And make a backup:

copy msys-1.0.dll msys-1.0.dll.bak

With later Visual Studio (VS2015) you can do it this way (don’t seem to have rebase.exe around) Opening Visual Studio Command Tools Command Prompt

editbin /rebase:base=0x50000000 msys-1.0.dll

For earlier version of Visual Studio:

rebase.exe -b 0x50000000 msys-1.0.dll

For showing the modification result:

dumpbin /headers msys-1.0.dll

Flexible DLL or Static Library Linkage Configurations.

Introduction

This is comes from Binglong’s space I have some code that must build into either a DLL or a statib library depending on the project setting. That says, I need to write the code carefully, such that when project configuration changes I can minimize code modification, and make it survive in a flexibly configured project.

It is well known that conditional compilation using a macro can help to make a header file for building a DLL itself (exporting objects) and being used by the client (importing symbols) without any change. The problem for me is more complex: not only the code should be used to create a DLL and use a DLL, but also to create a static library and use a static library.

Obviously to minimize the code modification, conditional compilation is a must. The problem is what macros can be leveraged?

Experiment

In Microsoft Visual Studio 2005, I used the Add New Project Wizard to create various projects and observe the macros that are defined by these wizard generated projects. Below is the result:

In the project creation wizard, there are macros defined by the wizard.

  • Win32 Project -> Windows application WIN32 _WINDOWS
  • Win32 Project -> Console application WIN32 _CONSOLE
  • Win32 Project -> Console application, Using: MFC (implicit: in shared DLL) WIN32 _CONSOLE _AFXDLL
  • Win32 Project -> DLL WIN32 _WINDOWS _USRDLL _WINDLL _EXPORTS
  • Win32 Project -> DLL, Additional options: Export Symbols WIN32 _WINDOWS _USRDLL _WINDLL _EXPORTS
  • Win32 Project -> DLL, Using: MFC (implicit: in shared DLL) WIN32 _WINDOWS _USRDLL _WINDLL _AFXDLL _EXPORTS
  • Win32 Project -> Static library WIN32 _LIB
  • Win32 Project -> Static library, Using: MFC (implicit: in shared DLL) WIN32 _LIB _AFXDLL
  • MFC -> MFC application, Use MFC in a shared DLL WIN32 _WINDOWS _AFXDLL
  • MFC -> MFC application, Use MFC in a static library WIN32 _WINDOWS
  • MFC -> MFC DLL, Regular DLL using shared MFC DLL WIN32 _WINDOWS _USRDLL _WINDLL _AFXDLL Merely using CWinApp derived class’s InitInstance/ExitInstance to wrap up DllMain() This is still a C/C++ DLL, and you need to export the symbols on your own.
  • MFC -> MFC DLL, Regular DLL with MFC statically linked WIN32 _WINDOWS _USRDLL _WINDLL
  • Merely using CWinApp derived class’s InitInstance/ExitInstance to wrap up DllMain() This is still a C/C++ DLL, and you need to export the symbols on your own.
  • MFC -> MFC DLL, MFC Extension DLL WIN32 _WINDOWS _AFXEXT _WINDLL _AFXDLL

There are orthogonal macros not affected by the project creation wizard .

  • Release build: NDEBUG / Debug Build: _DEBUG
  • MBCS build: _MBCS / Unicode build: UNICODE _UNICODE
  • Also, _EXPORTS controls _API to be either __declspec(dllexport) or __declspec(dllimport), reference to [Exporting C++ Classes from an MFC Extension DLL] (http://www.codeproject.com/Articles/161/Exporting-C-Classes-from-an-MFC-Extension-DLL).

Summary

For all the compile time macros:

  • All projects have: WIN32. WIN32 probably means the very low-level feature of Windows, for example Kernel, that every project running on the OS depends on. WIN32 is defined even for 64-bit compilation according to MSDN.
  • Console applications have: _CONSOLE. Note: at link time, /SUBSYSTEM:CONSOLE option is used such that a console window is created before it enters CRT startup entry point, mainCRTStartup. CRT startup routine initializes C Run Time library, then calls our application entry function, normally main(). The program is a Unicode build, both the CRT startup entry point and our application entry function should be the Unicode version, wmainCRTStartup and wmain().
  • Windows applications and DLLs have: _WINDOWS. Note: at link time, /SUBSYSTEM:WINDOWS option is used. This makes sure no console window appears, and CRT is initialized, and correspondent WinMain() or DllMain() is then called when the EXE or DLL is loaded.
  • Static libraries have: _LIB. Note: static libraries does not need to specify _CONSOLE or _WINDOWS, because it alone will never be an executable and loaded.
  • DLLs have: _WINDLL. All DLLs have this. Notice also all DLLs should export some symbols.
  • Regular DLLs have: _USRDLL. Regular DLL means that it is not a MFC extension DLL. Regular DLLs can be C or C++ DLLs. C DLL is the normal case. C++ DLL is not compiler neutral due to name mangling. Regular DLLs can choose to use or not use MFC. Regular DLLs can also choose to use MFC in a static library or a shared DLL.
  • All projects using MFC as a shared DLL have: _AFXDLL. No matter it is a static library, DLL or application, using MFC in a shared DLL needs this macro.
  • MFC extension DLLs have: _AFXEXT _AFXDLL. _AFXDLL is actually from the fact that an MFC extension DLL must use MFC as a shared DLL. _AFXEXT makes special arrangement for these extension DLLs. There are extra requirements to write such DLLs to work correctly. Obviously, any client using an MFC extension DLL must use MFC as a shared DLL, therefore define _AFXDLL too.

For the bold bullets above, remember that the compile time macros apply when the target static library or DLL is built. When the client of the target is compiled, even it includes the header files from the target, the macros applied on the target no longer apply; it is the client project’s own macros that apply.

The fact that a library’s header file can be included when building the library or when the client uses the library, means that the header file itself cannot distinguish whether _LIB or _WINDLL is from the client or the library itself. Therefore it cannot rely on these standard macros to determine if it is used to {create, use}x{static library, DLL}. For example, if the header file senses _LIB, it could be that the target library is being built as a static library, or that the target library (static or even DLL) is being used to build a client static library. The conclusion is that the standard macros above are useless for us here. Good learning, haha.

Calling conventions and linking

INFO: Using _declspec(dllimport) & _declspec(dllexport) in Code is available at Microsoft Help and Support. Specifically, __declspec(dllexport) is used to indicate that the object symbol should be put in the import library when building a DLL project; __declspec(dllimport) is used in a client project to import the symbol from the DLL. Thus in a DLL project’s header file, it looks like below:

#ifdef OURLIB_EXPORTS // when building DLL
  #define OURLIB_API __declspec(dllexport)
#else // when client uses DLL
  #define OURLIB_API __declspec(dllimport)
#endif
class OURLIB_API OurClass{};
OURLIB_API void OurGlobalFunc();

The DLL project defines OURLIB_EXPORTS when it is built, while the client does not.

If we build and use a static library, the case is not that complex. Remember a static library is just like a collection of .obj files, directly added to the client project. Everything is visible to the client, except those file static objects. That says, OURLIB_API can just be empty, nothing, for a static library, no matter it is built or used.

But we need to look closer at __declspec(dllexport) and __declspec(dllimport) first.

First of all, when building a DLL, __declspec(dllexport) is almost a must for exporting symbols. You can use a .DEF (module definition) file to export symbols, but it is inconvenient. Also, C++ name decoration, because it may change in different versions of compilers, makes the .DEF hard to maintain; but __declspec(dllexport) is invariant.

On the other side, __declspec(dllimport) is not a must for the DLL’s client. If the client does not use __declspec(dllimport), the linker has to generate a thunk to simulate a non-DLL call. The thunk itself jumps to an entry of the client EXE’s import address table, which the loader updates when the client is loaded with the DLL. If the client uses __declspec(dllimport), the linker directly puts a call ptr __imp_func1 at the call site, where __imp_func1 is the import address entry, thus saving space and time of a thunk.

Therefore, the following code works, at the cost of slower and larger client due to the thunks when OURLIB is a DLL:

#ifdef OURLIB_EXPORTS // when building DLL
  #define OURLIB_API __declspec(dllexport)
#else // when client uses DLL,  or when building static library, or when client uses static library
  #define OURLIB_API 
#endif

class OURLIB_API OurClass{};
OURLIB_API void OurGlobalFunc();

To get better performance, we can also write:

// in ourlib.h:

#ifdef OURLIB_EXPORTS // when building DLL, target project defines this macro
  #define OURLIB_API __declspec(dllexport)
#elif defined(OURLIB_IMPORTS) // when using DLL, client project defines this macro
  #define OURLIB_API __declspec(dllimport)
#else // when building or using target static library, or whatever: define it as nothing
  #define OURLIB_API 
#endif

class OURLIB_API OurClass{};
OURLIB_API void OurGlobalFunc();

Of course, you only add OURLIB_API to the objects that are intended to be exported when building a DLL. The internal objects in a DLL should not be decorated with this macro. When building/using the static library, OURLIB_API does nothing. Compared to a DLL only target header file, the DLL/static library dual-build header file further requires the client project to define OURLIB_IMPORTS when it uses the target project as a DLL. This slight extra work is worthwhile. If you forget to do that in your client project, your only consequence is slower and larger client, maybe still acceptable.

Example

Suppose in the target library we provide a class ClassT1, which has a public member function void foo(). The client calls ClassT1::foo() in its code. We test with a few scenarios below.

  • We build the target library as a DLL using __declspec(dllexport), then the client imports symbols from the DLL using __declspec(dllimport). The client assembly code is call DWORD PTR __imp_?foo@ClassT1@@QAEXXZ for t1.foo(); where __imp_?foo@ClassT1@@QAEXXZ is an entry in the PE’s import address table. That entry is filled by loader when the DLL is loaded.
  • We build the target library as a DLL using __declspec(dllexport), then the client imports symbols from the DLL without using __declspec(dllimport). The client assembly code is call ?foo@ClassT1@@QAEXXZ for t1.foo(). It appears as a normal function call, as if ?foo@ClassT1@@QAEXXZ is a routine with a known address. But since the actual function lives in a DLL, this simple call will not work directly. In fact, the linker makes a thunk, an entry somewhere in the executable that ?foo@ClassT1@@QAEXXZ points to. The thunk is simply one instruction jmp DWORD PTR __imp_?foo@ClassT1@@QAEXXZ. Again, __imp_?foo@ClassT1@@QAEXXZ is an entry in the PE’s import address table, which is updated by the loader.
  • We build the target library as a static library, and the client links to it. The client assembly code is call ?foo@ClassT1@@QAEXXZ for t1.foo(). This is just a normal function call, as if the function is from the same translation unit, or same project. The linker treats the function from a static library the same as one from another object file.

Obviously, 3 gives best performance, 1 seconds that, and 2 is the slowest.

Experiment with Microsoft Visual C++ Project Create Wizard.

Introduction

When I want to construct a building system, I need to dig into the Microsoft Visual C++’s project wizard created macros. So I didn’t try different kinds of combination of Microsoft Visual C++ Project create wizard, and listing their cl.exe command line option and link command line option. some article have same functional Felxible DLL/static library linkage configurations

Experiment

In Microsoft Visual Studio 2013, I tried the following wizard creating.

  • Empty Project
    • Application (.exe)
      • Use Standard Windows Libraries
        • MBCS-Debug
          • cl.exe /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd”Debug\vc120.pdb” /fp:precise /D “_MBCS” /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa”Debug" /EHsc /nologo /Fo”Debug" /Fp”Debug\Project2.pch”
          • link.exe /OUT:”D:\CI\freelancer\msvc\Project2\Debug\Project2.exe” /MANIFEST /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\Project2\Debug\Project2.pdb” /DYNAMICBASE “kernel32.lib” “user32.lib” “gdi32.lib” “winspool.lib” “comdlg32.lib” “advapi32.lib” “shell32.lib” “ole32.lib” “oleaut32.lib” “uuid.lib” “odbc32.lib” “odbccp32.lib” /DEBUG /MACHINE:X86 /INCREMENTAL /PGD:”D:\CI\freelancer\msvc\Project2\Debug\Project2.pgd” /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Debug\Project2.exe.intermediate.manifest” /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
        • MBCS-Release
          • cl.exe /GS /GL /analyze- /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Fd”Release\vc120.pdb” /fp:precise /D “_MBCS” /errorReport:prompt /WX- /Zc:forScope /Gd /Oy- /Oi /MD /Fa”Release" /EHsc /nologo /Fo”Release" /Fp”Release\Project2.pch”
          • link.exe /OUT:”D:\CI\freelancer\msvc\Project2\Release\Project2.exe” /MANIFEST /LTCG /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\Project2\Release\Project2.pdb” /DYNAMICBASE “kernel32.lib” “user32.lib” “gdi32.lib” “winspool.lib” “comdlg32.lib” “advapi32.lib” “shell32.lib” “ole32.lib” “oleaut32.lib” “uuid.lib” “odbc32.lib” “odbccp32.lib” /DEBUG /MACHINE:X86 /OPT:REF /SAFESEH /PGD:”D:\CI\freelancer\msvc\Project2\Release\Project2.pgd” /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Release\Project2.exe.intermediate.manifest” /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
        • Unicode-Debug
          • cl.exe /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd”Debug\vc120.pdb” /fp:precise /D “_UNICODE” /D “UNICODE” /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa”Debug" /EHsc /nologo /Fo”Debug" /Fp”Debug\Project2.pch”
          • link.exe /OUT:”D:\CI\freelancer\msvc\Project2\Debug\Project2.exe” /MANIFEST /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\Project2\Debug\Project2.pdb” /DYNAMICBASE “kernel32.lib” “user32.lib” “gdi32.lib” “winspool.lib” “comdlg32.lib” “advapi32.lib” “shell32.lib” “ole32.lib” “oleaut32.lib” “uuid.lib” “odbc32.lib” “odbccp32.lib” /DEBUG /MACHINE:X86 /INCREMENTAL /PGD:”D:\CI\freelancer\msvc\Project2\Debug\Project2.pgd” /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Debug\Project2.exe.intermediate.manifest” /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
        • Unicode-Release
          • cl.exe /GS /GL /analyze- /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Fd”Release\vc120.pdb” /fp:precise /D “_UNICODE” /D “UNICODE” /errorReport:prompt /WX- /Zc:forScope /Gd /Oy- /Oi /MD /Fa”Release" /EHsc /nologo /Fo”Release" /Fp”Release\Project2.pch”
          • link.exe /OUT:”D:\CI\freelancer\msvc\Project2\Release\Project2.exe” /MANIFEST /LTCG /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\Project2\Release\Project2.pdb” /DYNAMICBASE “kernel32.lib” “user32.lib” “gdi32.lib” “winspool.lib” “comdlg32.lib” “advapi32.lib” “shell32.lib” “ole32.lib” “oleaut32.lib” “uuid.lib” “odbc32.lib” “odbccp32.lib” /DEBUG /MACHINE:X86 /OPT:REF /SAFESEH /PGD:”D:\CI\freelancer\msvc\Project2\Release\Project2.pgd” /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Release\Project2.exe.intermediate.manifest” /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
      • Use MFC in a Static Library
        • Unicode-Release
          • cl.exe /GS /GL /analyze- /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Fd”Release\vc120.pdb” /fp:precise /D “_UNICODE” /D “UNICODE” /errorReport:prompt /WX- /Zc:forScope /Gd /Oy- /Oi /MT /Fa”Release" /EHsc /nologo /Fo”Release" /Fp”Release\Project2.pch”
          • link.exe /OUT:”D:\CI\freelancer\msvc\Project2\Release\Project2.exe” /MANIFEST /LTCG /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\Project2\Release\Project2.pdb” /DYNAMICBASE /DEBUG /MACHINE:X86 /OPT:REF /SAFESEH /PGD:”D:\CI\freelancer\msvc\Project2\Release\Project2.pgd” /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Release\Project2.exe.intermediate.manifest” /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
      • Use MFC in a Shared DLL
        • Unicode-Release
          • cl.exe /GS /GL /analyze- /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Fd”Release\vc120.pdb” /fp:precise /D “_UNICODE” /D “UNICODE” /D “_AFXDLL” /errorReport:prompt /WX- /Zc:forScope /Gd /Oy- /Oi /MD /Fa”Release" /EHsc /nologo /Fo”Release" /Fp”Release\Project2.pch”
          • link.exe /OUT:”D:\CI\freelancer\msvc\Project2\Release\Project2.exe” /MANIFEST /LTCG /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\Project2\Release\Project2.pdb” /DYNAMICBASE /DEBUG /MACHINE:X86 /OPT:REF /SAFESEH /PGD:”D:\CI\freelancer\msvc\Project2\Release\Project2.pgd” /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Release\Project2.exe.intermediate.manifest” /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
    • Dynamic Library (.dll)
      • Use Standard Windows Libraries
        • Unicode-Release
          • cl.exe /GS /GL /analyze- /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Fd”Release\vc120.pdb” /fp:precise /D “_WINDLL” /D “_UNICODE” /D “UNICODE” /errorReport:prompt /WX- /Zc:forScope /Gd /Oy- /Oi /MD /Fa”Release" /EHsc /nologo /Fo”Release" /Fp”Release\Project2.pch”
          • link.exe /OUT:”D:\CI\freelancer\msvc\Project2\Release\Project2.dll” /MANIFEST /LTCG /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\Project2\Release\Project2.pdb” /DYNAMICBASE “kernel32.lib” “user32.lib” “gdi32.lib” “winspool.lib” “comdlg32.lib” “advapi32.lib” “shell32.lib” “ole32.lib” “oleaut32.lib” “uuid.lib” “odbc32.lib” “odbccp32.lib” /IMPLIB:”D:\CI\freelancer\msvc\Project2\Release\Project2.lib” /DEBUG /DLL /MACHINE:X86 /OPT:REF /SAFESEH /PGD:”D:\CI\freelancer\msvc\Project2\Release\Project2.pgd” /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Release\Project2.dll.intermediate.manifest” /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
      • Use MFC in a Static Library
        • Unicode-Release
          • cl.exe /GS /GL /analyze- /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Fd”Release\vc120.pdb” /fp:precise /D “_WINDLL” /D “_UNICODE” /D “UNICODE” /errorReport:prompt /WX- /Zc:forScope /Gd /Oy- /Oi /MT /Fa”Release" /EHsc /nologo /Fo”Release" /Fp”Release\Project2.pch”
          • link.exe /OUT:”D:\CI\freelancer\msvc\Project2\Release\Project2.dll” /MANIFEST /LTCG /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\Project2\Release\Project2.pdb” /DYNAMICBASE /IMPLIB:”D:\CI\freelancer\msvc\Project2\Release\Project2.lib” /DEBUG /DLL /MACHINE:X86 /OPT:REF /SAFESEH /PGD:”D:\CI\freelancer\msvc\Project2\Release\Project2.pgd” /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Release\Project2.dll.intermediate.manifest” /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
      • Use MFC in a Shared DLL
        • Unicode-Release
          • cl.exe /GS /GL /analyze- /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Fd”Release\vc120.pdb” /fp:precise /D “_WINDLL” /D “_UNICODE” /D “UNICODE” /D “_AFXDLL” /errorReport:prompt /WX- /Zc:forScope /Gd /Oy- /Oi /MD /Fa”Release" /EHsc /nologo /Fo”Release" /Fp”Release\Project2.pch”
          • link.exe /OUT:”D:\CI\freelancer\msvc\Project2\Release\Project2.dll” /MANIFEST /LTCG /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\Project2\Release\Project2.pdb” /DYNAMICBASE /IMPLIB:”D:\CI\freelancer\msvc\Project2\Release\Project2.lib” /DEBUG /DLL /MACHINE:X86 /OPT:REF /SAFESEH /PGD:”D:\CI\freelancer\msvc\Project2\Release\Project2.pgd” /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Release\Project2.dll.intermediate.manifest” /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
    • Static library (.lib)
      • Use Standard Windows Libraries
        • Unicode-Release
          • cl.exe /GS /GL /analyze- /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Fd”Release\vc120.pdb” /fp:precise /D “_UNICODE” /D “UNICODE” /errorReport:prompt /WX- /Zc:forScope /Gd /Oy- /Oi /MD /Fa”Release" /EHsc /nologo /Fo”Release" /Fp”Release\Project2.pch”
          • link.exe /OUT:”D:\CI\freelancer\msvc\Project2\Release\Project2.lib” /MANIFEST /LTCG /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\Project2\Release\Project2.pdb” /DYNAMICBASE “kernel32.lib” “user32.lib” “gdi32.lib” “winspool.lib” “comdlg32.lib” “advapi32.lib” “shell32.lib” “ole32.lib” “oleaut32.lib” “uuid.lib” “odbc32.lib” “odbccp32.lib” /DEBUG /MACHINE:X86 /OPT:REF /SAFESEH /PGD:”D:\CI\freelancer\msvc\Project2\Release\Project2.pgd” /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Release\Project2.lib.intermediate.manifest” /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
      • Use MFC in a Static Library
        • Unicode-Release
          • cl.exe /GS /GL /analyze- /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Fd”Release\vc120.pdb” /fp:precise /D “_UNICODE” /D “UNICODE” /errorReport:prompt /WX- /Zc:forScope /Gd /Oy- /Oi /MT /Fa”Release" /EHsc /nologo /Fo”Release" /Fp”Release\Project2.pch”
          • link.exe /OUT:”D:\CI\freelancer\msvc\Project2\Release\Project2.lib” /MANIFEST /LTCG /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\Project2\Release\Project2.pdb” /DYNAMICBASE /DEBUG /MACHINE:X86 /OPT:REF /SAFESEH /PGD:”D:\CI\freelancer\msvc\Project2\Release\Project2.pgd” /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Release\Project2.lib.intermediate.manifest” /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
      • Use MFC in a Shared DLL
        • Unicode-Release
          • cl.exe /GS /GL /analyze- /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Fd”Release\vc120.pdb” /fp:precise /D “_UNICODE” /D “UNICODE” /D “_AFXDLL” /errorReport:prompt /WX- /Zc:forScope /Gd /Oy- /Oi /MD /Fa”Release" /EHsc /nologo /Fo”Release" /Fp”Release\Project2.pch”
          • link.exe /OUT:”D:\CI\freelancer\msvc\Project2\Release\Project2.lib” /MANIFEST /LTCG /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\Project2\Release\Project2.pdb” /DYNAMICBASE /DEBUG /MACHINE:X86 /OPT:REF /SAFESEH /PGD:”D:\CI\freelancer\msvc\Project2\Release\Project2.pgd” /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Release\Project2.lib.intermediate.manifest” /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
  • Win32Project->Windows Application.exe
    • Unicode-Debug
      • cl.exe /Yu”stdafx.h” /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd”Debug\vc120.pdb” /fp:precise /D “WIN32” /D “_DEBUG” /D “_WINDOWS” /D “_UNICODE” /D “UNICODE” /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa”Debug" /EHsc /nologo /Fo”Debug" /Fp”Debug\Win32Project10.pch”
      • link.exe /OUT:”D:\CI\freelancer\msvc\Win32Project10\Debug\Win32Project10.exe” /MANIFEST /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\Win32Project10\Debug\Win32Project10.pdb” /DYNAMICBASE “kernel32.lib” “user32.lib” “gdi32.lib” “winspool.lib” “comdlg32.lib” “advapi32.lib” “shell32.lib” “ole32.lib” “oleaut32.lib” “uuid.lib” “odbc32.lib” “odbccp32.lib” /DEBUG /MACHINE:X86 /INCREMENTAL /PGD:”D:\CI\freelancer\msvc\Win32Project10\Debug\Win32Project10.pgd” /SUBSYSTEM:WINDOWS /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Debug\Win32Project10.exe.intermediate.manifest” /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
    • Unicode-Release
      • cl.exe /Yu”stdafx.h” /GS /GL /analyze- /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Fd”Release\vc120.pdb” /fp:precise /D “WIN32” /D “NDEBUG” /D “_WINDOWS” /D “_UNICODE” /D “UNICODE” /errorReport:prompt /WX- /Zc:forScope /Gd /Oy- /Oi /MD /Fa”Release" /EHsc /nologo /Fo”Release" /Fp”Release\Win32Project10.pch”
      • link.exe /OUT:”D:\CI\freelancer\msvc\Win32Project10\Release\Win32Project10.exe” /MANIFEST /LTCG /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\Win32Project10\Release\Win32Project10.pdb” /DYNAMICBASE “kernel32.lib” “user32.lib” “gdi32.lib” “winspool.lib” “comdlg32.lib” “advapi32.lib” “shell32.lib” “ole32.lib” “oleaut32.lib” “uuid.lib” “odbc32.lib” “odbccp32.lib” /DEBUG /MACHINE:X86 /OPT:REF /SAFESEH /INCREMENTAL:NO /PGD:”D:\CI\freelancer\msvc\Win32Project10\Release\Win32Project10.pgd” /SUBSYSTEM:WINDOWS /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Release\Win32Project10.exe.intermediate.manifest” /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
  • Win32Project->Windows Application.exe->ATL (So ATL affect nothing, MFC can not used with this, So ATL doesn’t affect cl and link options)
    • Unicode-Debug
      • cl.exe /Yu”stdafx.h” /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd”Debug\vc120.pdb” /fp:precise /D “WIN32” /D “_DEBUG” /D “_WINDOWS” /D “_UNICODE” /D “UNICODE” /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa”Debug" /EHsc /nologo /Fo”Debug" /Fp”Debug\Win32Project11.pch”
      • link.exe /OUT:”D:\CI\freelancer\msvc\Win32Project11\Debug\Win32Project11.exe” /MANIFEST /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\Win32Project11\Debug\Win32Project11.pdb” /DYNAMICBASE “kernel32.lib” “user32.lib” “gdi32.lib” “winspool.lib” “comdlg32.lib” “advapi32.lib” “shell32.lib” “ole32.lib” “oleaut32.lib” “uuid.lib” “odbc32.lib” “odbccp32.lib” /DEBUG /MACHINE:X86 /INCREMENTAL /PGD:”D:\CI\freelancer\msvc\Win32Project11\Debug\Win32Project11.pgd” /SUBSYSTEM:WINDOWS /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Debug\Win32Project11.exe.intermediate.manifest” /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
    • Unicode-Release
      • cl.exe /Yu”stdafx.h” /GS /GL /analyze- /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Fd”Release\vc120.pdb” /fp:precise /D “WIN32” /D “NDEBUG” /D “_WINDOWS” /D “_UNICODE” /D “UNICODE” /errorReport:prompt /WX- /Zc:forScope /Gd /Oy- /Oi /MD /Fa”Release" /EHsc /nologo /Fo”Release" /Fp”Release\Win32Project11.pch”
      • link.exe /OUT:”D:\CI\freelancer\msvc\Win32Project11\Release\Win32Project11.exe” /MANIFEST /LTCG /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\Win32Project11\Release\Win32Project11.pdb” /DYNAMICBASE “kernel32.lib” “user32.lib” “gdi32.lib” “winspool.lib” “comdlg32.lib” “advapi32.lib” “shell32.lib” “ole32.lib” “oleaut32.lib” “uuid.lib” “odbc32.lib” “odbccp32.lib” /DEBUG /MACHINE:X86 /OPT:REF /SAFESEH /INCREMENTAL:NO /PGD:”D:\CI\freelancer\msvc\Win32Project11\Release\Win32Project11.pgd” /SUBSYSTEM:WINDOWS /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Release\Win32Project11.exe.intermediate.manifest” /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
  • Win32Project->Console Application.exe (vs2013 bug, _LIB should disappear)
    • Unicode-Debug
      • cl.exe /Yu”stdafx.h” /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd”Debug\vc120.pdb” /fp:precise /D “WIN32” /D “_DEBUG” /D “_CONSOLE” /D “_LIB” /D “_UNICODE” /D “UNICODE” /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa”Debug" /EHsc /nologo /Fo”Debug" /Fp”Debug\Win32Project22.pch”
      • link.exe /OUT:”D:\CI\freelancer\msvc\Win32Project22\Debug\Win32Project22.exe” /MANIFEST /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\Win32Project22\Debug\Win32Project22.pdb” /DYNAMICBASE “kernel32.lib” “user32.lib” “gdi32.lib” “winspool.lib” “comdlg32.lib” “advapi32.lib” “shell32.lib” “ole32.lib” “oleaut32.lib” “uuid.lib” “odbc32.lib” “odbccp32.lib” /DEBUG /MACHINE:X86 /INCREMENTAL /PGD:”D:\CI\freelancer\msvc\Win32Project22\Debug\Win32Project22.pgd” /SUBSYSTEM:CONSOLE /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Debug\Win32Project22.exe.intermediate.manifest” /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
  • Win32Project->Console Application.exe->ATL (vs2013 bug, _LIB should disappear)
    • Unicode-Debug
      • cl.exe /Yu”stdafx.h” /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd”Debug\vc120.pdb” /fp:precise /D “WIN32” /D “_DEBUG” /D “_CONSOLE” /D “_LIB” /D “_UNICODE” /D “UNICODE” /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa”Debug" /EHsc /nologo /Fo”Debug" /Fp”Debug\Win32Project23.pch”
      • link.exe /OUT:”D:\CI\freelancer\msvc\Win32Project23\Debug\Win32Project23.exe” /MANIFEST /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\Win32Project23\Debug\Win32Project23.pdb” /DYNAMICBASE “kernel32.lib” “user32.lib” “gdi32.lib” “winspool.lib” “comdlg32.lib” “advapi32.lib” “shell32.lib” “ole32.lib” “oleaut32.lib” “uuid.lib” “odbc32.lib” “odbccp32.lib” /DEBUG /MACHINE:X86 /INCREMENTAL /PGD:”D:\CI\freelancer\msvc\Win32Project23\Debug\Win32Project23.pgd” /SUBSYSTEM:CONSOLE /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Debug\Win32Project23.exe.intermediate.manifest” /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
  • Win32Project->Console Application.exe->(ATL + MFC) (vs2013 bug, _LIB should disappear)
    • Unicode-Debug
      • cl.exe /Yu”stdafx.h” /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd”Debug\vc120.pdb” /fp:precise /D “WIN32” /D “_DEBUG” /D “_CONSOLE” /D “_LIB” /D “_UNICODE” /D “UNICODE” /D “_AFXDLL” /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa”Debug" /EHsc /nologo /Fo”Debug" /Fp”Debug\Win32Project24.pch”
      • link.exe /OUT:”D:\CI\freelancer\msvc\Win32Project24\Debug\Win32Project24.exe” /MANIFEST /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\Win32Project24\Debug\Win32Project24.pdb” /DYNAMICBASE /DEBUG /MACHINE:X86 /INCREMENTAL /PGD:”D:\CI\freelancer\msvc\Win32Project24\Debug\Win32Project24.pgd” /SUBSYSTEM:CONSOLE /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Debug\Win32Project24.exe.intermediate.manifest” /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
  • Win32Project->DLL
    • Unicode-Debug
      • cl.exe /Yu”stdafx.h” /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd”Debug\vc120.pdb” /fp:precise /D “WIN32” /D “_DEBUG” /D “_WINDOWS” /D “_USRDLL” /D “WIN32PROJECT25_EXPORTS” /D “_WINDLL” /D “_UNICODE” /D “UNICODE” /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa”Debug" /EHsc /nologo /Fo”Debug" /Fp”Debug\Win32Project25.pch”
      • link.exe /OUT:”D:\CI\freelancer\msvc\Win32Project25\Debug\Win32Project25.dll” /MANIFEST /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\Win32Project25\Debug\Win32Project25.pdb” /DYNAMICBASE “kernel32.lib” “user32.lib” “gdi32.lib” “winspool.lib” “comdlg32.lib” “advapi32.lib” “shell32.lib” “ole32.lib” “oleaut32.lib” “uuid.lib” “odbc32.lib” “odbccp32.lib” /IMPLIB:”D:\CI\freelancer\msvc\Win32Project25\Debug\Win32Project25.lib” /DEBUG /DLL /MACHINE:X86 /INCREMENTAL /PGD:”D:\CI\freelancer\msvc\Win32Project25\Debug\Win32Project25.pgd” /SUBSYSTEM:WINDOWS /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Debug\Win32Project25.dll.intermediate.manifest” /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
  • Win32Project->DLL->ATL
    • Unicode-Debug
      • cl.exe /Yu”stdafx.h” /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd”Debug\vc120.pdb” /fp:precise /D “WIN32” /D “_DEBUG” /D “_WINDOWS” /D “_USRDLL” /D “WIN32PROJECT26_EXPORTS” /D “_WINDLL” /D “_UNICODE” /D “UNICODE” /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa”Debug" /EHsc /nologo /Fo”Debug" /Fp”Debug\Win32Project26.pch”
      • link.exe /OUT:”D:\CI\freelancer\msvc\Win32Project26\Debug\Win32Project26.dll” /MANIFEST /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\Win32Project26\Debug\Win32Project26.pdb” /DYNAMICBASE “kernel32.lib” “user32.lib” “gdi32.lib” “winspool.lib” “comdlg32.lib” “advapi32.lib” “shell32.lib” “ole32.lib” “oleaut32.lib” “uuid.lib” “odbc32.lib” “odbccp32.lib” /IMPLIB:”D:\CI\freelancer\msvc\Win32Project26\Debug\Win32Project26.lib” /DEBUG /DLL /MACHINE:X86 /INCREMENTAL /PGD:”D:\CI\freelancer\msvc\Win32Project26\Debug\Win32Project26.pgd” /SUBSYSTEM:WINDOWS /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Debug\Win32Project26.dll.intermediate.manifest” /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
  • Win32Project->DLL->ATL+MFC
    • Unicode-Debug
      • cl.exe /Yu”stdafx.h” /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd”Debug\vc120.pdb” /fp:precise /D “WIN32” /D “_DEBUG” /D “_WINDOWS” /D “_USRDLL” /D “WIN32PROJECT27_EXPORTS” /D “_WINDLL” /D “_UNICODE” /D “UNICODE” /D “_AFXDLL” /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa”Debug" /EHsc /nologo /Fo”Debug" /Fp”Debug\Win32Project27.pch”
      • link.exe /OUT:”D:\CI\freelancer\msvc\Win32Project27\Debug\Win32Project27.dll” /MANIFEST /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\Win32Project27\Debug\Win32Project27.pdb” /DYNAMICBASE /IMPLIB:”D:\CI\freelancer\msvc\Win32Project27\Debug\Win32Project27.lib” /DEBUG /DLL /MACHINE:X86 /INCREMENTAL /PGD:”D:\CI\freelancer\msvc\Win32Project27\Debug\Win32Project27.pgd” /SUBSYSTEM:WINDOWS /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Debug\Win32Project27.dll.intermediate.manifest” /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
  • Win32Project->Static Library
    • Unicode-Debug
      • cl.exe /Yu”stdafx.h” /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd”Debug\vc120.pdb” /fp:precise /D “WIN32” /D “_DEBUG” /D “_LIB” /D “_UNICODE” /D “UNICODE” /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa”Debug" /EHsc /nologo /Fo”Debug" /Fp”Debug\Win32Project28.pch”
      • link.exe /OUT:”D:\CI\freelancer\msvc\Win32Project28\Debug\Win32Project28.lib” /NOLOGO
  • Win32Project->Static Library->MFC ( Can not check ATL)
    • Unicode-Debug
      • cl.exe /Yu”stdafx.h” /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd”Debug\vc120.pdb” /fp:precise /D “WIN32” /D “_DEBUG” /D “_LIB” /D “_UNICODE” /D “UNICODE” /D “_AFXDLL” /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa”Debug" /EHsc /nologo /Fo”Debug" /Fp”Debug\Win32Project29.pch”
      • link.exe /OUT:”D:\CI\freelancer\msvc\Win32Project29\Debug\Win32Project29.lib” /NOLOGO
  • ATL Project->Proxy Project (Use by every ATL Project without Stub) Compiling IDL files
    • Unicode-Debug
      • cl.exe /GS /analyze- /W1 /Zc:wchar_t /ZI /Gm /Od /Fd”DebugPS\vc120.pdb” /fp:precise /D “WIN32” /D “REGISTER_PROXY_DLL” /D “_DEBUG” /D “_WINDLL” /D “_UNICODE” /D “UNICODE” /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa”DebugPS" /EHsc /nologo /Fo”DebugPS" /Fp”DebugPS\ATLProject6PS.pch”
      • link.exe /OUT:”D:\CI\freelancer\msvc\ATLProject6\Debug\ATLProject6PS.dll” /MANIFEST /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\ATLProject6\Debug\ATLProject6PS.pdb” /DYNAMICBASE “kernel32.lib” “rpcns4.lib” “rpcrt4.lib” “oleaut32.lib” “uuid.lib” “user32.lib” “gdi32.lib” “winspool.lib” “comdlg32.lib” “advapi32.lib” “shell32.lib” “ole32.lib” “odbc32.lib” “odbccp32.lib” /DEF:”ATLProject6PS.def” /IMPLIB:”D:\CI\freelancer\msvc\ATLProject6\Debug\ATLProject6PS.lib” /DLL /MACHINE:X86 /INCREMENTAL /PGD:”D:\CI\freelancer\msvc\ATLProject6\Debug\ATLProject6PS.pgd” /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”DebugPS\ATLProject6PS.dll.intermediate.manifest” /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
  • ATL Project->DLL
    • Unicode-Debug
      • cl.exe /Yu”stdafx.h” /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd”Debug\vc120.pdb” /fp:precise /D “WIN32” /D “_WINDOWS” /D “_DEBUG” /D “_USRDLL” /D “_WINDLL” /D “_UNICODE” /D “UNICODE” /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa”Debug" /EHsc /nologo /Fo”Debug" /Fp”Debug\ATLProject6.pch”
      • link.exe /OUT:”D:\CI\freelancer\msvc\ATLProject6\Debug\ATLProject6.dll” /MANIFEST /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\ATLProject6\Debug\ATLProject6.pdb” /DYNAMICBASE “kernel32.lib” “user32.lib” “gdi32.lib” “winspool.lib” “comdlg32.lib” “advapi32.lib” “shell32.lib” “ole32.lib” “oleaut32.lib” “uuid.lib” “odbc32.lib” “odbccp32.lib” /DEF:”.\ATLProject6.def” /DEBUG /DLL /MACHINE:X86 /INCREMENTAL /PGD:”D:\CI\freelancer\msvc\ATLProject6\Debug\ATLProject6.pgd” /SUBSYSTEM:WINDOWS /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Debug\ATLProject6.dll.intermediate.manifest” /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
  • ATL Project->DLL->Stub (Check Stub means no separate Proxy Project)
    • Unicode-Debug
      • cl.exe /Yu”stdafx.h” /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd”Debug\vc120.pdb” /fp:precise /D “WIN32” /D “_WINDOWS” /D “_DEBUG” /D “_USRDLL” /D “_WINDLL” /D “_UNICODE” /D “UNICODE” /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa”Debug" /EHsc /nologo /Fo”Debug" /Fp”Debug\ATLProject7.pch”
      • link.exe /OUT:”D:\CI\freelancer\msvc\ATLProject7\Debug\ATLProject7.dll” /MANIFEST /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\ATLProject7\Debug\ATLProject7.pdb” /DYNAMICBASE “kernel32.lib” “user32.lib” “gdi32.lib” “winspool.lib” “comdlg32.lib” “advapi32.lib” “shell32.lib” “ole32.lib” “oleaut32.lib” “uuid.lib” “odbc32.lib” “odbccp32.lib” /DEF:”.\ATLProject7.def” /DEBUG /DLL /MACHINE:X86 /INCREMENTAL /PGD:”D:\CI\freelancer\msvc\ATLProject7\Debug\ATLProject7.pgd” /SUBSYSTEM:WINDOWS /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Debug\ATLProject7.dll.intermediate.manifest” /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
  • ATL Project->DLL->COM 1.0
    • Unicode-Debug
      • cl.exe /Yu”stdafx.h” /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd”Debug\vc120.pdb” /fp:precise /D “WIN32” /D “_WINDOWS” /D “_DEBUG” /D “_USRDLL” /D “_WINDLL” /D “_UNICODE” /D “UNICODE” /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa”Debug" /EHsc /nologo /Fo”Debug" /Fp”Debug\ATLProject8.pch”
      • link.exe /OUT:”D:\CI\freelancer\msvc\ATLProject8\Debug\ATLProject8.dll” /MANIFEST /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\ATLProject8\Debug\ATLProject8.pdb” /DYNAMICBASE “comsvcs.lib” “kernel32.lib” “user32.lib” “gdi32.lib” “winspool.lib” “comdlg32.lib” “advapi32.lib” “shell32.lib” “ole32.lib” “oleaut32.lib” “uuid.lib” “odbc32.lib” “odbccp32.lib” /DEF:”.\ATLProject8.def” /DEBUG /DLL /MACHINE:X86 /INCREMENTAL /PGD:”D:\CI\freelancer\msvc\ATLProject8\Debug\ATLProject8.pgd” /SUBSYSTEM:WINDOWS /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Debug\ATLProject8.dll.intermediate.manifest” /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
  • ATL Project->DLL->MFC
    • Unicode-Debug
      • cl.exe /Yu”stdafx.h” /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd”Debug\vc120.pdb” /fp:precise /D “WIN32” /D “_WINDOWS” /D “_DEBUG” /D “_USRDLL” /D “_WINDLL” /D “_UNICODE” /D “UNICODE” /D “_AFXDLL” /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa”Debug" /EHsc /nologo /Fo”Debug" /Fp”Debug\ATLProject9.pch”
      • link.exe /OUT:”D:\CI\freelancer\msvc\ATLProject9\Debug\ATLProject9.dll” /MANIFEST /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\ATLProject9\Debug\ATLProject9.pdb” /DYNAMICBASE /DEF:”.\ATLProject9.def” /DEBUG /DLL /MACHINE:X86 /INCREMENTAL /PGD:”D:\CI\freelancer\msvc\ATLProject9\Debug\ATLProject9.pgd” /SUBSYSTEM:WINDOWS /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Debug\ATLProject9.dll.intermediate.manifest” /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
  • ATL Project->Executable
    • Unicode-Debug
      • cl.exe /Yu”stdafx.h” /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd”Debug\vc120.pdb” /fp:precise /D “WIN32” /D “_WINDOWS” /D “_DEBUG” /D “_UNICODE” /D “UNICODE” /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa”Debug" /EHsc /nologo /Fo”Debug" /Fp”Debug\ATLProject11.pch”
      • link.exe /OUT:”D:\CI\freelancer\msvc\ATLProject11\Debug\ATLProject11.exe” /MANIFEST /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\ATLProject11\Debug\ATLProject11.pdb” /DYNAMICBASE “kernel32.lib” “user32.lib” “gdi32.lib” “winspool.lib” “comdlg32.lib” “advapi32.lib” “shell32.lib” “ole32.lib” “oleaut32.lib” “uuid.lib” “odbc32.lib” “odbccp32.lib” /DEBUG /MACHINE:X86 /INCREMENTAL /PGD:”D:\CI\freelancer\msvc\ATLProject11\Debug\ATLProject11.pgd” /SUBSYSTEM:WINDOWS /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Debug\ATLProject11.exe.intermediate.manifest” /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
  • ATL Project->Executable->Stub (Check Stub means no separate Proxy Project)
    • Unicode-Debug
      • cl.exe /Yu”stdafx.h” /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd”Debug\vc120.pdb” /fp:precise /D “WIN32” /D “_WINDOWS” /D “_DEBUG” /D “_UNICODE” /D “UNICODE” /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa”Debug" /EHsc /nologo /Fo”Debug" /Fp”Debug\ATLProject12.pch”
      • link.exe /OUT:”D:\CI\freelancer\msvc\ATLProject12\Debug\ATLProject12.exe” /MANIFEST /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\ATLProject12\Debug\ATLProject12.pdb” /DYNAMICBASE “kernel32.lib” “user32.lib” “gdi32.lib” “winspool.lib” “comdlg32.lib” “advapi32.lib” “shell32.lib” “ole32.lib” “oleaut32.lib” “uuid.lib” “odbc32.lib” “odbccp32.lib” /DEBUG /MACHINE:X86 /INCREMENTAL /PGD:”D:\CI\freelancer\msvc\ATLProject12\Debug\ATLProject12.pgd” /SUBSYSTEM:WINDOWS /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Debug\ATLProject12.exe.intermediate.manifest” /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
  • ATL Project->Service Executable
    • Unicode-Debug
      • cl.exe /Yu”stdafx.h” /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd”Debug\vc120.pdb” /fp:precise /D “WIN32” /D “_WINDOWS” /D “_DEBUG” /D “_UNICODE” /D “UNICODE” /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa”Debug" /EHsc /nologo /Fo”Debug" /Fp”Debug\ATLProject13.pch”
      • link.exe /OUT:”D:\CI\freelancer\msvc\ATLProject13\Debug\ATLProject13.exe” /MANIFEST /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\ATLProject13\Debug\ATLProject13.pdb” /DYNAMICBASE “kernel32.lib” “user32.lib” “gdi32.lib” “winspool.lib” “comdlg32.lib” “advapi32.lib” “shell32.lib” “ole32.lib” “oleaut32.lib” “uuid.lib” “odbc32.lib” “odbccp32.lib” /DEBUG /MACHINE:X86 /INCREMENTAL /PGD:”D:\CI\freelancer\msvc\ATLProject13\Debug\ATLProject13.pgd” /SUBSYSTEM:WINDOWS /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Debug\ATLProject13.exe.intermediate.manifest” /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
  • MFC Application
    • Unicode-Debug
      • cl.exe /Yu”stdafx.h” /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd”Debug\vc120.pdb” /fp:precise /D “WIN32” /D “_WINDOWS” /D “_DEBUG” /D “_UNICODE” /D “UNICODE” /D “_AFXDLL” /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa”Debug" /EHsc /nologo /Fo”Debug" /Fp”Debug\MFCApplication1.pch”
      • link.exe /OUT:”D:\CI\freelancer\msvc\MFCApplication1\Debug\MFCApplication1.exe” /MANIFEST /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\MFCApplication1\Debug\MFCApplication1.pdb” /DYNAMICBASE /DEBUG /MACHINE:X86 /INCREMENTAL /PGD:”D:\CI\freelancer\msvc\MFCApplication1\Debug\MFCApplication1.pgd” /SUBSYSTEM:WINDOWS /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Debug\MFCApplication1.exe.intermediate.manifest” /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
  • MFC Active Control
    • Unicode-Debug
      • cl.exe /Yu”stdafx.h” /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd”Debug\vc120.pdb” /fp:precise /D “WIN32” /D “_WINDOWS” /D “_DEBUG” /D “_USRDLL” /D “_WINDLL” /D “_UNICODE” /D “UNICODE” /D “_AFXDLL” /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa”Debug" /EHsc /nologo /Fo”Debug" /Fp”Debug\MFCActiveXControl3.pch”
      • link.exe /OUT:”D:\CI\freelancer\msvc\MFCActiveXControl3\Debug\MFCActiveXControl3.ocx” /MANIFEST /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\MFCActiveXControl3\Debug\MFCActiveXControl3.pdb” /DYNAMICBASE /DEF:”.\MFCActiveXControl3.def” /IMPLIB:”D:\CI\freelancer\msvc\MFCActiveXControl3\Debug\MFCActiveXControl3.lib” /DEBUG /DLL /MACHINE:X86 /INCREMENTAL /PGD:”D:\CI\freelancer\msvc\MFCActiveXControl3\Debug\MFCActiveXControl3.pgd” /SUBSYSTEM:WINDOWS /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Debug\MFCActiveXControl3.ocx.intermediate.manifest” /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
  • MFC->DLL->Link with Shared MFC dll
    • Unicode-Debug
      • cl.exe /Yu”stdafx.h” /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd”Debug\vc120.pdb” /fp:precise /D “WIN32” /D “_WINDOWS” /D “_DEBUG” /D “_USRDLL” /D “_WINDLL” /D “_UNICODE” /D “UNICODE” /D “_AFXDLL” /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa”Debug" /EHsc /nologo /Fo”Debug" /Fp”Debug\MFCLibrary5.pch”
      • link.exe /OUT:”D:\CI\freelancer\msvc\MFCLibrary5\Debug\MFCLibrary5.dll” /MANIFEST /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\MFCLibrary5\Debug\MFCLibrary5.pdb” /DYNAMICBASE /DEF:”.\MFCLibrary5.def” /IMPLIB:”D:\CI\freelancer\msvc\MFCLibrary5\Debug\MFCLibrary5.lib” /DEBUG /DLL /MACHINE:X86 /INCREMENTAL /PGD:”D:\CI\freelancer\msvc\MFCLibrary5\Debug\MFCLibrary5.pgd” /SUBSYSTEM:WINDOWS /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Debug\MFCLibrary5.dll.intermediate.manifest” /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
  • MFC->DLL->Link with Static MFC dll
    • Unicode-Debug
      • cl.exe /Yu”stdafx.h” /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd”Debug\vc120.pdb” /fp:precise /D “WIN32” /D “_WINDOWS” /D “_DEBUG” /D “_USRDLL” /D “_WINDLL” /D “_UNICODE” /D “UNICODE” /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MTd /Fa”Debug" /EHsc /nologo /Fo”Debug" /Fp”Debug\MFCLibrary6.pch”
      • link.exe /OUT:”D:\CI\freelancer\msvc\MFCLibrary6\Debug\MFCLibrary6.dll” /MANIFEST /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\MFCLibrary6\Debug\MFCLibrary6.pdb” /DYNAMICBASE /DEF:”.\MFCLibrary6.def” /IMPLIB:”D:\CI\freelancer\msvc\MFCLibrary6\Debug\MFCLibrary6.lib” /DEBUG /DLL /MACHINE:X86 /INCREMENTAL /PGD:”D:\CI\freelancer\msvc\MFCLibrary6\Debug\MFCLibrary6.pgd” /SUBSYSTEM:WINDOWS /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Debug\MFCLibrary6.dll.intermediate.manifest” /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
  • MFC->DLL->Extension of MFC DLL
    • Unicode-Debug
      • cl.exe //Yu”stdafx.h” /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd”Debug\vc120.pdb” /fp:precise /D “WIN32” /D “_WINDOWS” /D “_DEBUG” /D “_AFXEXT” /D “_WINDLL” /D “_UNICODE” /D “UNICODE” /D “_AFXDLL” /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa”Debug" /EHsc /nologo /Fo”Debug" /Fp”Debug\MFCLibrary7.pch”
      • link.exe /OUT:”D:\CI\freelancer\msvc\MFCLibrary7\Debug\MFCLibrary7.dll” /MANIFEST /NXCOMPAT /PDB:”D:\CI\freelancer\msvc\MFCLibrary7\Debug\MFCLibrary7.pdb” /DYNAMICBASE /DEF:”.\MFCLibrary7.def” /IMPLIB:”D:\CI\freelancer\msvc\MFCLibrary7\Debug\MFCLibrary7.lib” /DEBUG /DLL /MACHINE:X86 /INCREMENTAL /PGD:”D:\CI\freelancer\msvc\MFCLibrary7\Debug\MFCLibrary7.pgd” /SUBSYSTEM:WINDOWS /MANIFESTUAC:”level=’asInvoker’ uiAccess=’false’” /ManifestFile:”Debug\MFCLibrary7.dll.intermediate.manifest” /ERRORREPORT:PROMPT /NOLOGO /TLBID:1

Multi-Threaded Image Processing using Qt Camera with Android USB.

Introduction

Image processing is a resource intensive task. This article describes means how to apply image processing effects to the camera viewfinder using multi-threading to keep the user interface responsive. The following topics are covered in detail:

  • Using the Qt Mobility camera class in QML.
  • Spawning a worker thread for background image processing.
  • Adding a simple black and white effect.
  • Discussion about hardware acceleration.
  • Conclusion.

The code provided here shows only the most important functional parts. The full code can be downloaded from here.

Using the Qt Mobility Camera in QML

The QML camera component provides basic means to view and capture camera images directly from the QML scripting language. For our purpose the QML camera is not suitable because we need (i) live viewfinder image data stream and (ii) the final image as a data stream. In this article a stripped-down version of the custom QML camera component from the Qt Camera Demo is used which uses the Qt Mobility Camera classes.

Project Preparation

First, the Qt Mobility dependency and Symbian capabilities have to be added to the project (*.pro) file:

symbian: {
    TARGET.CAPABILITY += LocalServices \  # camera
         ReadUserData \                   #
         WriteUserData \                  # writing image file
         UserEnvironment                  # camera
}

On Symbian, depending on the expected memory usage the heap and stack sizes should be increased as well:

symbian: {
    TARGET.EPOCSTACKSIZE = 0x14000
    TARGET.EPOCHEAPSIZE = 0x20000 0x8000000
}

Receiving viewfinder frames from the camera

To receive video frames from the camera the QAbstractVideoSurface has to be implemented. The video surface has basically two functions: First, it tells the camera which image formats (for instance ARGB, UYVY, etc.) are supported by our application. Our sample application supports ARGB format only (caution: the Nokia N9 supports only UYVY format, thus either the effect processing has to be changed, or the UYVY data has to be converted to ARGB format before processing as for instance described here):

QList<QVideoFrame::PixelFormat> VideoSurface::supportedPixelFormats(
        QAbstractVideoBuffer::HandleType handleType) const
{
    Q_UNUSED(handleType);

    return QList<QVideoFrame::PixelFormat>() << QVideoFrame::Format_ARGB32; //N9: Format_UYVY
}

Second it notifies our application over the FrameObserver interface when new image data is available:

class FrameObserver {
public:
    virtual bool updateFrame(const QVideoFrame &frame) = 0;
};

Defining a custom QML camera view

Next we define the class in C++ which communicates with the camera hardware using Qt Mobility camera and shows the live viewfinder image stream in QML. This class extends QDeclarativeItem which is required for including the camera class as a QML view and implements the interface to get notifications about new frames arriving from the camera viewfinder. We also define some properties which can be later accessed from QML:

  • information about the camera state, for instance if the camera is loaded properly.

  • a list of available cameras. These are usually the front- and back facing cameras.

  • a parameter for our live image processing effect.

class CustomCamera : public QDeclarativeItem, public FrameObserver
{
    Q_OBJECT
    Q_ENUMS(State)

    // State properties
    Q_PROPERTY(State cameraState READ cameraState NOTIFY cameraStateChanged)

    // Devices properties
    Q_PROPERTY(QStringList availableDevices READ availableDevices)

    // Effect properties
    Q_PROPERTY(int effectThreshold READ effectThreshold WRITE effectThreshold)

The method which receives viewfinder images is implemented from the interface. If the worker thread is not busy then the frame is copied for later processing, else it is dropped.

bool CustomCamera::updateFrame(const QVideoFrame &frame)
{
    if (!frame.isValid()) {
        return false;
    }

    if (m_fipThread->isProcessing()) {
        // Discard frame if worker thread is busy.
        return true;
    }

    QVideoFrame f = frame;
    if (f.map(QAbstractVideoBuffer::ReadOnly)) {
        m_fipThread->setNewFrame(&f); // send frame to worker thread
        f.unmap(); // ready for next frame from camera
    }

     return true;
}

Next we define the start method to initialize and start the camera:

void CustomCamera::start(const QString &device)
{
    destroyResources();

    m_camera = new QCamera(device.toLatin1(), this);

    // Make sure the camera is in loaded state.
    m_camera->load();

    m_videoSurface = new VideoSurface(this, m_camera);
    m_camera->setViewfinder(m_videoSurface);

    // Set the image capturing objects.
    m_cameraImageCapture = new QCameraImageCapture(m_camera);
    m_cameraImageCapture->setCaptureDestination(
                QCameraImageCapture::CaptureToBuffer);

    // Camera API
    connect(m_camera, SIGNAL(locked()), this, SIGNAL(locked()));
    connect(m_camera, SIGNAL(lockFailed()), this, SIGNAL(lockFailed()));

    connect(m_camera, SIGNAL(stateChanged(QCamera::State)),
            this, SLOT(cameraStateChanged(QCamera::State)));
    connect(m_camera, SIGNAL(stateChanged(QCamera::State)),
            this, SIGNAL(cameraStateChanged()));

    // Image capture API
    connect(m_cameraImageCapture, SIGNAL(imageCaptured(int, const QImage&)),
            this, SIGNAL(imageCaptured(int, const QImage&)));

    connect(m_cameraImageCapture, SIGNAL(imageAvailable(int, const QVideoFrame&)),
            this, SLOT(imageAvailable(int, const QVideoFrame&)));

    // Set the initial capture mode to image capturing.
    m_camera->setCaptureMode(QCamera::CaptureStillImage);

    // Begin the receiving of view finder frames.
    m_camera->start();
}

The capture destination is set to QCameraImageCapture::CaptureToBuffer resulting in an image buffer of the captured image (instead of automatically writing it to a file). This method is available since Qt Mobility 1.2. The captured image buffer is sent through the slot. When a full-resolution picture arrives it is copied to the worker thread (see next section).

void CustomCamera::imageAvailable(int id, const QVideoFrame &frame)
{
    if (frame.map(QAbstractVideoBuffer::ReadOnly))
    {
        m_fipThread->setFullResolutionFrame(&frame);
        frame.unmap();
    }
}

The worker thread notifies the class when a viewfinder image is processed and tells the QML view to repaint (update):

void CustomCamera::processedFrameAvailable()
{
    update();
}

The method pulls the latest processed image from the worker thread and draws it on the center of the QML view:

void CustomCamera::paint(QPainter *painter,
                         const QStyleOptionGraphicsItem *option,
                         QWidget *widget)
{
    // Get processed image from worker thread and draw it.
    QImage *ptrImage = m_fipThread->getLatestProcessedImage();

    if (ptrImage)
    {
        QPointF upperLeft = boundingRect().center() -
                QPointF(ptrImage->width() / 2,
                        ptrImage->height() / 2);


        // Draw the black borders.
        painter->fillRect(0, 0, upperLeft.x(), boundingRect().height(),
                          Qt::black);
        painter->fillRect(upperLeft.x() + ptrImage->width(), 0,
                          boundingRect().right(), boundingRect().bottom(),
                          Qt::black);

        painter->drawImage(QRect(upperLeft.x(), upperLeft.y(),
                                 ptrImage->width(),
                                 ptrImage->height()), *ptrImage);

        // unlock
        m_fipThread->getLatestProcessedImageReady();
    }
}

The paint method presented above works only in Symbian. In Meego we have to draw the image using an OpenGL texture and OpenGL ES 2 shaders because the output of is overwritten by the OpenGL drawing routines. QML 2.0 which will be included with Qt 5.0 offers a scene graph API which hides the OpenGL complexity from the user and allows painting of QImages on the Nokia N9 as well. The procedure for drawing in OpenGL is as follows (not included in the example source code):

painter->beginNativePainting();
// 1.) Upload texture
glBindTexture(...);
glTexSubImage2d(...); // update texture data on GPU

// 2.) Bind shader 
glBindProgram(program_id);

// 3.) Draw geometry with texture
glDrawElements(...);
painter->endNativePainting();

Before we can use our class in QML, it has to be registered somewhere before loading the QML source code (e.g. in the application’s main method):

void FIPMain::show()
{
    qmlRegisterType<CustomCamera>("CustomElements", 1, 0, "CustomCamera");
    m_qmlView.setSource(QUrl("qrc:/qml/MainView.qml"));
    m_qmlView.showFullScreen();
}

The can now be easily used in QML:

import CustomElements 1.0

Page {
    Component.onCompleted: {
        camera.start();
    }
    
    CustomCamera {
        id: camera
        anchors.fill: parent
    }
}

Spawning a worker thread for background image processing

To keep the user interface responsive a worker thread is created which handles all image effect processing. More information about threading in Qt can be found here. First, we define our class FIPThread which is responsible for image processing work:

class FIPThread : public QThread
{
    Q_OBJECT
public:
    // Worker loop
    void run();

    // Is an image currently processed?
    inline bool isProcessing() const {
        return m_stateProcessing;
    }
    
Q_SIGNALS:
    void newFrameReady();
    void fullImageSaved(QString fn);
private:
    enum TMode {
        EMode_Live,
        EMode_Captured
    };

    TMode m_currentMode;

    int m_frameIdx; // current buffer marked as ready
    QImage m_frames[2]; // double buffer
    QImage m_fullResFrame;

    bool m_stateProcessing;

    QMutex m_mutex;
    QWaitCondition m_condition;

    bool m_abort;
    bool m_restart;

    int m_effectThreshold;
};

This class emits two different signals:

  • is emitted when a viewfinder frame is ready.
  • is emitted when the captured image has been processed and saved.

The following member variables are defined:

  • if working on a viewfinder image or if working on a full resolution image.
  • two QImage objects are used for double buffering. One buffer at position holds the latest processed image, while the other buffer is used during processing. If == -1 then no processed image is available.
  • holds the full resolution captured image (not processed). The image is automatically freed after processing.
  • indicates whether the thread is currently processing an image.
  • the effect’s parameter value.

New viewfinder frames are added to the worker thread with the following method:

void FIPThread::setNewFrame(QVideoFrame *ptrFrame)
{
    // Drop frame if last frame is still being processed or not in live mode
    if (m_stateProcessing || m_currentMode != EMode_Live)
        return;

    QMutexLocker locker(&m_mutex);

    // Select buffer which is not in use at the moment
    if (m_frameIdx < 0) m_frameIdx = 0;
    int bufferIdx = 1 - m_frameIdx;

    if (m_frames[bufferIdx].isNull() || m_frames[bufferIdx].width() != ptrFrame->width() ||
        m_frames[bufferIdx].height() != ptrFrame->height()) {
        m_frames[bufferIdx] = QImage(ptrFrame->width(), ptrFrame->height(), QImage::Format_ARGB32);
    }

    // Copy data to local buffer
    memcpy(m_frames[bufferIdx].bits(), ptrFrame->bits(), ptrFrame->mappedBytes());

    // Start processing
    m_abort = false;
    if (!isRunning()) {
        start(LowPriority);
    } else {
        m_restart = true;
        m_condition.wakeOne();
    }
}

The method copies the frame data to the locked double buffer, and starts or restarts the thread. The QMutexLocker is used to automatically release the mutex lock when the method is left. For full-resolution captured images the following method is used which incorporates decoding of the frame data (from usually EXIF Jpeg) to QImage:

void FIPThread::setFullResolutionFrame(QVideoFrame *ptrFrame)
{
    QMutexLocker locker(&m_mutex);

    // Decode and copy frame data to local buffer.
    // "loadFromData()" consumes a lot of time. To improve performance, the raw data could be copied here
    // and "loadFromData()" be called in "run()" method.
   //  We want to avoid too much data copying here and thus decode in the main thread.
    if (m_fullResFrame.loadFromData(ptrFrame->bits(), ptrFrame->mappedBytes()))
    {
        m_currentMode = EMode_Captured;

        // Start processing
        m_abort = false;
        if (!isRunning()) {
            start(LowPriority);
        } else {
            m_restart = true;
            m_condition.wakeOne();
        }
    }
}

The image processing is performed in the thread’s method:

void FIPThread::run()
{
    forever
    {
        int effectThreshold;
        TMode currentMode;
        BlackAndWhiteEffect effect;
        int curIdx;
        QImage *ptrImage;

        // We "freeze" the state by copying class variables to local variables.
        m_mutex.lock();
        m_stateProcessing = true;
        effectThreshold = m_effectThreshold;
        currentMode = m_currentMode;
        m_mutex.unlock();

        // In live mode we use double buffering
        if (currentMode == EMode_Live)
        {
            curIdx = 1 - m_frameIdx;
            ptrImage = &m_frames[curIdx];
        }
        else
        {
            curIdx = m_frameIdx;
            ptrImage = &m_fullResFrame;
        }

        // Apply effect directly to the source image (overriding the source image).
        effect.applyEffect(*ptrImage, *ptrImage, effectThreshold);

        if (currentMode == EMode_Captured)
        {
            // Save image
            QString fn = QDesktopServices::storageLocation(QDesktopServices::PicturesLocation) +
                    QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss.jpg");
            if (ptrImage->save(fn))
                emit fullImageSaved(fn);

            // Free memory of full-resolution buffer
            m_fullResFrame = QImage();
        }
        else
        {
            // Signal that a new processed frame is available.
            // There is no guarantee that *this* frame is available with "getLatestProcessedImage()".
            // For this scenario the latest frame is sufficient.
            emit newFrameReady();
        }

        // Now we are ready for the next frame.
        m_mutex.lock();
        m_frameIdx = curIdx;
        m_stateProcessing = false;

        if (m_abort)
        {
            m_mutex.unlock();
            return;
        }
        if (!m_restart)
        {
            // Block the loop and wait for new data
            m_condition.wait(&m_mutex);
        }
        m_restart = false;
        m_mutex.unlock();
    }
}

First we copy member variables to local variables which might change outside the run loop during processing. A mutex locks to prevent concurrent access to memory during copying. In live mode the buffers are swapped after processing while in capture mode the full resolution image is processed, saved to a file, and memory is freed. Finally we check if the thread is about to exit (==true) or more work has to be done (==true). If both, and , evaluate to false then we wait for more work.

To get the latest processed viewfinder image the following method is used:

QImage * FIPThread::getLatestProcessedImage()
{
    m_mutex.lock();
    if (m_frameIdx == -1 || m_frames[m_frameIdx].isNull())
    {
        m_mutex.unlock();
        return NULL;
    }
    return &m_frames[m_frameIdx];
}

The mutex is locked to prevent writing to the image buffer during reading. Thus, after reading it has to be released:

void FIPThread::getLatestProcessedImageReady()
{
    m_mutex.unlock();
}

Before the worker thread can be released it has to stop processing of eventual remaining work:

FIPThread::~FIPThread()
{
    // Wait for the worker thread to finish.
    m_mutex.lock();
    m_abort = true;
    m_condition.wakeOne();
    m_mutex.unlock();
    wait();
}

Adding a simple black and white effect

For this sample application a simple threshold-based black and white effect is applied:

bool BlackAndWhiteEffect::applyEffect(const QImage &srcImg, QImage &dstImg, const int &thresh)
{
    // Check if in/out images match
    if (srcImg.size() != dstImg.size() || srcImg.format() != dstImg.format())
    {
        return false;
    }

    // Parameters
    int w1 = 76; // (0.299f);
    int w2 = 149; // (0.587f);
    int w3 = 29; // (0.114f);

    int intensity;
    int threshold = thresh;

    // Process image
    uint r,g,b;
    uint *ptrSrc = (uint*)srcImg.bits();
    uint *ptrDst = (uint*)dstImg.bits();
    uint *end = ptrSrc + srcImg.width() * srcImg.height();
    while (ptrSrc != end) {
        // Extract RGB components from the source image pixel
        r = (*ptrSrc&0xff);
        g = (((*ptrSrc)>>8)&0xff);
        b = (((*ptrSrc)>>16)&0xff);

        // Gray (intensity) from RGB
        intensity = ((w1 * r) + (w2 * g) + (w3 * b)) >> 8;

        // Decide between black and white based on threshold
        if (intensity < threshold)
        {
            r = g = b = 0;
        }
        else
        {
            r = g = b = 255;
        }

        // "Mix" rgb values and save to destination image
        *ptrDst = r | (g<<8) | (b<<16) | 0xFF000000;

        // Jump to next pixel
        ptrSrc++;
        ptrDst++;
    }

    return true;
}

First, we check if source and destination images’ metrics match. Then for each pixel the intensity is calculated. If the intensity is below a given threshold then the pixel color is set to black, else to white. Intensity is calculated by weighting the red, green, and blue color components (assuming red, green, blue are in the range between 0 and 255):

Intensity = red*0.299 + green*0.587 + blue*0.114;

When image data is processed on the CPU (not GPU) then integer operations are often much faster than floating point operations (note: some compilers convert/optimize floating point operations to integer operations automatically). For image processing this can account in huge processing speed gains. Our intensity value can be calculated using only integers (at the cost of loss of accuracy):

Intensity = (red*76 + green*149 + blue*29) / 256;

The float values have been converted to integers by multiplication of 256. The accuracy can be increased by using higher factors than 256 but it must be paid attention to buffer overruns. Another mean to gain performance is the use of shift operations (often automatically applied by the compiler). Here the trick is for instance to get rid of multiplication and division of integers by using shifts, where “<<” shifts left (multiplication) and “>>” shifts right (division):

Intensity = (red*76 + green*149 + blue*29) >> 8;

Adding a control for live user interaction

Our simple black and white effect has one parameter, a threshold, which decides which intensities are marked as black, and which ones are white. In the QML file we add a slider to control this threshold:

Slider {
    id: sldThreshold
    minimumValue: 0
    maximumValue: 255
    stepSize: 1
    orientation: Qt.Vertical
    onValueChanged: camera.effectThreshold = value
}

Each time the slider’s value is changed, the component is notified which forwards the parameter to the worker thread:

void CustomCamera::effectThreshold(int thresh)
{
    m_fipThread->setEffectThreshold(thresh);
}

void FIPThread::setEffectThreshold(const int &thresh)
{
    QMutexLocker locker(&m_mutex);
    m_effectThreshold = thresh;
}

Discussion about hardware acceleration

The presented effect is calculated on the CPU without specific hardware acceleration. Generally, there are two means for hardware acceleration on mobile devices:

  • ARM specific instructions (assembler)
  • OpenGL ES shaders

ARM assembler code using vectorization has huge performance potential but is hard to develop and can be incompatible between different device models. A use-case for ARM assembler is for instance UYVY to RGB24 conversion on the Nokia N9 (as an alternative to the method presented in this article).

OpenGL ES shaders are compatible between different models (with small tweaks) starting with Symbian\^3 but performance is heavily affected by the time required to upload image data to the GPU. Besides, many mobile GPUs are limited memory and texture size wise allowing only small images (e.g. viewfinder size) to be easily processed. A use case for OpenGL is the live effect preview using QML 1.2 on the Nokia N9 (see here). Other use cases for OpenGL are effects which heavily incorporate floating point calculations which cannot be converted to integer arithmetic.

The next table gives a comparison of processing and drawing times in milliseconds (ms) for ARM, OpenGL, and CPU-based conversion of UYVY to RGBA data on a Nokia N9 PR 1.2 (mean over 300 runs; α=0.05 for t-test):

ARM CPU ARM/CPU drawing OpenGL + drawing OpenGL upload
5 9.09 5.69 7.82 18.03
         

It can be seen that ARM-based conversion is the fastest and sums up to 10.69ms for conversion and drawing. The CPU-based conversion requires almost double the time and sums up to 14.78ms. OpenGL ES 2 shader based drawing and conversion requires 7.82ms but the time for upload is very high and requires 18.03 which sums up to a total of 25.85ms.

From a performance perspective the best means for data conversion and drawing is ARM-based conversion with “normal” drawing. But with QML 1.2 on the Nokia N9 only OpenGL-based drawing is supported. Thus, if QML is used, the best method is to do conversion and drawing with OpenGL ES 2 shaders. Finally, it should be noted that all methods are fine for live video preview because with a frame rate of 30fps the available frame time is 33.33ms.

When should multi-threading be used?

Multi-threading incorporates additional processing and memory costs for thread management, inter-thread communication, locking, and data copying. As a rule-of-thumb multi-threading should be used if a task (e.g. image processing) is expected to take longer than 1 second (see Gnome guidelines for desktop here; users of mobile devices accept only very short response times!).

This article focuses on multi-threading for user interface responsiveness by processing live data in a worker thread. But multi-threading is also useful when multiple tasks can be run in parallel, as for instance in the QHdrCamera project where image processing starts during capturing of remaining pictures which decreases processing time significantly.

Summary

This article presents a brief overview on how to apply near-real time image processing effects to a camera viewfinder using QML and how to capture full-resolution snapshots. It outlines how image processing can be moved to a worker thread and how to handle concurrent access using double buffering and mutex. Finally, optimizations are discussed.

Extract boot.img from an android device, unpack/repack it, and write it back to the android device.

I did this on my rooted, boot-unlocked Nexus 7 II running Android 4.4.2 under Windows.

This tutorial pointed me in the right direction.

###boot.img Retrieve Instructions

I use adb tools to retrieve the desired boot-from-android-device.img, after that, I use Root Explorer to copy the file, so that we can copy the file to computer through MTP:

;use the following commands to found the boot partition,note:msm_sdcc.1 is different on different android device
adb shell
ls -l /dev/block/platform/
;now we know the device platform is msm_sdcc.1
ls -l /dev/block/platform/msm_sdcc.1/by-name
; now we know the boot partition is cat mmcblk0p14 by [boot -> /dev/block/mmcblk0p14]
;use the following command to retrieve the boot.img
su
cat /dev/block/mmcblk0p14 > /sdcard/boot-from-android-device.img
chmod 0666 /sdcard/boot-from-android-device.img

###Repack Instructions I use Android Image Kitchen to unpack the boot.img and repack it to boot-from-android-device-repacked.img.

1) Unzip
2) Either use the command-line "unpackimg <image-filename.img>", or simply drag-and-drop the image. This will split the image and unpack the ramdisk to a subdirectory.
3) Alter the ramdisk as you like.
4) The repackimg batch script requires no input and simply recombines the previously split zImage with the newly packed modified ramdisk using all the original image information (which was also split and saved).
5) The cleanup batch script resets the folder to its initial state, removing the split_img+ramdisk directories and any new packed ramdisk or image files.

###Write the boot.img back to the Android device. I use fastboot tool to do the job.

adb reboot-bootloader
;[wait for bootloader to come up]
fastboot flash boot boot-from-android-device-repacked.img
fastboot reboot

罗技摄像头C270与嵌入式LINUX

现在,假如你的手上有一只摄像头,它是罗技高清网络摄像头webcam-C270,还有一块cortexA8开发板,这块开发板来自FriendlyARM,已经预装了linux系统,版本号是最新提供的linux-3.0.8,图形界面是Qtopia-2.2.0,交叉编译器是arm-linux-gcc-4.5.1。主机是Fedora9。 摄像头和开发板,这两样东西安安静静的躺在了你的手里,准备就绪,状态良好。而你的任务,就是要让摄像头正常的工作在开发板上,并且完成一些简单的任务,比如说将图像显示在Qtopia的界面上,并判断当前的图像中有没有阿拉伯数字。 (虽然说C270并不支持linux系统,可是支持linux系统的摄像头又有几只呢?即使C270不支持linux系统,不代表linux系统不支持C270^_^)

Simple Trace implement with macros in C/C++

Permalink

C语言##__VA_ARGS__

在GNU C中,宏可以接受可变数目的参数,就象函数一样,例如:

#define pr_debug(fmt,arg...)  
printk(KERN_DEBUG fmt, ##arg) 

用可变参数宏(variadic macros)传递可变参数表

你可能很熟悉在函数中使用可变参数表,如:

void printf(const char* format, ...); 

直到最近,可变参数表还是只能应用在真正的函数中,不能使用在宏中。

C99编译器标准终于改变了这种局面,它允许你可以定义可变参数宏(variadic macros),这样你就可以使用拥有可以变化的参数表的宏。可变参数宏就像下面这个样子:

#define debug(...) printf(__VA_ARGS__) 

缺省号代表一个可以变化的参数表。使用保留名 __VA_ARGS\__ 把参数传递给宏。当宏的调用展开时,实际的参数就传递给 printf()了。例如:

Debug("Y = %dn", y); 

而处理器会把宏的调用替换成:

printf("Y = %dn", y); 

因为debug()是一个可变参数宏,你能在每一次调用中传递不同数目的参数:

debug("test");  // 一个参数 

可变参数宏不被ANSI/ISO C++ 所正式支持。因此,你应当检查你的编译器,看它是否支持这项技术。

用GCC和C99的可变参数宏, 更方便地打印调试信息

gcc的预处理提供的可变参数宏定义真是好用:

#ifdef DEBUG 
#define dbgprint(format,args...)  
fprintf(stderr, format, ##args) 
#else 
#define dbgprint(format,args...) 
#endif 

如此定义之后,代码中就可以用dbgprint了,例如dbgprint(“%s”, __FILE__);

下面是C99的方法:

#define dgbmsg(fmt,...)     printf(fmt,__VA_ARGS__) 

新的C99规范支持了可变参数的宏

具体使用如下:

以下内容为程序代码:

#include  
#include  
#define LOGSTRINGS(fm, ...) printf(fm,__VA_ARGS__) 
int main() 
{ 
    LOGSTRINGS("hello, %d ", 10); 
    return 0; 
} 

但现在似乎只有gcc才支持。

可变参数的宏里的’##’操作说明带有可变参数的宏(Macros with a Variable Number of Arguments)

在1999年版本的ISO C 标准中,宏可以象函数一样,定义时可以带有可变参数。宏的语法和函数的语法类似。下面有个例子:

#define debug(format, ...) fprintf (stderr, format, __VA_ARGS__) 

这里,’…‘指可变参数。这类宏在被调用时,它(这里指’…‘)被表示成零个或多个符号,包括里面的逗号,一直到到右括弧结束为止。当被调用时,在宏体(macro body)中,那些符号序列集合将代替里面的__VA_ARGS\__标识符。更多的信息可以参考CPP手册。

GCC始终支持复杂的宏,它使用一种不同的语法从而可以使你可以给可变参数一个名字,如同其它参数一样。例如下面的例子:

#define debug(format, args...) fprintf (stderr, format, args) 

这和上面举的那个ISO C定义的宏例子是完全一样的,但是这么写可读性更强并且更容易进行描述。

GNU CPP还有两种更复杂的宏扩展,支持上面两种格式的定义格式。

在标准C里,你不能省略可变参数,但是你却可以给它传递一个空的参数。例如,下面的宏调用在ISO C里是非法的,因为字符串后面没有逗号:

debug (“A message”)

GNU CPP在这种情况下可以让你完全的忽略可变参数。在上面的例子中,编译器仍然会有问题(complain),因为宏展开后,里面的字符串后面会有个多余的逗号。

为了解决这个问题,CPP使用一个特殊的’##’操作。书写格式为:

#define debug(format, ...) fprintf (stderr, format, ## __VA_ARGS__) 

这里,如果可变参数被忽略或为空,’##’操作将使预处理器(preprocessor)去除掉它前面的那个逗号。如果你在宏调用时,确实提供了一些可变参数,GNU CPP也会工作正常,它会把这些可变参数放到逗号的后面。象其它的pasted macro参数一样,这些参数不是宏的扩展。

##还可以起到替换作用

如:

#define FUN(IName)  IName##_ptr 

这里将会把IName变成实际数据.

怎样写参数个数可变的宏

一种流行的技巧是用一个单独的用括弧括起来的的 ``参数” 定义和调用宏, 参数在 宏扩展的时候成为类似 printf() 那样的函数的整个参数列表。

#define DEBUG(args) (printf("DEBUG: "), printf args) 
if (n != 0) DEBUG(("n is %dn", n)); 

明显的缺陷是调用者必须记住使用一对额外的括弧。

gcc 有一个扩展可以让函数式的宏接受可变个数的参数。 但这不是标准。另一种 可能的解决方案是根据参数个数使用多个宏 (DEBUG1, DEBUG2, 等等), 或者用逗号玩个这样的花招:

#define DEBUG(args) (printf("DEBUG: "), printf(args)) 
#define _ , 
DEBUG("i = %d" _ i); 

C99 引入了对参数个数可变的函数式宏的正式支持。在宏 ``原型” 的末尾加上符号 … (就像在参数可变的函数定义中), 宏定义中的伪宏 __VA_ARGS\__ 就会在调用是 替换成可变参数。

最后, 你总是可以使用真实的函数, 接受明确定义的可变参数

如果你需要替换宏, 使用一个 函数和一个非函数式宏, 如 #define printf myprintf

C/C++ TRACE


#define ENABLE(x) ENABLE_##x
#define TRACE_LEVEL(level) level##_TRACE_LEVEL

#define TRACE_LEVEL_FATAL 0
#define TRACE_LEVEL_ERROR 1
#define TRACE_LEVEL_WARNING 2
#define TRACE_LEVEL_INFO 3
#define TRACE_LEVEL_DEBUG 4

#define TRACE_IMPL(error_level, module, format, ...) \
    if (ENABLE(module) && error_level <= TRACE_LEVEL(module)) {\
        printf("[%s:%d %s %s %d]\r\n", #module, error_level, __FILE__, __FUNCTION__, __LINE__); \
        printf(format, __VA_ARGS__);\
    } \

#define TRACE_FATAL(module, format, ...) TRACE_IMPL(TRACE_LEVEL_FATAL, module, format, __VA_ARGS__)
#define TRACE_ERROR(module, format, ...) TRACE_IMPL(TRACE_LEVEL_ERROR, module, format, __VA_ARGS__)
#define TRACE_WARNING(module, format, ...) TRACE_IMPL(TRACE_LEVEL_WARNING, module, format, __VA_ARGS__)
#define TRACE_INFO(module, format, ...) TRACE_IMPL(TRACE_LEVEL_INFO, module, format, __VA_ARGS__)
#define TRACE_DEBUG(module, format, ...) TRACE_IMPL(TRACE_LEVEL_DEBUG, module, format, __VA_ARGS__)

void testTrace()
{
#define ENABLE_ACAS 1

#define ACAS_TRACE_LEVEL TRACE_LEVEL_FATAL
    TRACE_ERROR(ACAS, "Error\r\n");
    TRACE_FATAL(ACAS, "Fatal\r\n");

#define ACAS_TRACE_LEVEL TRACE_LEVEL_INFO
    TRACE_INFO(ACAS, "Info\r\n");
    TRACE_DEBUG(ACAS, "Debug\r\n");
}

XY Problem

“XY Problem” explanations by various people:

Every now and then I hear people say I might have an “XY problem”. What is that?

  • You want to do X, and you think Y is the best way of doing so. Instead of asking about X, you ask about Y.
    — from “Re: sequencial file naming” by Abigail

  • You’re trying to do X, and you thought of solution Y. So you’re asking about solution Y, without even mentioning X. The problem is, there might be a better solution, but we can’t know that unless you describe what X is.
    — from Re: How do I keep the command line from eating the backslashes? by revdiablo

  • Someone asks how to do Y when they really want to do X. They ask how to do Y because they believe it is the best way to accomplish X. People trying to help go through many iterations of “try this”, followed by “that won’t work because of”. That is, depending on the circumstances, other solutions may be the way to go.
    — from Re: Re: Re: Re: regex to validate e-mail addresses and phone numbers by Limbic~Region

  • To answer question Y, without understanding larger problem (the context) X, will most likely not help them entirely with X.
    — from The XY problem (was Re: CGI.pm: controlling Back & Reload) by Randal L. Schwartz

  • A.k.a. “premature closure”: the questioner wanted to solve some not very clearly stated X, they concluded that Y was a component of a solution, and now they’re asking how to implement Y.
    — from Re: CGI.pm: controlling Back & Reload by Alan J. Flavell

  • The XY problem is when you need to do X, and you think you can use Y to do X, so you ask about how to do Y, when what you really should do is state what your X problem is. There may be a Z solution that is even better than Y, but nobody can suggest it if X is never mentioned.
    — from Re: Compound scalar names? by Tad McClellan

  • When people come [in here] asking how to do something stupid, I’m never quite sure what to do. I can just answer the question as asked, figuring that it’s not my problem to tell people that they’re being stupid. . . . But if I do that, people might jump on me for being a smart aleck, which has happened at times. (“Come on, help the poor guy out; if you know what he really need why don’t you just give it to him?”)
    . . .
    On the other hand, I could try to answer on a different level, present a better solution, and maybe slap a little education on ‘em. That’s nice when it works, but if it doesn’t it’s really sad to see your hard work and good advice ignored. Also, people tend to jump on you for not answering the question. (“Who are you to be telling this guy what he should be doing? Just answer the question.”)
    . . .
    I guess there’s room for both kinds of answer. Or maybe there isn’t room for either kind.
    — from Why it’s stupid to use a variable as a variable name by Mark-Jason Dominus

  • The questions I like the best are the ones that go like this:

      I want to accomplish X.
    	
      I thought that the following code fragment would do it:
    	
      ...
    	
      But instead it does Y.
    	
      Why is that? This one is also pretty good:
    
      I want to accomplish X.
    	
      I thought I might be able to use facility Y.
    	
      But Y doesn't seem like it's quite right, 
      because of Z.
    	
      What should I use instead of Y, or how can I overcome Z? — from [Re: system() question](https://groups.google.com/forum/?fromgroups=#!msg/comp.lang.perl/wu0T7a9orc0/3Q4PVIbEzZUJ "I never get answers to questions in newsgroups.") by Mark-Jason Dominus
    
  • TIP: How to post good questions In article fl_aggie-2406981247580001@aggie.coaps.fsu.edu, I R A Aggie fl_aggie@thepentagon.com wrote:

    Dominus wrote:

    ``How do I use X to accomplish Y?’’ There’s nothing wrong with this, except that sometimes X is a chocolate-covered banana and Y is the integration of European currency systems.

A less abominable example of this that comes up all the time is

I have an array of strings.  How do I check whether the array
contains a certain string? Usually (not always, but usually) the best answer is to `unask the question`:

You should be using a hash, not an array. I wish I had a convenient term for this kind of mistake. The general case is:
  1. Someone wants to accomplish task Y.
  2. They determine that a way to accomplish Y is to use facility X.
  3. There is a sub-task of Y, say Z, for which X is ill-suited.
  4. They come into the group and ask "how can I use X to accomplish Z?"

This is a problem for people here trying to answer the real question, which is:

How can I accomplish Y? — from [TIP: How to post good questions](http://perl.plover.com/Questions3.html) by Mark-Jason Dominus

Semaphore, Mutex, Critical section, SpinLock, Event

####Critical Section

In concurrent programming, a critical section is a piece of code that accesses a shared resource (data structure or device) that must not be concurrently accessed by more than one thread of execution. A critical section will usually terminate in fixed time, and a thread, task, or process will have to wait for a fixed time to enter it (aka bounded waiting). Some synchronization mechanism is required at the entry and exit of the critical section to ensure exclusive use, for example a semaphore. (From wiki)

中文名叫做临界区.不论是硬件临界资源,还是软件临界资源,多个线程必须互斥地对它进行访问。由于不需要进入系统级(Mutex可以用于跨进程同步,因此是内核对象),它比较轻量,效率会高很多(Windows下)。但是有的操作系统进程线程是同一个概念,比如在VxWorks只有Task,在这种环境下,Mutex与Critical Section是等价的。

#####Critical Section Usage Example Code For Critical Sections with POSIX pthread library

/* Sample C/C++, Unix/Linux */
#include <pthread.h>
 
/* This is the critical section object (statically allocated). */
static pthread_mutex_t cs_mutex = PTHREAD_MUTEX_INITIALIZER;
 
void f()
{
    /* Enter the critical section -- other threads are locked out */
    pthread_mutex_lock( &cs_mutex );
 
    /* Do some thread-safe processing! */
 
    /*Leave the critical section -- other threads can now pthread_mutex_lock()  */
    pthread_mutex_unlock( &cs_mutex );
}
 
int main()
{
    f();
 
    return 0;
}

Example Code For Critical Sections with Win32 API

/* Sample C/C++, Windows, link to kernel32.dll */
#include <windows.h>
 
static CRITICAL_SECTION cs; /* This is the critical section object -- once initialized,
                               it cannot be moved in memory */
                            /* If you program in OOP, declare this as a non-static member in your class */ 
void f()
{
    /* Enter the critical section -- other threads are locked out */
    EnterCriticalSection(&cs);
 
    /* Do some thread-safe processing! */
 
    /* Leave the critical section -- other threads can now EnterCriticalSection() */
    LeaveCriticalSection(&cs);
}
 
int main()
{
    /* Initialize the critical section before entering multi-threaded context. */
    InitializeCriticalSection(&cs);
 
    f(); 
 
    /* Release system object when all finished -- usually at the end of the cleanup code */
    DeleteCriticalSection(&cs);
 
    return 0;
}
Critical Section 与 Mutex 的区别

Critical Section不是一个核心对象,无法获知进入临界区的线程是生是死,如果进入临界区的线程挂了,没有释放临界资源,系统无法获知,而且没有办法释放该临界资源。而 Mutex 是有超时选项的,如果一个 Mutex 占用资源太久,那么会直接被释放。而且可以在其它进程销毁 Mutex对象,但是 Critical Section就不可以

Critical Section properties

Typically, critical sections prevent process and thread migration between processors and the preemption of processes and threads by interrupts and other processes and threads.

Critical sections often allow nesting. Nesting allows multiple critical sections to be entered and exited at little cost. If the scheduler interrupts the current process or thread in a critical section, the scheduler will either allow the currently executing process or thread to run to completion of the critical section, or it will schedule the process or thread for another complete quantum. The scheduler will not migrate the process or thread to another processor, and it will not schedule another process or thread to run while the current process or thread is in a critical section.

Similarly, if an interrupt occurs in a critical section, the interrupt’s information is recorded for future processing, and execution is returned to the process or thread in the critical section. Once the critical section is exited, and in some cases the scheduled quantum completes, the pending interrupt will be executed. The concept of scheduling quantum applies to “Round Robin” and similar scheduling policies.

Since critical sections may execute only on the processor on which they are entered, synchronization is only required within the executing processor. This allows critical sections to be entered and exited at almost zero cost. No interprocessor synchronization is required, only instruction stream synchronization. Most processors provide the required amount of synchronization by the simple act of interrupting the current execution state. This allows critical sections in most cases to be nothing more than a per processor count of critical sections entered.

Performance enhancements include executing pending interrupts at the exit of all critical sections and allowing the scheduler to run at the exit of all critical sections. Furthermore, pending interrupts may be transferred to other processors for execution.

Critical Section 使用注意事项

Critical sections should not be used as a long-lived locking primitive. They should be short enough that the critical section will be entered, executed, and exited without any interrupts occurring, neither from hardware much less the scheduler.

Critical Section under Linux is futex

The ‘fast’ Windows equal of critical selection in Linux would be a futex, which stands for fast user space mutex. The difference between a futex and a mutex is that with a futex, the kernel only becomes involved when arbitration is required, so you save the overhead of talking to the kernel each time the atomic counter is modified. A futex can also be shared amongst processes, using the means you would employ to share a mutex.

Unfortunately, futexes can be very tricky to implement (PDF).

####Mutex (“mutual exclusion” lock)

Mutex和critical section一样,用来保证同时只有一个线程进入某区域,通常用来实现对某单一资源的访问控制。Mutex可以设定time out,可以不像critical section一样死等。如果一个拥有Mutex的线程在返回之前没有调用ReleaseMutex(),那么这个Mutex就被舍弃了,但是当其他线程等待(WaitForSingleObject等)这个Mutex时,仍能返回,并得到一个WAIT_ABANDONED_0返回值。

A mutex (which stands for “mutual exclusion” lock) is a locking or synchronization object that allows multiple threads to synchronize access to shared resources. It is often used to ensure that shared variables are always seen by other threads in a consistent state.

In Windows, the mutexes are both named and un-named. The named mutex is shared between the threads of different process.

在MS Windows上API是CreateMutex(), OpenMutex(), ReleaseMutex(), WaitForSingleObject()和WaitForMultipleObjects()。用MFC库的CMutex类可以完成同样功能。

In Linux, the mutexes are shared only between the threads of the same process. To achieve the same functionality in Linux, a System V semaphore can be used (具体参考这篇文章).

支持POSIX库的系统(Linux/Unix)上有pthread_mutex_lock()和pthread_mutex_unlock()。

简单说CriticalSection is a user-mode component implemented by the Win32 subsystem, while Mutex is a kernel-mode component. Practially, CriticalSection is much faster when there’s no actual blocking (due to reduction in user-kernel mode switches), and probably slower when there is blocking (due to more complex implementation). Additionally, since a Mutex is represented by a HANDLE, you can wait on a mutex with a timeout, or with several other handles. Neither option is available with a Critical Section. Mutexes can be named and shared between processes, while CriticalSections are restricted to the threads of a single process.

####Semaphore

特点是有计数,同时可以有N个线程可以进入一个区域。Windows上的API有CreateSemaphore(), OpenSemaphore(), ReleaseSemaphore(), WaitForSingleObject()和WaitForMultipleObjects()。或者用MFC的CSemaphore类。

VxWorks没有Mutex, 它提供三种Semaphore: binary, counting, mutex. 相关API是semBCreate, semMCreate, semCCreate, semDelete, semTake, semGive, semFlush

在VxWork上,Mutex会触发prority inheritance. If a higher priority task is waiting for a semaphore taken a low priority task and the low priority task, its priority will be temporarily changed to the high priority task which is waiting.

####Binary semaphore

在有的系统中Binary semaphore与Mutex是没有差异的。在有的系统上,主要的差异是mutex一定要由获得锁的进程来释放。而semaphore可以由其它进程释放(这时的semaphore实际就是个原子的变量,大家可以加或减),因此semaphore可以用于进程间同步。Semaphore的同步功能是所有系统都支持的,而Mutex能否由其他进程释放则未定,因此建议mutex只用于保护critical section。而semaphore则用于保护某变量,或者同步。

####Event

Event可以用来实现observer模式。创建一个Event,然后用WaitForSingleObject()挂起等待其它线程点亮(set)这个Event。我经常用的一个伎俩是在用户态创建一个Event的句柄,然后通过DeviceIoControl()把它传到驱动里面去,当驱动收到外部总线传来的数据包就点亮这个Event。Windows的API是CreateEvent(), OpenEvent(), SetEvent(), WaitForSingleObject(), WaitForMultipleObjects()。MFC库里有CEvent类。

####Spin lock

spin lock是一个内核态概念。spin lock与semaphore的主要区别是spin lock是busy waiting,而semaphore是sleep。对于可以sleep的进程来说,busy waiting当然没有意义。对于单CPU的系统,busy waiting当然更没意义(没有CPU可以释放锁)。因此,只有多CPU的内核态非进程空间,才会用到spin lock。Linux kernel的spin lock在非SMP的情况下,只是关irq,没有别的操作,用于确保该段程序的运行不会被打断。其实也就是类似mutex的作用,串行化对 critical section的访问。但是mutex不能保护中断的打断,也不能在中断处理程序中被调用。而spin lock也一般没有必要用于可以sleep的进程空间。