laboratory of symstore.exe

Example 1 – creating a symbol store:
symstore add /r /f <folder where symbol files locate> /s <target folder where symbol store will be created> /t <product for this symbol store> /v <version info> /c <extra comment of this symbol store>
Example 2 – creating a symbol store with symbols compressed:
step 1 – create a file pointer:
symstore add /r /p /l /f "C:\Documents and Settings\daiw\Desktop\Task Plann
ing\TaskPlanning\website\Bin\*.*" /s \\cadccippublic2\webservices\MSSymbols /t "TaskPlanning" /v "Build 1" /c "test for symbol store"
[Note: SYMSTORE ERROR: Class: Syntax. Desc: /f must be followed by a network path when storing pointers unless /l is used.]
 
step 2 – compress binary and symbol files:
[Note: user compress.exe from Windows Server 2003 kit tool to compress the symbol files.]
 
C:\Program Files\Windows Resource Kits\Tools>compress.exe "C:\Documents and Settings\daiw\Desktop\Task Planning\TaskPlan
ning\website\Bin\*.*"
[Note: when ERROR: No destination is specified. prompt, use -r as extra parameter.]
 
C:\Program Files\Windows Resource Kits\Tools>compress.exe -r "C:\Documents and Settings\daiw\Desktop\Task Planning\TaskP
lanning\website\Bin\*.*"
 
[Note: no futher steps needed, file.ptr will be created and points to the target file]
 
Example 3 – content of an index file:
"AjaxControlToolkit.dll","AjaxControlToolkit.dll\46673B6C116000","AjaxControlToolkit.dll",bin,,,,
"Autodesk.TaskPlanning.Model.dll","Autodesk.TaskPlanning.Model.dll\47998A37e000","Autodesk.TaskPlanning.Model.dll",bin,,,,
"AntiXssLibrary.dll","AntiXssLibrary.dll\455884108000","AntiXssLibrary.dll",bin,,,,
"Microsoft.ApplicationBlocks.Data.dll","Microsoft.ApplicationBlocks.Data.dll\47998A37c000","Microsoft.ApplicationBlocks.Data.dll",bin,,,,
"AjaxControlToolkit.pdb","AjaxControlToolkit.pdb\59F583B97C5B4A558E78D2206CED42441","AjaxControlToolkit.pdb",pri,,,,
"Autodesk.TaskPlanning.Model.pdb","Autodesk.TaskPlanning.Model.pdb1E6CB4DA2D241139969FC016B8ACB2A1","Autodesk.TaskPlanning.Model.pdb",pri,,,,
"Microsoft.ApplicationBlocks.Data.pdb","Microsoft.ApplicationBlocks.Data.pdb\AC29002C1C6A4D10BD4D831A7ACBDF671","Microsoft.ApplicationBlocks.Data.pdb",pri,,,,
Example 4 – context of history.txt:
[Note: record every transactions perfomed with symstore.exe in CSV-format(known as comma seperated formate)]

0000000001,add,file,03/18/2008,16:27:26,"TaskPlanning","Build 10","For Symbol Store Test",
0000000002,add,file,03/18/2008,16:32:59,"TaskPlanning","Build 10","For Symbol Store Test",
0000000003,del,0000000002
0000000004,del,0000000001
0000000005,add,file,03/18/2008,16:34:08,"TaskPlanning","Build 10","For Symbol Store Test",
0000000006,del,0000000005
0000000007,add,ptr,03/18/2008,16:47:59,"TaskPlanning","Build 12","test",
0000000008,del,0000000007
Example 5 – content of a transaction file:
"Autodesk.TaskPlanning.Model.dll\47998A37e000","C:\Documents and Settings\daiw\Desktop\Task Planning\TaskPlanning\website\Bin\Autodesk.TaskPlanning.Model.dll"
"Microsoft.ApplicationBlocks.Data.dll\47998A37c000","C:\Documents and Settings\daiw\Desktop\Task Planning\TaskPlanning\website\Bin\Microsoft.ApplicationBlocks.Data.dll"
"AjaxControlToolkit.dll\46673B6C116000","C:\Documents and Settings\daiw\Desktop\Task Planning\TaskPlanning\website\Bin\AjaxControlToolkit.dll"
"AntiXssLibrary.dll\455884108000","C:\Documents and Settings\daiw\Desktop\Task Planning\TaskPlanning\website\Bin\AntiXssLibrary.dll"
"AjaxControlToolkit.pdb\59F583B97C5B4A558E78D2206CED42441","C:\Documents and Settings\daiw\Desktop\Task Planning\TaskPlanning\website\Bin\AjaxControlToolkit.pdb"
"Autodesk.TaskPlanning.Model.pdb1E6CB4DA2D241139969FC016B8ACB2A1","C:\Documents and Settings\daiw\Desktop\Task Planning\TaskPlanning\website\Bin\Autodesk.TaskPlanning.Model.pdb"
"Microsoft.ApplicationBlocks.Data.pdb\AC29002C1C6A4D10BD4D831A7ACBDF671","C:\Documents and Settings\daiw\Desktop\Task Planning\TaskPlanning\website\Bin\Microsoft.ApplicationBlocks.Data.pdb"

On-the-job Training

Extract from ‘Message of the week’ by Wesley Miao [A senior manager of Autodesk]. I think it is very useful for those who are still being confused about their future life/carear development. Try to read toward the bottom, though it’s a bit long. Thus, you will gain a lot.

 

It require great skills/knowledge to deliver great results. So it’s quite obvious that we need to develop great skills/knowledge to be able to deliver great results. Today I’ll talk about on-the-job training.

 

When I was interviewed by Henry and Kermit (Sr. Director of Civil3D Development) in JinMao Tower four years ago, I was asked to ask them questions, one of which is “What kind of training I can receive after I join Autodesk?” The answer I got from Kermit was “primarily on-the-job training”. “What a routine answer!” I was thinking at that time. Like many of you, as a fresh graduate, I was expecting the company sending me to US for three month for training, or something like that.

 

After four years, when I look back, I did take a lot official trainings by outside consultants, like C++ training by a MS consultant, Employee Leadership Program, Successful communications, Global Savvy, Project Management in a Chaotic Environment, Interview Skills, Inside-out, and some others I can’t remember.

 

You might say hey Wesley you become what you are today because you had so many trainings before. But I’d say I become what I am today because I’ve been learning hard in every single day in the past four years. I learned when I see how people do things that I never did before and think what if I was doing that. I still remember the first time I wrote a software design document by following a well-written one by a software architect; I still remember the first time I did the presentation for VP after several rounds of dry-runs and all the struggling and being nervous; I still remember the first time I hosted a debriefing session by following a good framework (just a couple of weeks ago); There are so many other “first time” I don’t want to mention here but you get the point.

 

So everyday everybody is receiving on-the-job training. That is, everybody basically has the same opportunities. But you will be surprised how different people would become several years later even they started with almost the same background.

 

What’s key thing here that is making huge difference?

 

The answer is in your every day. It’s true that everybody gets 24 hours a day and 365 days a year. It’s also true some people put more time than others everyday to read more, listen more, think more, learn more, speak more, mimic more, practice more and try more things they never did before. Every day I put a little more extra time than others to learn a little more than others, and I increased my breads of experience a little bit more every day, guess what’s going to happen one year later, what’ll happen 5 years later. You get the point.

 

On my side, one of my jobs is to set up things to drive you to put more time to learn and grow. On your side you need to be ready and willing to.

 

For those of you who are willing to learn and grow *faster* than others, put a little bit more time and effort every day, read more, see more, speak more, practice more, think more, make all every piece of your life and work more *intensive*.

 

Last point, be tenacious. Believe me, several years down the road, you will make a huge difference.

 

Cheers,

Wesley

Global Object Initializers

我们都知道,如果在一个.cpp文件中定义了一系列的全局对象,这些对象的初始化顺序(即,他们的.ctor的调用顺序)是和他们的定义顺序一致的,我们可以很容易的知道哪些对象先被实例化,从而不知不觉的依赖于这种顺序来编码。然而如果是在几个.cpp文件中定义全局对象,此时他们的初始化顺序呢?C++标准并没有对这个顺序作任何声明,只是简单要求全局对象必须在main函数进入之前初始化完毕。那诸如以下代码,我们如何保证他能够被正确执行呢?

Class A { // 不应该写出这样的类型,不尊从C++语义
public:
    A() { cout << "In A’s Constructor…" << endl; }
    ~A() { cout << "In A’s Destructor…" << endl; } };

A aaaa; // 这里定义了一个全局的aaaa对象

我们经常很随意的就写出了这样的一个类型,殊不知cout和aaaa的初始化顺序,会影响代码的正确执行。我们本能的做出这样的假设,为什么cout就先于aaaa被初始化呢?基于这种假设的实现依赖于编译器+连接器,不同的平台实现稍有差异,但是始终大同小异。详见《Inside the C++ Object Model》。

对于VC++的实现方式,是通过两点完成的。CRT Startup Code和预处理指令#pregma:

#pragma init_seg({ compiler | lib | user | "section-name" [, func-name]} )

[In MSDN: Specifies a keyword or code section that affects the order in which startup code is executed. ]

compiler/lib/user/section_name分别定义了初始化顺序的优先级别,compiler为最优先,一般为CRT库保留使用。我们可以在cout所在的.cpp文件中找到#pragma init_seg(compiler)的声明。CRT中的实现呢?

         /* crtexe.c
           * do C++ constructors (initializers) specific to this EXE
           */
           if (__native_startup_state == __initializing)
           {
               _initterm( __xc_a, __xc_z );
               __native_startup_state = __initialized;
           }

在__tmainCRTStartup的定义中可以发现如上的代码,他的工作就是遍历一个函数指针列表,依次进行调用。这些函数指针就指向了那个全局对象的构造函数,当然也有可能是其他的初始化用意的函数。那么这个函数指针列表是如何被构造出来的呢?这就要借助于连接器和编译器了。VC++编译器和CRT有一个约定:当VC++编译器遇到全局对象的初始化器以及内存释放工作(如:构造函数&析构函数),他就会产生一个dynamic initializer,并把他置于.obj文件的.CRT$XCU段中。.CRT是section的名称,$后面的XCU是group名称。(关于COFF或者PE的详细内容,请关注Matt大拿的Columns)。从init_seg的sample code所编译得到的代码中,使用dumpbin /all ctor.obj /out:d:\ctor.txt可以发现这个段中的内容如下:

SECTION HEADER #22
.CRT$XCU name
       0 physical address
       0 virtual address
       4 size of raw data
    21B8 file pointer to raw data (000021B8 to 000021BB)
    21BC file pointer to relocation table
       0 file pointer to line numbers
       1 number of relocations
       0 number of line numbers
40300040 flags
         Initialized Data
         4 byte align
         Read Only

RAW DATA #22
  00000000: 00 00 00 00                                      ….

RELOCATIONS #22
                                                Symbol    Symbol
Offset    Type              Applied To         Index     Name
——–  —————-  —————–  ——–  ——
00000000  DIR32                      00000000        42  ??__Eaaaa@@YAXXZ (void __cdecl `dynamic initializer for ‘aaaa”(void))

这就是一个编译器为aaaa产生的dynamic initializer,??__Eaaaa@@YAXXZ 是被name mangling后的名称(详见calling convention)。

另外编译器还产生了两个section,其中个包含了一个变量用作这个列表的哨兵:

__xc_a in .CRT$XCA
__xc_z in .CRT$XCZ //__xc_a和__xc_z就是刚才CRT Startup Code中传给_initterm的两个参数

OK。当连接器将各个同名的section进行归并,同时按照$后面的group name进行排序。那么将来被windows loader加载进内存后也会依旧保持这个顺序。那么我们的全局对象初始化器的dynamic initializer也会以这个顺序被调用。

_initterm 的汇编代码:

023C010  mov         edi,edi
1023C012  push        ebp 
1023C013  mov         ebp,esp
1023C015  mov         eax,dword ptr [ebp+8]
1023C018  cmp         eax,dword ptr [ebp+0Ch]
1023C01B  jae         __initterm+27h (1023C037h)
1023C01D  mov         ecx,dword ptr [ebp+8]
1023C020  cmp         dword ptr [ecx],0
1023C023  je          __initterm+1Ch (1023C02Ch)
1023C025  mov         edx,dword ptr [ebp+8]
1023C028  mov         eax,dword ptr [edx]
1023C02A  call        eax  // 在这里调用了每个dynamic initializer
1023C02C  mov         ecx,dword ptr [ebp+8]
1023C02F  add         ecx,4
1023C032  mov         dword ptr [ebp+8],ecx
1023C035  jmp         __initterm+5 (1023C015h)
1023C037  pop         ebp 
1023C038  ret             

dynamic initializer:

004146F0  push        ebp 
004146F1  mov         ebp,esp
004146F3  sub         esp,0C0h
004146F9  push        ebx 
004146FA  push        esi 
004146FB  push        edi 
004146FC  lea         edi,[ebp-0C0h]
00414702  mov         ecx,30h
00414707  mov         eax,0CCCCCCCCh
0041470C  rep stos    dword ptr es:[edi]
0041470E  mov         ecx,offset aaaa (419484h)
00414713  call        A::A (4110EBh)  // 真正调用了对象的构造函数
00414718  push        offset `dynamic atexit destructor for ‘aaaa” (415810h)
0041471D  call        @ILT+100(_atexit) (411069h)

00414722  add         esp,4
00414725  pop         edi 
00414726  pop         esi 
00414727  pop         ebx 
00414728  add         esp,0C0h
0041472E  cmp         ebp,esp
00414730  call        @ILT+340(__RTC_CheckEsp) (411159h)
00414735  mov         esp,ebp
00414737  pop         ebp 
00414738  ret 

同时注意以上的_atexit的调用。dynamic initializer为对象aaaa又注册了一个dynamic atexit destructor,用来在程序退出的时候由atexit调用以释放对象的内存。atexit:

int __cdecl atexit ( _PVFV func  ) {
        return (_onexit((_onexit_t)func) == NULL) ? -1 : 0; }

对于MSDN中的那段sample code还有一点需要说明:InitSegStart和InitSegEnd都是在这个哨兵section中的变量,在后面的代码中只是用到了他们的地址。他们就相当于上面的__xc_a和__xc_z

#pragma section(".mine$a", read)
__declspec(allocate(".mine$a")) const PF InitSegStart = (PF)1;

#pragma section(".mine$z",read)
__declspec(allocate(".mine$z")) const PF InitSegEnd = (PF)1;

小节

最近在重构ExUnitTest的代码,同时也在Review代码,发现了不少Singleton使用不当的地方。这些Singleton严重的基于了一定的初始化顺序的约束,所以每次我手工调换FreeInstance的位置时,进程就会Crash。当然这样的问题在任何C++项目中应该都是比较普遍的,在我们的项目中比较好的地方就是这些个类的实例化以及释放都被Facade封装了,我们只需调用expose出来的interface就可以,不用关心这些依赖性。

最后讲个额外的话题,boss要让我做ACRD Team这边的Build Engineer接手Chris Canndy一部分工作,感觉担子有点重,毕竟是把关的position。不过只要做两个月,之后会招一个intern,让intern来接管这个工作。由于最近公司预算的问题,intern的职位需要等到4月以后才能下来。这个position是build engineer & developer,需要较好的development skill,因为我们将来正在考虑实现自动编译部署,所以编程技能不能忽略。有机会看到我这个post的同僚可以发我简历,没看见的哥们就算你可惜了。哈哈~

最近工作中遇到的一些细节问题

以下这些是最近在重构ExUnitTest项目中遇到的一些比较有意思的问题

1. "Explicit" (C++ Key Word),用于构造函数前,以关闭隐式的类型转换

class CDemo {
     int value;
public:
     CDemo(char * p) { }
     //~CDemo() { } // no meanful, extra load will be added, comment out.
     CDemo& operator +(const CDemo &right) {
          //…
          return *this;
     }
     CDemo& operator +(char * p) {
          //…
          return *this;
     }
};
CDemo a; a = a +"3"; // 试问两个+运算符,会调用哪个? 如果加上Explicit又会怎样?有兴趣的人自己写代码去试试。哈哈~~

2. HTTP 405 & 500 Error Code

在测试LibCurl发送的类时,我曾企图写一个ASPX页来接受处理MC3发出的请求,结果先后出现了如上两个Status Code。
  • 405是Resource Not Allowed Error,说明IIS无法处理请求所对应的资源。原因是我设置的URL资源后缀在IIS上没有未映射过(Mapped)。IIS只支持Get可以访问未映射的资源,而Post, Head都不可以。
  • 500是服务器内部错误。原因是MC3发送给ASPX页面的Request中的contenta并不是ASP.NET所能识别的数据,所以ASP.NET在解析的时候就发生错误。解决的方法是使用Generic HttpHandler(.ashx),这样http的请求就都可以在服务器上处理了。

Namidairo

Namidairo
嫌われているような 気がしてた 帰り道
见上げた部屋の灯り 今 どんな気持ちでいるのだろう?

在回家路上察觉到了 其实自己还是很讨厌这样吧
抬头望向房间的灯光 现在的自己怀着一个怎样的心情?

ケンカになればすぐ谢る よわくて アナタハ ズルイヒト

如果演变成吵架的话就马上用微弱的声音道歉吧   你是一个狡猾的人

なみだいろ 声が 闻こえない夜は
困らせてしまうほど わがままになりたい

Namidairo   身处在不能听见声音的晚上
虽然可能会令你觉得困扰 但我也想继续任性下去

だいじょうぶ そう言ってみたけど
そんなはずないでしょ…

虽然已经对你说过「没问题」了
但这样下去也应该没有可能吧…

水たまりに映る 哀しい颜 见惯れている
ムリ 言わないつもり わかってるから 苦しくなるの

水面上映照着的是感到悲伤的脸容   虽然已经看惯了
已经打算不说「没可能」的了 因为自己明白 才会觉得痛苦

优しくされると泣けてくる やっぱり アナタハ ズルイヒト

温柔的对待令我想哭 果然你还是一个狡猾的人

なみだいろ 声が 闻こえない夜は
困らせてしまうほど わがままになりたい

Namidairo   身处在不能听见声音的晚上
虽然可能会令你觉得困扰 但我也想继续任性下去

だいじょうぶ そう言ってみたけど
そんなはずないでしょ…

虽然已经对你说过「没问题」了
但这样下去也应该没有可能吧…

あなたの前じゃ 嘘つきよ
気づいてほしいと 思っているの
そんなに强いわけじゃないからね アタシ

之前也有像你一样爱说谎的人
但我也希望自己能够受到注意
因为我始终也不能变得坚强呢

涙こぼさない 决めていたのに
困らせてしまうよね? わがままになれない

明明决定过不会再让眼泪流下来
但始终会觉得困扰吧? 因为已经不能再任性下去了
                                                
だいじょうぶ? なんてまた讯くけど
そんなはずないでしょ…

像「没问题吧?」之类的短讯应该已经不能再收到了吧
但这样下去也应该没有可能吧…