腾讯MIG实习技术成长日记集

**************************************声明*********************************************************

      原创作品,出自 “晓风残月xj” 博客,欢迎转载,转载时请务必注明出处(http://blog.csdn.net/xiaofengcanyuexj)。

      由于各种原因,可能存在诸多不足,欢迎斧正!

*****************************************************************************************************

    有幸在这样一家国内顶级的互联网公司实习,由于在校期间主要时间都投在ACM上,对于windows编程比较生疏,工作方面职位为PC客户端开发,所以职场导师推荐了基本专业书籍,在完成自己的任务之余,我把时间放在慢慢咀嚼这些经典书籍上。由于相关积累有限,故有些地方怕表达不当,所以以摘抄经典为主。在此说明,由于工作原因,有些技术需要保密,程序代码就不提供了,具体做些什么就不宜多说了。实习很快结束了,在这两个多月里真的很愉快,学到很多在学校学不到的东西,只是马上快开学了,得回学校继续自己的学习生活。由衷的感谢实习期间帮助过我的导师同事们!


6月24日

1.COM即组件对象模型,Component Object Model ,COM是一种跨应用和语言共享二进制代码的方法。与C++不同,它提倡源代码重用。COM与语言、平台无关。

2.COM,是一种说明如何建立可动态互变组件的规范,此规范提供了为保证能够交互操作,客户和组件应遵循的一些二进制和网络标准。通过这种标准将可以在任意两个组件之间进行通信而不用考虑其所处的操作环境是否相同、使用的开发语言是否一致以及是否运行于同一台计算机。

3.HRESULT 其实是一个双字节的值,其最高位(bit)如果是0表示成功,1表示错误。我们在程序中如果需要判断返回值,则可以使用比较运算符号;switch开关语句;也可以使用VC提供的宏:

  HRESULT hr = 调用组件函数; 

 view p

4.COM 组件是运行在分布式环境中的。BSTR 其实是一个指针类型,指向 UNICODE 字符串的指针,且 BSTR 向前的4个字节中,使用DWORD保存着这个字符串的字节长度( 没有含字符串的结束符)。

5.COM组件实际上是一个C++类,而接口都是纯虚类。接口都是纯虚类,所包含的函数都是纯虚函数,而且它没有成员变量。而COM组件就是从这些纯虚类继承下来的派生类,它实现了这些虚函数。COM组件是以C++为基础的,特别重要的是虚函数和多态性的概念,COM中所有函数都是虚函数,都必须通过虚函数表VTable来调用。


6月26日

1.ATL,即ActiveX template library,活动模板库。ATL可以连接MFC,如CString、CRect等类。

2.类向导又称Class Wizard,VC提供了管理类快捷界面和快捷方式使我们能方便管理成员变量、成员函数、消息映射等。

3.分布式应用程序是指:应用程序分布在不同计算机上,通过网络来共同完成一项任务。通常为服务器/客户端模式。人们开始偏爱基于浏览器的客户应用程序。这当然不是因为客户能够提供更好的用户界面,而是因为它能够避免花在桌面应用程序发布上的高成本。发布桌面应用程序成本很高,一半是因为应用程序安装和配置的问题,另一半是因为客户和服务器之间通信的问题。

4.COM实际提供了一组开发组件的方法。组件是功能相对独立的二进制可执行程序,可以提供给其他应用程序使用。COM组件可以看做动态的、面向对象的API。


6月27日

1.OLE,全称Object Linking and Embedding,对象连接与嵌入。OLE 不仅是桌面应用程序集成,而且还定义和实现了一种允许应用程序作为软件“对象”(数据集合和操作数据的函数)彼此进行“连接”的机制,这种连接机制和协议称为组件对象模型(COM)。

2.COM组件必须可以动态链接、隐藏实现细节。

3.COM组件是以Win32动态链接库DLL和可执行文件EXE组成的可执行代码组成的。COM组件与语言无关,是由二进制代码组成。


6月28日

1.类并非COM组件。一个组件可有多个C++类实现,或者根本不用类也可实现组件。

2.COM接口是一个标准的二进制可执行代码,客户同接口的连接并不是按其名称或其成员函数的名称来完成的,而是通过它在内存块中的位置来完成的。

3.一个接口表示的行为越多,适用场所的特定性就越强,可复用性就越小。

4.在C++中接口可通过只含纯虚函数的抽象类表示,而接口的机制可以通过虚指针、虚函数表来理解。

5.COM接口都继承了IUnkown,每个COM接口虚指针vtbl的前3个元素都是指向函数QueryInterface、AddRef、Release的。

6.表示错误有3种方式:消息ID(宏)、消息文本、错误号。当Windows函数运行失败时,应该立即调用GetLastError函数。如果调用另一个Windows函数它的值很可能被改写。注意GetLastError能返回线程产生的最后一个错误。


6月29日

1.将this指针进行类型转换会导致其值的改变,如

   static_cast<IX*>(this)!= static_cast<IY*>(this);

通常将一个类型的指针转换成另一个类型的指针不会导致其值的改变,但为了支持多继承,某些情况下其值会发生改变。

        腾讯MIG实习技术成长日记集_第1张图片

1.组件的实例只有一个IUnkown接口,故查询组件的接口时无论通过哪个接口所得到的均是同一个指针值。

2.COM组件所支持的接口集就是QueryInface能够返回接口指针的接口集。客户了解COM组件的唯一方法就是进行查询。


6月30日

1.AddRef和Release函数实现的是名为引用计数的内存管理技术。引用计数技术室内存管理的一个非常重要的技术。

      腾讯MIG实习技术成长日记集_第2张图片

上面是非线程安全的版本,下面是县城安全的版本,可以保证同一时刻只能有一个线程来来访成员变量。

      腾讯MIG实习技术成长日记集_第3张图片


71

1.关于vector用法应该特别注意vector容器的erase()函数会返回下一个迭代器的地址,这可能会给编程带来问题。在对vector循环删除时,erase(iter)自动返回下一个迭代器的地址,即iter=iter+1,如果是某种条件删除:连续多个都要删除此时若for(;;++iter)就会漏掉一些数,而且若删除的是最后一个数,则iter=end(),此时执行++iter会出错。最好的方法将++iter放在for循环体内。这是vector的内部机制所造成的,所以对vector进行erase的时候特别注意迭代器是否会失效!

for(iter = member.begin();iter != member.end();iter++)
 {
      if(*iter == 2)
      {
         iter = member.erase(iter);//vector中可以直接用member.erase(iter),但map不行
      }
 }
上述代码犯了提到的2个错误,下面代码是对的。
for(iter = member.begin();iter != member.end();) 
{
    if(*iter == 2)
    {
       iter = member.erase(iter);  
    }
    else  iter++;
}


上述规则同样适用于map关联容器。

2.内核对象的数据结构只能被内核访问,应用程序无法在内存中找到这些数据结构并直接改变它们的内容。Microsoft 规定了这个限制条件,目的是为了确保内核对象结构保持状态的一致。这个限制也使Microsoft能够在不破坏任何应用程序的情况下在这些结构中添加、 删除和修改数据成员。当调用一个用于创建内核对象的函数时,该函数就返回一个用于标识该对象的句柄。如果将该句柄值传递给另一个进程中的一个线程,那么这另一个进程使用你的进程的句柄值所作的调用就会失败。如果想在多个进程中共享内核对象,要通过一定的机制。

除了内核对象外,你的应用程序也可以使用其他类型的对象,如菜单、窗口、鼠标光标、刷子和字体等,这些对象属于用户对象或图形设备接口(GDI)对象,而不是内核对象。

3.进程是不活泼的。若要使进程完成某项操作,它必须拥有一个在它的环境中运行的线程,该线程负责执行包含在进程的地址空间中的代码。实际上, 单个进程可能包含若干个线程,所有这些线程都“同时”执行进程地址空间中的代码。为此,每个线程都有它自己的一组CPU 寄存器和它自己的堆 栈。每个进程至少拥有一个线程,来执行进程的地址空间中的代码。如果没有线程来执行进程的地址空间中的代码,那么进程就没有存在的理由了,系统就将自动撤消该进程和它的地址空间。

4.Windows支持两种类型的应用程序。一种是基于图形用户界面(GUI)的应用程序,另一种是基于控制台用户界面(CUI)的应用程序。 基于GUI的应用程序有一个图形前端程序:它能创建窗口,拥有菜单,可以通过对话框与用户打交道,并可使用所有的标准“Windows”组件。 于控制台的应用程序属于文本操作的应用程序。它们通常不能用于创建窗口或处理消息,并且它们不需要图形用户界面。虽然基于CUI的应用程序 包含在屏幕上的窗口中,但是窗口只包含文本。

7月2日

1.一般来说,进程中的线程可以在主计算机中的任何一个CPU上执行,但是一个进程的线程可能被强制在可用CPU的子集上运行,这称为进程的亲缘性.

2.当一个线程调用CreateProcess时,系统就会创建一个进程内核对象,其初始使用计数是1,该进程内核对象不是进程本身,而是操作系统管理进程时使用的一个较小的数据结构,可以将进程内核对象视为由进程的统计信息组成的一个较小的数据结构。然后,系统为新进程创建一个虚拟地址空间,并将可执行文件或任何必要的DLL文件的代码和数据加载到该进程的地址空间中。

3.若要终止进程的运行,可以使用下面四种方法: 

   1.主线程的进入点函数返回(最好使用这个方法)。 

   2.进程中的一个线程调用ExitProcess函数(应该避免使用这种方法)。 

   3.另一个进程中的线程调用TerminateProcess函数(应该避免使用这种方法)。 

   4.进程中的所有线程自行终止运行(这种情况几乎从未发生)。 

4.Windows是个抢占式多线程系统,这意味着新线程和调用CreateThread的线程可以同时执行。

7月3日

1.线程用于描述进程中的运行路径。每当进程被初始化时,系统就要创建一个主线程,该线程与C/C++运行期库的启动代码一道开始运行,启动代码则调用进入点函数(main、wmain、WinMain或wWinMain),并且继续运行直到进入点函数返回并且C/C++运行期库的启动代码调用ExitProcess为止。对于许多应用程序来说,这个主线程是应用程序需要的唯一线程。不过,进程能够创建更多的线程来帮助执行它们的操作。

2.线程函数(实际上是你的所有函数)应该尽可能使用函数参数和局部变量,当使用静态变量和全局变量时,多个线程可以同时访问这些变量,这可能破坏变量的内容。然而,参数和局部变量是在线程堆栈中创建的,因此它们不太可能被另一个线程破坏。

3.volatile是一个类型修饰符(type specifier)。它是被设计用来修饰被不同线程访问和修改的变量。如果没有volatile,基本上会导致这样的结果:要么无法编写多线程程序,要么编译器失去大量优化的机会。

4.stdafx:名称的英文全称为:Standard Application Framework Extensions.所谓头文件预编译,就是把一个工程(Project)中使用的一些MFC标准头文件(如Windows.H、Afxwin.H)预先编译,以后该工程编译时,不再编译这部分头文件,仅仅使用预编译的结果。这样可以加快编译速度,节省时间。

5.

HANDLE CreateThread(
   PSECURITY_ATTRIBUTES psa, //线程句柄的安全属性,默认设置为NULL
   DWORD cbStack,           //设定线程堆栈的地址空间大小,默认设置为0
   PTHREAD_START_ROUTINE pfnStartAddr,//线程函数入口地址
   PVOID pvParam,//传递给线程函数的参数
   DWORD fdwCreate,//设定用于控制创建线程的标志。它可以是两个值中的一个:如果该                           值是0,那么线程创建后可以立即进行调度;如果该值是CREATE_SUSPENDED,系统可以完整地创建线程并对它进行初始化,但是要暂停该线程的运行,这样它就无法进行调度。
   PDWORD pdwThreadID);//设定线程ID,必须是DWORD的一个有效地址

6.终止线程的运行的方法:

• 线程函数返回(最好使用这种方法)。

• 通过调用ExitThread函数,线程将自行撤消(最好不要使用这种方法)。

• 同一个进程或另一个进程中的线程调用TerminateThread函数(应该避免使用这种方法)。

• 包含线程的进程终止运行(应该避免使用这种方法)。



7月4日

1.模型(model,应用程序对象)、视图(view,向用户显示)、控制器(controller,用户控件)。

2.调用Sleep,可使线程自愿放弃它剩余的时间片.系统将在大约的指定毫秒数内使线程不可调度。不错,如果告诉系统,想睡眠100ms,那么可以睡眠大约这么长时间,但是也可能睡眠数秒钟或者数分钟。记住,windows不是个实时操作系统。虽然线程可能在规定的时间被唤醒,但是它能否做到,取决于系统中还有什么操作正在进行。


7月5日

1.系统提供了一个称为SwitchToThread的函数,使得另一个可调度线程(如果存在能够运行):BOOL SwitchToThread();当调用这个函数的时候,系统要查看是否存在一个迫切需要CPU时间的线程。如果没有线程迫切需要CPU时间,SwitchToThread就会立即返回;如果存在一个迫切需要CPU时间的线程,SwitchToThread就对该线程进行调度(该线程的优先级可能低于调用SwitchToThread的线程)。这个迫切需要CPU时间的线程可以运行一个时间段,然后系统调度程序照常运行。

2.BOOL GetThreadTimes(HANDLE hThread,PFILETIME pftCreationTime, PFILETIME pftExitTime,PFILETIME pftKernelTime, PFILETIME pftUserTime);GetThreadTimes函数返回4个不同的时间值,这些值如表7 - 1所示。

时间值     含义 

创建时间   用英国格林威治时间1601年1月1日午夜后100ns的时间间隔表示的英国绝对值,用于指明线程创建的时间 

退出时间   用英国格林威治时间1601年1月1日午夜后100ns的时间间隔表示的英国绝对值,用于指明线程退出的时间。如果线程仍然在运行,退出时间则未定义 

内核时间   一个相对值,用于指明线程执行操作系统代码已经经过了多少个100ns的CPU时间 

用户时间   一个相对值,用于指明线程执行应用程序代码已经经过了多少个100ns的CPU时间 

调用2次,获取时间差,对应相减即可。

3.线程同步问题在很大程度上与原子访问有关,所谓原子访问,是指线程在访问资源时能够确保所有其他线程都不在同一时间内访问相同的资源。


7月6日

1.高速缓存行存储块中的和高速缓存行边界上的应用程序数据组合在一起。这样做的目的是确保不同的CPU能够访问至少由高速缓存行边界分开的不同的内存地址。还有,应该将只读数据与读写数据分开。同时,应该将同一时间访问的数据组合在一起。

2.指定一个CRITICAL_SECTION数据结构g_cs,然后在对EnterCriticalSection和LeaveCriticalSection函数调用中封装要接触共享资源的任何代码。注意,在对EnterCriticalSection和LeaveCriticalSection的所有调用中,传递的是g_cs的地址。

3.当无法用互锁函数来解决同步问题时,你应该试用关键代码段。关键代码段的优点在于它们的使用非常容易,它们在内部使用互锁函数,这样它们就能够迅速运行。关键代码的主要缺点是无法用它们对多个进程中的各个线程进行同步。

4.该函数必须在任何线程调用EnterCriticalSection函数之前被调用,如果一个线程试图进入一个未初始化的CRTICAL_SECTION,那么结果将是很难预计的。

5.为了提高关键代码段的运行性能,Microsoft将循环锁纳入了这些代码段。因此,当EnterCritialSection函数被调用时,它就使用循环锁进行循环,以便设法多次取得该资源。只有当为了取得该资源的每次试图都失败时,该线程才转入内核方式,以便进入等待状态。

BOOL InitializeCriticalSectionAndSpinCount(  PCRITICAL_SECTION pcs, DWORD dwSpinCount);

与InitialieCriticalSection中的情况一样,InitializeCriticalSectionAndSpinCount的第一个参数是关键代码段结构的地址。但是在第二个参数dwSpinCount中,传递的是在使线程等待之前它试图获得资源时想要循环锁循环迭代的次数。

6.解决解决死锁,必须始终按照完全相同的关键代码段顺序请求对资源的访问。

DWORD WINAPI ThreadFunc(PVOID pvParam)
{
   EnterCriticalSection(&g_csNums);
   EnterCriticalSection(&g_csChars);

   //This loop requires simultaneous access to both resources.
   for(int x = 0; x < 100; x++)
      g_nNums[x] = g_cChars[x];

   LeaveCriticalSection(&g_csChars);
   LeaveCriticalSection(&g_csNums);
   return(0);
}

假定下面这个函数的进程中的另一个线程也要求访问这两个数组:x下面代码是存在死锁的危险的。

DWORD WINAPI OtherThreadFunc(PVOID pvParam) 
{
   EnterCriticalSection(&g_csChars);
   EnterCriticalSection(&g_csNums);

   for(int x = 0; x < 100; x++)
      g_nNums[x] = g_cChars[x];

   LeaveCriticalSection(&g_csNums);
   LeaveCriticalSection(&g_csChars);
   return(0);
}

假定ThreadFunc开始执行,并且获得了g_csNums关键代码段的所有权,那么执行OtherThreadFunc函数的线程就被赋予一定的CPU时间,并可获得g_csChars关键代码段的所有权。这时就出现了一个死锁状态。当ThreadFunc或OtherThreadFunc中的任何一个函数试图继续执行时,这两个函数都无法取得对它需要的另一个关键代码段的所有权。

7.当一个关键代码段长时间运行时,其他线程就会进入等待状态,这会降低应用程序的运行性能,故尽可能不要长时间运行关键代码段。


7月8日

1.TCHAR类型   C++支持两种字符串,即常规的ANSI编码(使用""包裹)和Unicode编码(使用L""包裹),这样对应的就有了两套字符串处理函数,比如:strlen和wcslen,分别用于处理两种字符串。微软将这两套字符集及其操作进行了统一,通过条件编译(通过_UNICODE和UNICODE宏)控制实际使用的字符集,这样就有了_T("")这样的字符串,对应的就有了_tcslen这样的函数。为了存储这样的通用字符,就有了TCHAR:    当没有定义_UNICODE宏时,TCHAR = char,_tcslen =strlen    当定义了_UNICODE宏时,TCHAR = wchar_t , _tcslen = wcslen[1] 当我们定义了UNICODE宏,就相当于告诉了编译器:我准备采用UNICODE版本。这个时候,TCHAR就会摇身一变,变成了wchar_t。而未定义UNICODE宏时,TCHAR摇身一变,变成了unsigned char。这样就可以很好的切换宽窄字符集。7月10日1.有时需要控件在排除任务栏的窗口内显示,此时只需调用 

RECT winRc;
   SystemParametersInfo(SPI_GETWORKAREA,0,(PVOID)&winRc,0);

得到的winRc即除去了任务栏,注意此时不随任务栏位置变化而变化。

7月12日

1.MFC中CString和STL中string的互换

(1)string转CString
CString strMfc;
std::string strStl=“test“;
strMfc=strStl.c_str();
(2)CString转string
CString strMFC;
string strSTL;
strSTL = CStringA(strMFC);

2.用户方式的线程同步机制具有速度快的优点,但对于许多应用程序来说,这种机制是不适用的。例如,互锁函数家族只能在单值上运行,根本无法使线程进入等待状态。可以使用关键代码段使线程进入等待状态,但是只能用这些代码段对单个进程中的线程实施同步。还有,使用关键代码段时,很容易陷入死锁状态,因为在等待进入关键代码段时无法设定超时值。
内核对象机制的适应性远远优于用户方式机制,实际上,内核对象机制的唯一不足之处是它的速度比较慢。

3.当进程正在运行的时候,进程内核对象处于未通知状态;当进程终止运行的时候,它就变为已通知状态。进程内核对象中是个布尔值,当对象创建时,该值被初始化为FALSE(未通知状态);当进程终止运行时,操作系统自动将对应的对象布尔值改为TRUE,表示该对象已经得到通知。

4.等待函数可使线程自愿进入等待状态,直到一个特定的内核对象变为已通知状态为止。这些等待函数中最常用的是WaitForSingleObject:DWORD WaitForSingleObject(HANDLE hObject,   DWORD dwMilliseconds);当线程调用该函数时,第一个参数hObject标识一个能够支持被通知/未通知的内核对象;第二个参数dwMilliseconds允许该线程指明,为了等待该对象变为已通知状态,它将等待多长时间。

5.原子操作是指不会被线程调度机制打断的操作。这种操作一旦开始,就一直运行到结束,中间不会被打断。



7月13日

1.C++中也有内部类和外部类之分,即在类中嵌套定义另外一个类。不同于Java的是不能通过内部类直接获得外部类的指针。

2.在所有的内核对象中,事件内核对象是个最基本的对象。它们包含一个使用计数,一个用于指明该事件是个自动重置的事件还是一个人工重置的事件的布尔值;另一个用于指明该事件处于已通知状态还是未通知状态的布尔值。

3.

HANDLE CreateEvent(
   PSECURITY_ATTRIBUTES psa,
   BOOL fManualReset,
   BOOL fInitialState,
   PCTSTR pszName);

其中,FMannualReset参数是个布尔值,它能够告诉系统是创建一个人工重置的事件(TRUE)还是创建一个自动重置的事件(FALSE)。fInitialState参数用于指明该事件是要初始化为已通知状态(TRUE)还是未通知状态(FALSE)。当系统创建事件对象后,createEvent就将与进程相关的句柄返回给事件对象。

// Create a global handle to a manual-reset, nonsignaled event.
HANDLE g_hEvent;

int WINAPI WinMain(...) 
{
   //Create the manual-reset, nonsignaled event.
   g_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

   //Spawn 3 new threads.
   HANDLE hThread[3];
   DWORD dwThreadID;
   hThread[0] = _beginthreadex(NULL, 0, WordCount, NULL, 0, &dwThreadID);
   hThread[1] = _beginthreadex(NULL, 0, SpellCheck, NULL, 0, &dwThreadID);
   hThread[2] = _beginthreadex(NULL, 0, GrammarCheck, NULL, 0, &dwThreadID);

   OpenFileAndReadContentsIntoMemory(...);

   //Allow all 3 threads to access the memory.
   SetEvent(g_hEvent);
   ...
}

DWORD WINAPI WordCount(PVOID pvParam)
{
   //Wait until the file's data is in memory.
   WaitForSingleObject(g_hEvent, INFINITE);

   //Access the memory block.
   ...
   return(0);
}

DWORD WINAPI SpellCheck(PVOID pvParam)
{
   //Wait until the file's data is in memory.
   WaitForSingleObject(g_hEvent, INFINITE);

   //Access the memory block.
   ...
   return(0);
}

DWORD WINAPI GrammarCheck(PVOID pvParam)
{
   //Wait until the file's data is in memory.
   WaitForSingleObject(g_hEvent, INFINITE);

   //Access the memory block.
   ...
   return(0);
}

4.等待定时器是在某个时间或按规定的间隔时间发出自己的信号通知的内核对象。若要创建等待定时器,只需要调用CreateWaitableTimer函数。


7月14日

1.在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源。web服务器、数据库服务器、文件服务器和邮件服务器等服务器应用要面向处理远程服务请求。服务器应用程序的简单模型是:每当一个请求到达就创建一个新的服务对象,然后在新的服务对象中完成请求服务。但当有大量请求并发访问时,服务器不断的创建和销毁对象的开销很大。所以提高服务器效率的一个手段就是尽可能减少创建和销毁对象,这样就引入了“池”的概念,“池”的概念使得人们可以定制一定量的资源,然后对这些资源进行复用,而不是频繁的创建和销毁。线程池是预先创建线程,属于预处理技术。线程池在没有任务到来之前,创建一定数量的线程,放入空闲队列中。这些线程都是处于睡眠状态,不消耗CPU,而只是占用较小的内存空间。当请求到来之后,缓冲池给这次请求分配一个空闲线程,把请求传入此线程中进行处理。2.函数调用约定,是指当一个函数被调用时,函数的参数会被传递给被调用的函数和返回值会被返回给调用函数。函数的调用约定就是描述参数是怎么传递和由谁平衡堆栈的,当然还有返回值。参数传递顺序

1).从右到左依次入栈:__stdcall,__cdecl,__thiscall,__fastcall
2).从左到右依次入栈:__pascal
调用堆栈清理
1).调用者清除栈。
2).被调用函数返回后清除栈。
3.int memcmp(const void *buf1, const void *buf2, unsigned int count);
比较内存区域buf1和buf2的前count个字节。
#include<string.h>
#include<stdio.h>
main()
{
	char*s1="Hello,Programmers!";
	char*s2="Hello,Programmfrs!";
	int r;
	r=memcmp(s1,s2,strlen(s1));
	if(!r)
		printf("s1 and s2 are identical\n");/*s1??s2*/
	else if(r<0)
		printf("s1 is less than s2\n");/*s1??s2*/
	else
		printf("s1 is greater than s2\n");/*s1??s2*/
	return 0;
}


7月15日
1.获取文件绝对路径时应该注意‘\’是转移字符,所以应该打‘\\’,如下:
”C:\Program Files (x86)\Tencent\QQWifi\QQWifi.exe"打开会失败应该改成
"C:\\Program Files (x86)\\Tencent\\QQWifi\\QQWifi.exe“
2.GetModuleFileName获取当前进程已加载模块的文件的完整路径,该模块必须由当前进程加载。
GetModuleFileNameEx如果想要获取另一个已加载模块的文件路径。




7月16日
1.Debug通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。Release称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。
Debug和Release区别 
http://www.cnblogs.com/JemBai/archive/2009/01/13/1374805.html
2.debug是将每个字节位都赋成0xcc, 而release的赋值近似于随机。
3.句柄,是整个Windows编程的基础。一个句柄是指使用的一个唯一的整数值,即一个4字节(64位程序中为8字节)长的数值,来标识应用程序中的不同对象和同类对象中的不同的实例,诸如,一个窗口,按钮,图标,滚动条,输出设备,控件或者文件等。应用程序能够通过句柄访问相应的对象的信息,但是句柄不是一个指针,程序不能利用句柄来直接阅读文件中的信息。
4.数据对象加载进入内存中之后被分配地址,但是这个地址并不是固定的,数据对象会根据需要在内存与硬盘之间游弋移动,如不常用的数据会为常用数据让出其占用的内存空间进而被淘汰进硬盘中的虚拟内存之中以优化配置整体系统的资源进而提升效率性能,因此其物理地址总是变动的,那么作为管理者 则必须对 管理对象所发生的变化了如指掌才行,因此系统为进程分配固定的地址(句柄)来存储进程下的数据对象变化后的地址也就是当前的地址,其实设计机制很简单 :系统的某个部门移动了对象的地址后,同时上报给句柄所属部门管理者,管理者将改动写入句柄即可。该数据被重新起用时去其所属句柄内按内容存取即可。,Windows是一个以虚拟内存为基础的操作系统,Windows内存管理器经常在内存中来回移动对象,以此来满足各种应用程序的内存需要。
5.::是运算符中等级最高的,它分为三种:全局作用域符,类作用域符,命名空间作用域符。全局作用域符号,当全局变量在局部函数中与其中某个变量重名,那么就可以用::来标志全局作用域。



7月19日
1.OnSysCommand()这个函数主要是截获控制命令的,msdn上的解释如下:The framework calls this member function when the user selects a command from the Control menu, or when the user selects the Maximize or the Minimize button。尤其是最大化和最小化窗口的时候,比如现在软件流行的点关闭按钮,不是退出而是隐藏的情况,就可以在这里来实现.
2.SetMsgHandled(false)让消息通过CHAIN_MSG_MAP宏链入基类,这个调用代替了 ATL宏使用的bHandled参数。
SetMsgHandled (false)让消息流入基类是个好的习惯,因为这样我们就不必总是记着哪个消息需要基类处理那些消息不需要基类处理,这和VC的类向导产生的代码相似,多数的派生类的消息处理函数的开始或结尾都会调用基类的消息处理函数。
SetMsgHandled(TRUE)让消息不流入基类进行处理。
PathRemoveFileSpec函数的作用是将路径末尾的文件名和反斜杠去掉。

7月21日

1.Windows系统提供一个称为“新增与移除程序”的共享接口,内有大多数已安装软件的列表。通常安装程序都会在安装的同时将自己与自己的移除程序列表于其中.
2.自解压文件的原理是把压缩数据存放到exe中,当需要解压时,直接执行exe文件,就能把文件解压到制定的位置。那么如何将数据放到exe中是一个首先需要解决的问题,需要解决的第二个问题是exe文件如何实现自解压。
3.main是C/C++的标准入口函数名。
WinMain是windows API窗体程序的入口函数。(int WINAPI WinMain()) 中 WINAPI是__stdcall宏,在windef.h中定义的。
_tmain _tWinMain 是Unicode版本函数别名,对应与wmain和wWinMain。

#ifdef _UNICODE
#define _tmain      wmain
#define _tWinMain   wWinMain
#else
#define _tmain      main
#define _tWinMain   WinMain
#endif
这样定义是为了自动适应是否定义了UNICODE,其中wmain和wWinMain是支持UNICODE字符的。前缀为"_t"的应用与UNICODE的函数,工程中最好用这类函数。
4.7z 是一种主流高效的压缩格式,它拥有极高的压缩比,在计算机科学中,7z是一种可以使用多种压缩算法进行数据压缩的档案格式。


7月22日
1.安装包(Install pack),即软件安装包,是可自行解压缩文件的集合,其中包括软件安装的所有文件。运行这个安装包(可执行文件),可以将此软件的所有文件释放到硬盘上,完成修改注册表、修改系统设置、创建快捷方式等工作。安装包文件多为exe格式。
2.ProgramData属于电脑C盘的一个系统文件夹,它是公用的被创建文件夹或文件存放的地方,这些文件夹或文件仅由创建者完整控制。专家建议不要删除,隐藏即可!


7月24日
1.软件的安装程序就是一个Windows可识别的压缩包,安装时自动解压并且向注册表写入软件注册信息和许可信息。
2.int CompareNoCase( LPCTSTR lpsz ) const; 这个函数使用lstrcmpi函数对一个CString和另一个CString进行比较。由参数lpsz指定这个用于比较的string。如果两个对象完全一致则返回0,如果小于lpsz,则返回-1,否则返回1.比如,利用CompareNoCase比较str与lpsz,等同于区分大小写比较str与lpsz的第一个相异字符,如果str该处的字符比lpsz大,则字符串str大于lpsz,返回1;如果str该处的字符比lpsz小,则字符串str小于lpsz,返回-1;str与lpsz内容完全一致则返回0。
3.FindFirstFile:根据文件名查找文件。该函数到一个文件夹(包括子文件夹)去搜索指定文件 如果要使用附加属性去搜索文件的话 可以使用FindFirstFileEx函数。


7月26日
1.互斥对象(mutex)内核对象能够确保线程拥有对单个资源的互斥访问权。互斥对象的行为特性与关键代码段相同,但是互斥对象属于内核对象,而关键代码段则属于用户方式对象。这意味着互斥对象的运行速度比关键代码段要慢。互
2.斥对象包含一个使用数量,一个线程I D和一个递归计数器。ID用于标识系统中的哪个线程当前拥有互斥对象,递归计数器用于指明该线程拥有互斥对象的次数。

1).若要使用互斥对象,必须有一个进程首先调用CreateMutex,以便创建互斥对象:
HANDLE CreateMutex(
   PSECURITY_ATTRIBUTES psa,
   BOOL fInitialOwner,
   PCTSTR pszName);

2).通过调用OpenMutex,另一个进程可以获得它自己进程与现有互斥对象相关的句柄:
HANDLE OpenMutex(
   DWORD fdwAccess,
   BOOL bInheritHandle,
   PCTSTR pszName);

3).当目前拥有对资源的访问权的线程不再需要它的访问权时,它必须调用ReleaseMutex函数来释放该互斥对象:
BOOL ReleaseMutex(HANDLE hMutex);



7月28日
1.指定路径创建文件夹

void PathRemoveFileSpec(CString& strPath)
{
	int nPos = strPath.ReverseFind(_T('\\'));
	if (nPos == -1)
	{
		strPath.Empty();
	}
	else
	{
		strPath = strPath.Left(nPos);
	}
}

BOOL CreateDeepDirectory(LPCTSTR szPath)
{
	BOOL bRetCode = FALSE;
	CString strPath(szPath);	
	if (GetFileAttributes(szPath) != INVALID_FILE_ATTRIBUTES)
		return TRUE;	
	bRetCode = CreateDirectory(szPath, NULL);
	if (!bRetCode && GetLastError() != ERROR_ALREADY_EXISTS)
	{
		PathRemoveFileSpec(strPath);
		if (strPath.IsEmpty()) return FALSE;
		bRetCode = CreateDeepDirectory(strPath);
		if (!bRetCode) return FALSE;
		bRetCode = CreateDirectory(szPath, NULL);
		if (!bRetCode && GetLastError() != ERROR_ALREADY_EXISTS)
			return FALSE;
	}
	return TRUE;
}

2.注册表是Windows操作系统中的一个核心数据库,其中存放着各种参数,直接控制着Windows的启动、硬件驱动程序的装载以及一些Windows应用程序的运行,从而在整个系统中起着核心作用。这些作用包括了软、硬件的相关配置和状态信息,比如注册表中保存有应用程序和资源管理器外壳的初始条件、首选项和卸载数据等,联网计算机的整个系统的设置和各种许可,文件扩展名与应用程序的关联,硬件部件的描述、状态和属性,性能记录和其他底层的系统状态信息,以及其他数据等。



7月29号
1、脚本(script)是使用一种特定的描述性语言,依据一定的格式编写的可执行文件,又称作宏或批处理文件。
2、批处理,即批量处理。批处理文件是扩展名为·bat 或·cmd的文本文件,包含一条或多条命令,由DOS或Windows系统内嵌的命令解释器来解释运行。批处理的本质,是一堆DOS命令按一定顺序排列而形成的集合。
3、脚本简单地说就是一条条的文字命令,这些文字命令是可以看到的(如可以用记事本打开查看、编辑),脚本程序在执行时,是由系统的一个解释器,将其一条条的翻译成机器可识别的指令,并按程序顺序执行。因为脚本在执行时多了一道翻译的过程,所以它比二进制程序执行效率要稍低一些。



8月1号
1、金山界面库不使用Windows的窗口布局,只是使用Windows的窗口作为一个载体,整个窗口都只是作为一个绘制面,而Kui对窗口实行重新布局,取消了原窗口非客户区和客户区的概念.而自己对窗口划分为上中下三个部分.
(1)、上部分为Header,一般作为窗口标题栏,可以放置缩小,最大化,关闭按钮;
(2)、中部分为Body,是窗口主要功能操作区域;
(3)、下部分为Footer,一般作为状态显示。
2、Kui将使用到的诸如图片,布局定义xml等文件使用zip打包。



8月2日
1、消息处理机制

ON_MESSAGE是MFC中定义的用于将自定义消息和消息处理函数关联起来的宏。如:
#define WM_MYMESSAGE (WM_USER + 1)
BEGIN_MESSAGE_MAP( CMyWnd, CMyParentWndClass )
    ON_MESSAGE( WM_MYMESSAGE, OnMyMessage )
END_MESSAGE_MAP( )
MESSAGE_HANDLER是ATL中定义的用于将消息和消息处理函数关联起来的宏。如:
BEGIN_MSG_MAP(CMyClass)
   MESSAGE_HANDLER(WM_PAINT, OnPaint)
END_MSG_MAP()
两者分属于不同的开发框架,不能同时使用:MESSAGE_HANDLER属于ATL,ON_MESSAGE属于MFC。


8月3日

1、对话框支持文件拖拽
第一步、需要添加消息响应WM_DROPFILES
1)、如果是MFC,操作如下:对话框上点击右键,选择Properties->Extended Styles,点选Accept files选项即可。
2)、如果不是MFC,如ATL、Win32、金山卫士开源代码等,操作如下:

LONG dwLong = GetWindowLong(GWL_EXSTYLE);
SetWindowLong(GWL_EXSTYLE, dwLong|WS_EX_ACCEPTFILES);
第二步、文件拖拽消息响应函数

void CMainDlg::OnDropFiles(HDROP hDropInfo) 
{ 

	UINT count;     
	TCHAR strFilePath[MAX_PATH + 1]   ;   
	count = DragQueryFile(hDropInfo, 0xFFFFFFFF, NULL, 0);           
	if(count)            
	{ 
		for(UINT i=0; i<count; i++) 
                //支持多个文件的拖拽操作                    
		{ 
		    int pathLen = DragQueryFile(hDropInfo, i, strFilePath, sizeof(strFilePath)); 
                   //strFilePath存储的是当前文件的完整路径+文件名
                   //此处可以添加待处理的操作,完成应用程序的功能
		} 
	} 
	DragFinish(hDropInfo);  
        //CDialog::OnDropFiles(hDropInfo);//如果是MFC,最好添加此操作
} 


8月4日
1、防火墙(Firewall),允许或限制传输的数据通过的信息安全防护系统,是一个由软件和硬件设备组合而成、在内部网和外部网之间、专用网与公共网之间的界面上构造的保护屏障.是一种获取安全性方法的形象说法。



8月5日
1、若服务器采用线程池技术,当服务器进程的主线程收到客户机的请求时,可以调用下面这个函数

BOOL QueueUserWorkItem(
   PTHREAD_START_ROUTINE pfnCallback,
   PVOID pvContext,
   ULONG dwFlags);
该函数将收到的一个客户机的请求放入线程池队列中的一个线程中,然后立即返回。pfnCallback函数,它被调用并传递单个参数pvContext。线程池中的某个线程将处理该客户机的请求,即调用pfnCallback函数。所编的回调函数必须采用下面的原型:
DWORD WINAPI WorkItemFunc(PVOID pvContext);
此时,你不必自己调用CreateThread函数创建新线程。系统会自动为该进程创建一个线程池,线程池中的一个线程将调用该函数。另外,当该线程处理完客户机的请求之后,该线程不立即被撤消,而是返回线程池,这样就可以准备处理已经排队的其他客户机的请求。这样,应用程序的运行效率可能会变得更高,因为不必为每个客户机请求创建和撤消线程。另外,由于线程与完成端口相关联,所以可以同时运行的线程数量限制为CPU数量的两倍。
2、映像文件是将资料和程序结合而成的文件.

3、

         腾讯MIG实习技术成长日记集_第4张图片



86

1、

            腾讯MIG实习技术成长日记集_第5张图片

     为什么堆栈区域的最后一个页面始终被保留着?这样做的目的是为了防止不小心改写进程使用的其他数据。在0x07FF000这个地址上(0x08000000下面的一个页面),另一个地址空间区域已经提交了物理存储器。如果0x08000000地址上的页面包含物理存储器,系统将无法抓住线程访问已保留堆栈区域的尝试。如果堆栈深入到已保留堆栈区域的下面,那么线程中的代码就会改写进程的地址空间中的其他数据,这是个非常难以抓住的错误。




8月7日
1、dll,全称是Dynamic Link Libaray,即动态链接库,将程序运行所需要的类或方法的实现放在dll中,这样当可执行文件(即.exe文件)需要使用相关的类、方法时从dll中动态地获取,节省了可执行文件在编译时花费的时间。
2、静态库和动态库是两种共享程序代码的方式,静态库在程序的链接阶段被复制到程序中,和程序运行的时候没有关系;动态库在链接阶段没有被复制到程序中,而是程序在运行时由系统动态加载到内存中供程序调用。静态库特点是可执行文件中包含了库代码的一份完整拷贝,缺点就是被多次使用就会有多份冗余拷贝;动态库的优点是系统只需载入一次动态库,不同的程序可以得到内存中相同的动态库的副本,因此节省了很多内存。
3、云计算是基于互联网的计算,按需把共享的计算资源、网络资源、存储资源提供给用户。



8月8日
1、文件的全部属性信息。总计有以下9种属性信息:文件的标题名、文件的属性(只读、存档,隐藏等)、文件的创建时间、文件的最后访问时间、文件的最后修改时间、文件大小的高位双字、文件大小的低位双字、保留、保留。

typedef struct _WIN32_FIND_DATA {
DWORD dwFileAttributes; //文件属性
FILETIME ftCreationTime; // 文件创建时间
FILETIME ftLastAccessTime; // 文件最后一次访问时间
FILETIME ftLastWriteTime; // 文件最后一次修改时间
DWORD nFileSizeHigh; // 文件长度高位
DWORD nFileSizeLow; // 文件长度低位
DWORD dwReserved0; // 系统保留
DWORD dwReserved1; // 系统保留
TCHAR cFileName[ MAX_PATH ]; // 长文件名
TCHAR cAlternateFileName[ 14 ]; // 8.3格式文件名
} WIN32_FIND_DATA, *PWIN32_FIND_DATA;
可以通过FindFirstFile()函数根据当前的文件存放路径查找该文件来把待操作文件的相关属性读取到WIN32_FIND_DATA结构中去:
WIN32_FIND_DATA ffd ;
HANDLE hFind = FindFirstFile("c:\\test.dat",&ffd);
     在使用这个结构时不能手工修改这个结构中的任何数据,结构对于开发人员来说只能作为一个只读数据,其所有的成员变量都会由系统完成填写。
2、文件对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展标志语言的标准编程接口,以一种独立于平台和语言的方式访问和修改一个文档的内容和结构。 通过 JavaScript,您可以重构整个HTML文档。您可以添加、移除、改变或重排页面上的项目。要改变页面的某个东西,JavaScript就需要对HTML文档中所有元素进行访问的入口。这个入口,连同对HTML 元素进行添加、移动、改变或移除的方法和属性,都是通过文档对象模型来获得的(DOM)。



8月9日
1、PE(Portable Executable)格式,是微软Win32环境可移植可执行文件(如exe、dll、vxd、sys和vdm等)的标准文件格式。
PE文件的第一个部分是IMAGE_DOS_HEADER,大小为64B,这里面有两个重要的数据成员。第一个为e_magic,这个必须为MZ,即0x5A4D。当然,0x5A4D这是典型的小端格式(Little Endian);另一个重要的数据成员是最后一个成员e_lfanew,这个成员的值为IMAGE_NT_HEADERS的偏移,即可以算出PE文件的头。
IMAGE_DOS_HEADER的定义如下:
typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // Magic number
    WORD   e_cblp;                      // Bytes on last page of file
    WORD   e_cp;                        // Pages in file
    WORD   e_crlc;                      // Relocations
    WORD   e_cparhdr;                   // Size of header in paragraphs
    WORD   e_minalloc;                  // Minimum extra paragraphs needed
    WORD   e_maxalloc;                  // Maximum extra paragraphs needed
    WORD   e_ss;                        // Initial (relative) SS value
    WORD   e_sp;                        // Initial SP value
    WORD   e_csum;                      // Checksum
    WORD   e_ip;                        // Initial IP value
    WORD   e_cs;                        // Initial (relative) CS value
    WORD   e_lfarlc;                    // File address of relocation table
    WORD   e_ovno;                      // Overlay number
    WORD   e_res[4];                    // Reserved words
    WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
    WORD   e_oeminfo;                   // OEM information; e_oemid specific
    WORD   e_res2[10];                  // Reserved words
    LONG   e_lfanew;                    // File address of new exe header
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;


8月10日
1、云计算已经从根本上改变了人类对计算机资源的定义,它可以像电能和水一样被看作是一种资源,因需提取。在集中式部署的过程中,虚拟化作为一种整合技术,然而,虚拟化的环境会暴露更大受攻击面,云安全问题不可避免。以强大服务器功能作为“核心”,弱化客户端作为“边缘”的云计算技术,可以理解成是一种倒退到主机模式的计算。



8月12日

1、人工智能过去是基于某些预设规则的快速搜索和推理,离真正的智能还有相当的距离,或者说距离创造像人类一样具有抽象学习能力的机器还很遥远。

2、

    1)、欧几里德距离(Euclidean Distance):最初用于计算欧几里德空间中两个点的距离,假设 x,y 是 n 维空间的两个点,它们之间的欧几里德距离是:

                        

   2)、余弦相似度(Cosine-based Similarity):两个项目 i ,j 视作为两个m维用户空间向量,相似度计算通过计算两个向量的余弦夹角,那么,对于m*n的评分矩阵,i ,j 的相似度sim( i , j ) 计算公式:

                          

   3)、皮尔逊相关系数一般用于计算两个定距变量间联系的紧密程度,为了使计算结果精确,需要找出共同评分的用户。记用户集U为既评论了 i 又评论了 j 的用户集,那么对应的皮尔森:

                        



8月13日
1、根据调用方式的不同,对动态库的调用可分为静态调用方式和动态调用方式。 
(1)静态调用,也称为隐式调用,由编译系统完成对DLL的加载和应用程序结束时DLL卸载的编码(Windows系统负责对DLL调用次数 的计数),调用方式简单,能够满足通常的要求。通常采用的调用方式是把产生动态连接库时产生的.LIB文件加入到应用程序的工程中,想使用DLL中的函数 时,只须在源文件中声明一下。 LIB文件包含了每一个DLL导出函数的符号名和可选择的标识号以及DLL文件名,不含有实际的代码。Lib文件包含的信息进入到生成的应用程序中,被调 用的DLL文件会在应用程序加载时同时加载在到内存中。 
(2)动态调用,即显式调用方式,是由编程者用API函数加载和卸载DLL来达到调用DLL的目的,比较复杂,但能更加有效地使用内存,是编制大型应用程序时的重要方式。在Windows系统中,与动态库调用有关的函数包括: 
①LoadLibrary(或MFC 的AfxLoadLibrary),装载动态库。 
②GetProcAddress,获取要引入的函数,将符号名或标识号转换为DLL内部地址。 
③FreeLibrary(或MFC的AfxFreeLibrary),释放动态链接库。 
2、magic number:幻数,看局部代码无法判断其含义,必须要去上下文中找,才能发现其具体意义,一般指没有相关命名的数。消除魔术数的方法主要是将这些数字定义为常量,或者枚举类型,或者使用编译器的宏定义。
3、类实例不能使用memset初始化,同样如果结构体里面包含类也不行。因为每个包含虚函数的类对象都有一个指针指向虚函数表(vtbl)。这个指针被用于解决运行时以及动态类型强制转换时虚函数的调用问题。该指针是被隐藏的,对程序员来说,这个指针也是不可存取的。当进行memset操作时,这个指针的值也要被overwrite,这样一来,只要一调用虚函数,程序便崩溃。这在很多由C转向C++的程序员来说,很容易犯这个错误,而且这个错误很难查。为了避免这种情况,记住对于有虚拟函数的类对象,决不能使用 memset 来进行初始化操作。而是要用缺省的构造函数或其它的 init 例程来初始化成员变量。

#include <iostream>
using namespace std;

class GraphicsObject
{
public:
	virtual void Draw() {}
	virtual int Area() {}
	char* Name() 
	{ 
		return m_pcName;
	}
private:
	char *m_pcName;
	int   m_iId;
};

class Circle: public GraphicsObject
{
public:
	void Draw() {}
	int Area() {}
};

void main()
{
	GraphicsObject *obj = new Circle; 
	memset((void *)obj,NULL,sizeof(Circle)); 
	obj->Name(); 
	obj->Draw();
}



8月14日
1、进程地址空间由进程可寻址的虚拟内存组成,而且更为重要的特点是内核允许进程使用这种虚拟内存中的地址。
2、
使用WinExec命令
1)、函数原型:
UINT Win Exec(LPCSTR lpCmdLine, UINT uCmdShow);
2)、参数:
lpCmdLine:指向一个空结束的字符串,串中包含将要执行的应用程序的命令行(文件名加上可选参数)。
uCmdShow:定义Windows应用程序的窗口如何显示,并为CreateProcess函数提供STARTUPINFO参数的wShowWindow成员的值。
3)、返回值:
若函数调用成功,则返回值大于31。
3、仅仅由客户端主动实现拥塞控制远远不够,在新的拥塞控制发展中, 基于路由器的避免拥塞机制得到广泛的发展。在当今的交换机、路由器设备的队列都引入了队列拥塞管理机制,提前避免拥塞出现,进行流量整形。
4、Windows提供了3种进行内存管理的方法:
1)、虚拟内存,最适合用来管理大型对象或结构数组;
2)、内存映射文件,最适合用来管理大型数据流(通常来自文件)以及在单个计算机上运行的多个进程之间共享数据;
3)、内存堆栈,最适合用来管理大量的小对象。
5、内存映射文件可以用于3个不同的目的
1)、系统使用内存映射文件,以便加载和执行. exe和DLL文件。这可以大大节省页文件空间和应用程序启动运行所需的时间。
2)、可以使用内存映射文件来访问磁盘上的数据文件。这使你可以不必对文件执行I/O操作,并且可以不必对文件内容进行缓存。
3)、可以使用内存映射文件,使同一台计算机上运行的多个进程能够相互之间共享数据。Windows确实提供了其他一些方法,以便在进程之间进行数据通信,但是这些方法都是使用内存映射文件来实现的,这使得内存映射文件成为单个计算机上的多个进程互相进行通信的最有效的方法。
6、调用CreateFile函数,就可以将文件映像的物理存储器的位置告诉操作系统。你传递的路径名用于指明支持文件映像的物理存储器在磁盘或网络或光盘上的确切位置。这时,必须告诉系统,文件映射对象需要多少物理存储器。若要进行这项操作,就需要创建一个文件映射内核对象,在Windows中可以调用CreateFileMapping函数完成创建一个文件映射内核对象。


8月15日
1、通常,在一个C++程序定义的类中,包含两类文件:.cpp文件和.h文件。其中,.cpp文件被称作C++源文件,里面放的都是C++的源代码;而.h文件则被称作C++头文件,里面放的也是C++的源代码。
C++语言支持“分别编译”,也就是说,一个程序所有的内容,可以分成不同的部分分别放在不同的.cpp文件里。.cpp文件里的东西都是相对独立的,在编 译(compile)时不需要与其他文件互通,只需要在编译成目标文件后再与其他的目标文件做一次链接(link)就行了。比如,在文件a.cpp中定义 了一个全局函数“void a() {}”,而在文件b.cpp中需要调用这个函数。即使这样,文件a.cpp和文件b.cpp并不需要相互知道对方的存在,而是可以分别地对它们进行编译, 编译成目标文件之后再链接,整个程序就可以运行了。
这是怎么实现的呢?从写程序的角度来讲,很简单。在文件b.cpp中,在调用 “void a()”函数之前,先声明一下这个函数“void a();”,就可以了。这是因为编译器在编译b.cpp的时候会生成一个符号表(symbol table),像“void a()”这样的看不到定义的符号,就会被存放在这个表中。再进行链接的时候,编译器就会在别的目标文件中去寻找这个符号的定义。一旦找到了,程序也就可以顺利地生成了。



8月16日
1、ATL提供CComQIPtr和CComPtr两类智能指针,CComQIPtr从CComPtr继承,而CComPtr又依次从另一个类CComPtrBase继承;CComPtrBase定义了内部实际存储的原始指针,以及在原始指针上的实际引用数操作。CComQIPtr和CComPtr增加构造函数和赋值操作。
2、重构(Refactoring)就是在不改变软件现有功能的基础上,通过调整程序代码改善软件的质量、性能,使其程序的设计模式和架构更趋合理,提高软件的扩展性和维护性。



8月19日
1、往往指定注册表填写路径"Software",实际填写路径为"Software\\Wow6432Node"。X64系统引入一项技术叫文件和注册表的重定向。之所以有这个技术,是为了将32位程序和64位程序分离开。这种在64位平台上运行32位程序的模拟器被称为WOW64。WOW64是"Windows 32 on Windows 64"的简称,它在系统层中另提供了一层,以支持老式的32位程序。
有兴趣的读者可查阅相关资料,我这边只讨论关于注册表的重定向:如果是32位程序,对注册表的操作不论是读还是写, WOW64都将会截取对HKLM/Software访问,并重定向到HKLM/Software/Wow6432Node(即32位应用程序的注册信息被写在HKLM/Software/Wow6432Node中,而不是预期的HKLM/Software中);如:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\CSDN]被重定向到
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\CSDN]
如果是64位程序,就直接到 HKLM/Software。
这个重定向机制引发了一个很严重的问题,我们目前编译的程序很多都用x86编译生成的,写注册表时在x64环境下都被重定向到Wow6432Node下,而Office2010有32-bit和64-bit两个版本,32bit-office访问注册表时被重定向到Wow6432Node下读取,没有问题。然而64bit-office访问时直接到HKLM/Software,而不是到HKLM/Software/Wow6432Node下,显然此时因找不到对应的注册表项导致Addins出不来。现在的问题已经很明朗,我们要根据环境写到注册表指定位置,而不被重定向。
2、注册表逻辑结构中最基本的是主键,子键,键值项以及键值.它们是按照分组的方式来管理和组织的.首先是最底根键, 每个根键下有若干个子键,每个子键下又可以有若干(一个或多个)子键,子键下可以有一个或多个键值项和键值. 注册表的作用是保存程序所需要的信息,当程序需要这些信息时,就从注册表里读出.因此,注册表最基本的功能就是保存信息.
Windows 9x注册表逻辑结构中包含六个根键,每个根键包含着分类不同的信息!在WindowsNT/2000/XP中,如果用Windows自带的编辑器打开的时候,只能看到五个,还有一个隐藏的根键:HKEY_PERFOR_MANCE_DATA. 
1)、HKEY_CLASS_ROOT
  记录windows操作系统中所有数据文件的格式和关联信息,主要记录不同文件的文件名后缀和与之对应的应用程序其下子键可分为两类:一类是已经注册的各类文件的扩展名,这类子键前面都带有一个".";另一类是各类文件类型有关信息. 
2)、HKEY_CURRENT_USER
  此根根键包含当前登录用户的用户配置文件信息,这些信息保证不同的用户登录计算机时,使用自己的修改化设置,例如自己定义的墙纸,自己的收件箱,自己的安全访问权限. 
3)、HKEY_LOCAL_MACHINE
  此根键包含了当前计算机的配置灵气,包括所安装的硬件以软件设置.这些信息是为所有的用户登录系统服务的.这是事个注册表中最庞大也是最重要的根键! 
4)、HKEY_USERS
  HKEY_USERS根键包括默认用户的信息(DEFAULT子键)和所有以前登陆用户的信息. 
5)、HKEY_CURRENT_CONFIG
  此根键实际上是HKDY_LOCAL_MACHINE/CONFIG/0001分支下的数据完全一样. 
3、环境变量是包含关于系统及当前登录用户的环境信息的字符串,一些软件程序使用此信息确定在何处放置文件(如临时文件)。
 Windows下查看所有环境变量的值用“set”指令,查看某个用“set **”,其中**表示环境变量。如下查看环境变量“APPDATA”的值:
set APPDATA
APPDATA=C:\Users\jimjxu\AppData\Roaming


8月20日
1、传统认识上,杀毒软件对程序进行安全分析的一个非常重要的依据就是数字签名。它相当于软件程序在电脑系统中的身份证号码,每个合法程序都拥有唯一的签名信息,如果此文件被恶意篡改,签名信息就会失效。
2、Windows服务应用程序是一种需要长期运行的应用程序,它对于服务器环境特别适合。它没有用户界面,并且也不会产生任何可视输出。任何用户消息都会被写进Windows事件日志。计算机启动时,服务会自动开始运行。它们不要用户一定登录才运行,它们能在包括这个系统内的任何用户环境下运行。通过服务控制管理器,Windows服务是可控的,可以终止、暂停及当需要时启动。
3、NDIS(Network Driver Interface Specification)是网络驱动程序接口规范的简称。它横跨传输层、网络层和数据链路层,定义了网卡或网卡驱动程序与上层协议驱动程序之间的通信接口规范,屏蔽了底层物理硬件的不同,使上层的协议驱动程序可以和底层任何型号的网卡通信。
4、心跳包就是在客户端和服务器间定时通知对方自己状态的一个自己定义的命令字,按照一定的时间间隔发送,类似于心跳,所以叫做心跳包。
5、根据连接启动的方式以及本地套接字要连接的目标,套接字之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认。
   1)、服务器监听:是服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态;
   2)、客户端请求:是指由客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求;
   3)、连接确认:是指当服务器端套接字监听到或者说接收到客户端套接字的连接请求,它就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,连接就建立好了。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。



8月21日
1、GUID:英文名(Globally Unique Identifier),全局唯一标识符,是一种由算法生成的二进制长度为128位的数字标识符,主要用于在拥有多个节点、多台计算机的网络或系统中。在理想情况下,任何计算机和计算机集群都不会生成两个相同的GUID。它实际上提取了计算机上的网卡地址,芯片编号,还有毫秒级的时间做为参数来生成GUID,任何一个参数不同,生成的GUID都是不同的。GUID 的格式为“xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx”,其中每个x是0-9或a-f范围内的一个4个数位十六进制数。
2、
IP地址是指Internet协议使用的地址,而MAC地址是Ethernet协议使用的地址。IP地址和MAC地址相同点是都唯一分配的。
MAC地址与IP地址区别:
1)、对于网络上的某一设备,如一台计算机或一台路由器,其IP地址可变(,可以动态分配,但必须唯一),而MAC地址是不可变。我们可以根据需要给一台主机指定任意的IP地址,如我们可以给局域网上的某台计算机分配IP地址为192.168.0.112 ,也可以将它改成192.168.0.200。而任一网络设备(如网卡,路由器)一旦生产出来以后,其MAC地址不可由本地连接内的配置进行修改;
2)、长度不同。IP地址为32位(IPV4,正在向64位扩展即IPV6),MAC地址为48位;
3)、分配依据不同。IP地址的分配是基于网络拓扑,MAC地址的分配是基于制造商;
4)、寻址协议层不同。IP地址应用于OSI第三层,即网络层,而MAC地址应用在OSI第二层,即数据链路层。 数据链路层协议可以使数据从一个节点传递到相同链路的另一个节点上(通过MAC地址),而网络层协议使数据可以从一个网络传递到另一个网络上(ARP根据目的IP地址,找到中间节点的MAC地址,通过中间节点传送,从而最终到达目的网络)。
3、extern "C"的主要作用就是为了能够正确实现C++代码调用其他C语言代码。加上extern "C"后,会指示编译器这部分代码按C语言的进行编译,而不是C++的。由于C++支持函数重载,因此编译器编译函数的过程中会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名;而C语言并不支持函数重载,可以定义不属于任何类的全局变量和函数,因此编译C语言代码的函数时不会带上函数的参数类型,一般之包括函数名。
4、C++提供了关键字explicit,可以阻止不应该允许的经过转换构造函数进行的隐式转换的发生。

class Test1
{
public:
	Test1(intn){num=n;}
private:
	int num;
};
class Test2
{
public:
	explicit Test2(intn){num=n;}
private:
	int num;
};

int main()
{
     Test1t1=12;//隐式调用其构造函数,成功
     Test2t2=12;//编译错误,不能隐式调用其构造函数
     Test2t3(12);//显式调用成功
     return0;
}

5、计算机高级语言类型主要有编译型和解释型两种,Java是两种类型的集合,在Java中源文件的后缀为*.java,之后通过编译生成一个*.class文件,最后在Java自己设计的一个计算机上运行,也就是虚拟机(JVM),JVM是在一台计算机上由软件或硬件模拟的计算机,所有的*.class文件都是在JVM上运行的,即*.class文件只需认JVM,由JVM再去适应各个操作系统。如果不同的操作系统安装上符合其类型的JVM,那么以后程序无论到哪个OS上都是可以正确执行的。有些语言没有JVM的说法,当然也不能跨平台。



总结:

       两个多月的实习很快就要结束了,在这期间,真的很愉快,学到很多,也感觉到自己的程序可以被亿万用户使用的成就感!下面谈谈我的实习之旅吧。

       2014年6月19号入职,随后几日,在导师们帮助下熟悉部门业务和文化,了解Hummer平台开发技术。

之后在导师的安排下参与项目中widget与设备位置算法类的设计与实现。实现两种算法:第一种是通过准确计算得到设备的角度范围(二分优化),平分最大角度,然后随机产生小角度误差,此算法时间复杂度为O(n*n),空间方面要保存角度信息,涉及大量浮点数运算尤其除法运算,资源消耗大,效率较低;同时产品需求要求尽量均匀但不平分,而此方法基本平分,效果不理想。第二种方法是随机产生设备位置,然后检测是否碰撞。基于随机数的随机性原理,同时通过计算避免碰撞,此算法的时间复杂度为O(n),不需保留角度信息,不需浮点数除法运算,效率较高,可以达到尽量均匀但不平分的需求。所以最终提交第二种方法。

      第二个任务是导师给我安装包相关程序代码,要求在此基础上整理出相关文档,然后编程实现安装包中指定.exe文件的MD5计算(要求可以解压但不能安装)。通过仔细研读源代码,梳理执行流程,逐渐弄懂程序基本原理和界面引擎技术,在成功分离安装包文件解压释放与登记注册表等功能模块后,调用7z解压算法实现解压,并编写MD5代码,初步完成安装包解压并计算指定文件MD5值;后来在初步掌握UI引擎后,设计出自己的UI界面,完成小工具的开发。之后,修改程序达到配置xml文件从不同目录读取待打包文件,同时在安装过程中按需求将文件释放到不同目录下要求。此外,一直在工作之余研读导师推荐的几本关于Windows程序设计的经典书籍。

      由于常用数据结构和常用算法掌握较好,遇到的逻辑问题都能较快解决,对于同一问题,能够设计不同的解决方案,然后从执行效率等角度加以分析,从而选择最为高效的算法实现。当然,在实习过程中我发现自己的不足,知识面较为狭窄,缺乏Windows编程经验,在参与项目过程中很多时间都花在查阅相关资料学习相关知识上。此外,在实习过程中与其他导师同事们交流偏少,主要原因是在部门业务中参与较少,工作模块相对独立;而且由于缺乏Windows开发经验,为尽快适应岗位,在完成导师制定工作之余一直在学习Windows编程知识,没有主动承担其他任务。

      在这期间,真的很愉快,学到很多,感谢我的导师同事们!





你可能感兴趣的:(多线程,windows,操作系统,内存管理,可视化)