Manifest文件详解

Manifest是个XML的描述文件,对于每个DLL有DLL的Manifest文件,对于每个应用程序Application也有自己的Manifest。对于应用程序而言,Manifest可以是一个和exe文件同一目录下的.manifest文件,也可以是作为一个资源嵌入在exe文件内部的(Embed Manifest)。

XP以前版本的windows,会像以前那样执行这个exe文件,寻找相应的dll,没有分别Manifest只是个多余的文件或资源,dll文件会直接到system32的目录下查找,并且调用。这样,如果公共DLL升级,将会导致之前安装的应用程序不能使用,这就是“DLL Hell”的来源。为了解决这个问题,.NET开发提出了side-by-by的开发方法,来避免这个问题。主要方法,就是通过Manifest文件来查找相应的DLL。XP及以后的系统都集成了这样一种查找DLL的方法。

编辑

提取Manifest

默认Manifest文件都是内嵌在exe/dll中的,如果需要查看。VS提供mt.exe工具来从exe/dll中提取Manifest文件。

mt.exe -inputresource:d:\test.exe -out:d:\test.manifest
编辑

的Manifest文件有关设置

我们编译MFC工程时,会在stdafx.h文件里看到下列代码。

#ifdef _UNICODE
#if defined _M_IX86
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_IA64
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_X64
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#else
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif
#endif

如果是非unicode版本,则生成的界面是Win98风格,如果是unicdoe版本,则是当前操作系统的风格。 Linker→Manifest file→Generate Manifest→yes 即会生成EXE/DLL所用的Manifest文件。

<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type='win32' name='Microsoft.VC80.CRT' version='8.0.50608.0' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />
    </dependentAssembly>
  </dependency>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type='win32' name='Microsoft.VC80.MFC' version='8.0.50608.0' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />
    </dependentAssembly>
  </dependency>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*' />
    </dependentAssembly>
  </dependency>
</assembly>

如果没有设置上面的控件风格,则生成的Manifest不会包括contrls.

<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type='win32' name='Microsoft.VC80.CRT' version='8.0.50608.0' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />
    </dependentAssembly>
  </dependency>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type='win32' name='Microsoft.VC80.MFC' version='8.0.50608.0' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />
    </dependentAssembly>
  </dependency>
</assembly>

所有的exe/dllFT都必须要有Manifest。如果Linker→Manifest file→Generate Manifest→No,则在必须Manifest Tool→Additinal Manifest Files中指定相应的Manifest文件。 Manifest Tool→Embed Manifest→Yes。一般都是将Manifest文件嵌套在程序中。也可以不嵌套在程序中,像MFCxx.dll, MSVCRxx.Dll,MSVCPxx.dll都是没有将Manifest嵌套在程序中的。所以当使用它们时必须与其Manifest文件一起使用。

编辑

EXE调用DLL的过程

以下针对链接MFCxx.dll, MSVCPXX.DLL, MSVCRxx.dll的程序。 
系统启动exe时,会先检查其Manifest文件(如果没有查找到当前EXE中有Manifest,则会报“程序配置不正确的”的错误提示),查找系统中是否有注册相应的Dll组件。如果有,则会去c:\windows\winsxs\Manifest文件夹根据相应的调用策略及Manifest文件,然后再根据Manifest中的内容去c:\windows\winsxs同名文件夹中查找到关的DLL。 
如果没有查找到相应的DLL,则会到当前目录来查找Microsoft.VC80.CRT.manifest和Microsoft.VC80.MFC.manifest。 
如果没有查找到当前EXE中有Manifest,则会报“程序配置不正确的”的错误提示。查到之后,就会去找相应的DLL。然后执行程序。

编辑

相关DLL介绍

选择Use MFC in share DLL会用到MFCxx.DLL. MFC80.dll, 即对应VS2005的。 MFC80U.DLL,即对应VS2005的Unicode版本。

选择MD/MDd则会用到下面的DLL。 MSVCR80.dll,即VS2005下的C RunTime库,提供基本的C函数。 MSVCP80.dll, 即VS2005年的C++函数库,如果有调用<string>之类的文件,则会使用到此DLL。

编辑

注意

1、X86、X64需要去VS工具目录

C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\redist\x86
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\redist\x64

2、Manifest文件自VS2010之后,又被集成到模块当中去了,不再分开提供。

  • 9
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android联系人代码主要涉及到三个方面:联系人的读取、添加和删除。下面分别介绍一下: 1. 联系人读取 读取联系人的代码可以分为两个部分:一是获取读取联系人的权限,二是查询联系人数据。 获取读取联系人的权限: ```java if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_READ_CONTACTS); } else { // permission already granted readContacts(); } ``` 查询联系人数据: ```java private void readContacts() { Cursor cursor = null; try { cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null); while (cursor.moveToNext()) { String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)); String phoneNumber = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); // do something with name and phoneNumber } } catch (Exception e) { e.printStackTrace(); } finally { if (cursor != null) { cursor.close(); } } } ``` 2. 联系人添加 添加联系人的代码也分为两个部分:一是获取添加联系人的权限,二是向系统中添加联系人数据。 获取添加联系人的权限: ```java if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_CONTACTS) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_CONTACTS}, REQUEST_WRITE_CONTACTS); } else { // permission already granted addContact(); } ``` 向系统中添加联系人数据: ```java private void addContact() { ArrayList<ContentProviderOperation> ops = new ArrayList<>(); ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null) .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null) .build()); ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, "John Doe") .build()); ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, "1234567890") .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE) .build()); try { getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); } catch (Exception e) { e.printStackTrace(); } } ``` 3. 联系人删除 删除联系人的代码只需获取删除联系人的权限,并向系统中删除联系人数据即可。 获取删除联系人的权限: ```java if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_CONTACTS) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_CONTACTS}, REQUEST_WRITE_CONTACTS); } else { // permission already granted deleteContact(); } ``` 向系统中删除联系人数据: ```java private void deleteContact() { String[] args = {String.valueOf(contactId)}; getContentResolver().delete(ContactsContract.RawContacts.CONTENT_URI, ContactsContract.RawContacts.CONTACT_ID + "=?", args); } ``` 以上就是Android联系人代码的详解。需要注意的是,在使用读取、添加和删除联系人数据的代码时,需要在AndroidManifest.xml文件中添加相应的权限声明,否则会抛出SecurityException异常。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值