[转]Replace all UUIDs in an ATL COM DLL.
1. Introduction.
1.1 Recently, a friend asked me for advise on a very
unusual requirement.
1.2 He needs to replace all UUIDs in a COM DLL with new
ones.
1.3 He does not have the source codes to the original
COM server so any modifications will have to be done on the binary
code.
1.4 To be more accurate, the objective was to replace
the UUIDs of COM
Types defined in the COM DLL.
1.5 Ever enthusiastic for any opportunity to do unusual
spelunking, I helped to research into this.
1.6 Using a sample COM in-proc server written in ATL, I
managed to accomplish this and verified the results using a test
program.
1.7 In this blog, I aim to demonstrate to the reader how
this can be done.
2. The General Outline of the
Plan.
2.1 As I advised my friend, performing such a feat is
certainly possible but it depends on how the original COM DLL was created
:
– What tool was used to create the DLL ? e.g. ATL, VB,
C#, etc.
– Was it hand-crafted instead in C++ ?
2.2 Assuming that the COM DLL server was developed using
ATL, the process is quite straightforward but involves a number of steps
:
- Replacing the Type Library embedded as a resource inside
the DLL. - Replacing the registration strings embedded as a
resource inside the DLL. - Replacing all occurrences of specific GUIDs inside the
code of the DLL. - Registering the new DLL.
2.3 For the purposes of demonstration, I created a
simple COM in-proc server and a test console application that uses the COM Types
in the DLL.
2.4 The test program will initially link with the
original DLL.
2.5 After we have created a new DLL with all the
replacement UUIDs, the test program will link to the new DLL and we shall see
that the output of the test program will be the same.
3. A Simple ATL COM DLL.
3.1 The following are the main characteristics of the
COM DLL (SimpleATLCOMServer.dll)
which we will be working on :
- It is 32-bit and is written using ATL.
- It exposes a single coclass named
SimpleCOMClass. - SimpleCOMClass exposes a single interface
ISimpleCOMClass. - SimpleCOMClass supports a COM event
_ISimpleCOMClassEvents.
3.2 The following is a listing of the IDL :
// SimpleATLCOMServer.idl : IDL source for SimpleATLCOMServer
// // This file will be processed by the MIDL tool to
// produce the type library (SimpleATLCOMServer.tlb) and marshalling code. import "oaidl.idl";
import "ocidl.idl"; [ object, uuid(4C1AE3E8-736E-4750-9D08-48CDC33E66FA), dual, nonextensible, pointer_default(unique)
]
interface ISimpleCOMClass : IDispatch{ [id(1)] HRESULT TestMethod01([in] BSTR strParam);
};
[ uuid(8A32BF84-3743-4AE5-A791-623F17C6E804), version(1.0),
]
library SimpleATLCOMServerLib
{ importlib("stdole2.tlb"); [ uuid(60FD53D5-2D3E-4BCC-96E6-484F8D8A5119) ] dispinterface _ISimpleCOMClassEvents { properties: methods: [id(1)] HRESULT TestEvent01([in] BSTR strParam); }; [ uuid(68226D2E-8EE4-4B42-9B39-2D4ED9D578DD) ] coclass SimpleCOMClass { [default] interface ISimpleCOMClass; [default, source] dispinterface _ISimpleCOMClassEvents; };
};
3.3 The ISimpleCOMClass interface has a single method
TestMethod01() which takes a BSTR as parameter.
3.4 The _ISimpleCOMClassEvents event interface has a
single method TestEvent01() which also takes a BSTR parameter.
3.5 The actual implementation for ISimpleCOMClass is a
C++ class named CSimpleCOMClass.
3.6 The definition for TestMethod01() is as follows
:
STDMETHODIMP CSimpleCOMClass::TestMethod01(BSTR strParam)
{ // TODO: Add your implementation code here _bstr_t _bst(strParam, true); LPCTSTR lpszParam = (LPCTSTR)_bst; MessageBox(NULL, lpszParam, "CSimpleCOMClass", MB_OK); Fire_TestEvent01(strParam); return S_OK;
}
It displays the contents of the BSTR parameter and then
fires TestEvent01() using the same BSTR parameter to TestMethod01().
3.7 In the sections that follow, we will expound in
greater detail the steps that we take to replace all COM UUIDs in the DLL with
new ones.
4. Replacing the Type Library embedded as a resource
inside the DLL.
4.1 Extracting the type library of the original DLL can
be done using OleView. The following is a screenshot of how the IDL will be
displayed :
- The great thing about OleView is that it is able to save
the displayed IDL into an external file. - We shall save it as SimpleATLCOMServerNew.IDL.
4.2 Next, open SimpleATLCOMServerNew.IDL and
perform the following changes :
- Generate new UUIDs using GUIDGEN.EXE.
- Replace the UUID for the SimpleATLCOMServerLib LIBID,
_ISimpleCOMClassEvents Event Interface UUID, the SimpleCOMClass coclass CLSID
and ISimpleCOMClass interface IID. - Change the name of the library from
SimpleATLCOMServerLib to SimpleATLCOMServerNewLib.
The following is a sample
modified SimpleATLCOMServerNew.IDL :
// Generated .IDL file (by the OLE/COM Object Viewer)
//
// typelib filename: SimpleATLCOMServer.dll [ uuid(F702C924-7CC9-4E26-BE36-E646222A057E), version(1.0), custom(DE77BA64-517C-11D1-A2DA-0000F8773CE9, 134218331), custom(DE77BA63-517C-11D1-A2DA-0000F8773CE9, 1485538469), custom(DE77BA65-517C-11D1-A2DA-0000F8773CE9, "Created by MIDL version 8.00.0603 at Sat Jan 28 01:34:25 2017
") ]
library SimpleATLCOMServerNewLib
{ // TLib : // TLib : OLE Automation : {00020430-0000-0000-C000-000000000046} importlib("stdole2.tlb"); // Forward declare all types defined in this typelib dispinterface _ISimpleCOMClassEvents; interface ISimpleCOMClass; [ uuid(E793B680-C0B2-4FB6-ADDD-7F66A30EF5DB) ] dispinterface _ISimpleCOMClassEvents { properties: methods: [id(0x00000001)] HRESULT TestEvent01([in] BSTR strParam); }; [ uuid(F7C6EE89-AA69-4BB6-8CA0-D7CC9B6A0473) ] coclass SimpleCOMClass { [default] interface ISimpleCOMClass; [default, source] dispinterface _ISimpleCOMClassEvents; }; [ odl, uuid(78A36043-6DAE-4457-95D8-A4425ECF84DA), dual, nonextensible, oleautomation ] interface ISimpleCOMClass : IDispatch { [id(0x00000001)] HRESULT TestMethod01([in] BSTR strParam); };
};
All new replacement UUIDs are displayed in bold. The new
name for the library is also in bold.
4.3 Next we need to recompile the new IDL
using MIDL.exe :
- In a command prompt, go to the folder
where SimpleATLCOMServerNew.IDL is
stored and run the following command :
midl SimpleATLCOMServerNew.IDL /env win32 /W1 /char signed
- Before running this command, you may need to set the
“INCLUDE” path to include new directories (so as to ensure a successful MIDL
compilation) :
set INCLUDE=%INCLUDE%;C:\Program Files (x86)\Windows Kits\8.1\Include\um;C:\Program Files (x86)\Windows Kits\8.1\Include\shared
- A new type library SimpleATLCOMServerNew.tlb will
be produced.
4.4 Then, use Visual Studio to replace the original type
library of the DLL with the new modified one :
- Make a copy of the original SimpleATLCOMServer.dll and
named it as SimpleATLCOMServerNew.dll. - Run Visual Studio and open SimpleATLCOMServerNew.dll as
an executable file.
- Right-click on “TYPELIB” and select “Add Resource”
:
- The “Add Resource” dialog box will appear
:
- Select “TYPELIB” and click on the “Import”
button. - A File Selection dialog box will appear.
- Search for and select the new type
library SimpleATLCOMServerNew.tlb that
we have just created. - A new “TYPELIB” resource will be added
:
- Note well, however, that the resource ID for the new
“TYPELIB” resource is one given by Visual Studio. - In our example, it is 101. It needs to be renumbered to
1. - To do this, remove the “TYPELIB” resource with ID 1 by
righ-clicking on it and selecting “Delete” :
- Thereafter, select the 101 resource and right-click on
it. Then select “Properties”. - Under the “Properties” explorer, change the ID to 1
:
- And that’s it. We have put in place a new type library
resource within the COM DLL.
5. Replacing the Registration Scripts Embedded as a
Resource inside the DLL.
5.1 The registration scripts are the .rgs resources
commonly found in ATL projects.
5.2 It contains strings that are used in the COM
registration process.
5.3 The objective is to extract the existing .rgs
resources, modify them, and then re-insert them into the DLL.
5.4 Extracting the .rgs resource is done once again
using Visual Studio by opening up the DLL as an executable file :
- This time, the .rgs resources are contained in
“REGISTRY” :
- Unlike the type library, there could be several .rgs
resources contained in “REGISTRY”. - However, in our simple example, only one .rgs resource
is important (ID 106). - Select all relevant ,rgs resources and export them by
right-clicking and then selecting “Export” :
- A File-Save dialog box will appear. Save it
as SimpleATLCOMServerNew.rgs. - SimpleATLCOMServerNew.rgs is
a text file. Open it using notepad.exe. - The following is the contents :
HKCR
{ NoRemove CLSID { ForceRemove {68226D2E-8EE4-4B42-9B39-2D4ED9D578DD} = s 'SimpleCOMClass Class' { ForceRemove Programmable InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Apartment' } TypeLib = s '{8A32BF84-3743-4AE5-A791-623F17C6E804}' Version = s '1.0' } }
}
- We need to replace the existing UUIDs with new
corresponding ones :
HKCR
{ NoRemove CLSID { ForceRemove {F7C6EE89-AA69-4BB6-8CA0-D7CC9B6A0473} = s 'SimpleCOMClass Class' { ForceRemove Programmable InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Apartment' } TypeLib = s '{F702C924-7CC9-4E26-BE36-E646222A057E}' Version = s '1.0' } }
}
- Next, using methods that we have used previously on type
library replacement, replace the existing “REGISTRY” resource (ID 106) with the
new modified one.
6. Replacing all Occurrences of Specific UUIDs inside
the Code of the DLL.
6.1 This is by far the most interesting part of the
replacement process.
6.2 To do this, we need to write a program that performs
the following :
- Open the DLL file as a stream of bytes.
- Scan through the stream of bytes and search for byte
patterns that correspond with the original UUIDs. - Replace all original UUIDs with the new
ones.
6.3 It is important to note that a UUID is in actual
fact a binary structure and not a string (see UUID
structure).
- For convenience, UUIDs are often represented as strings
in source codes. - But they will all resolve to binary structures at
runtime. - Code like the following :
spISimpleCOMClass->QueryInterface(IID_ISimpleCOMClass, (void**)&pISimpleCOMClass);
requires that IID_ISimpleCOMClass be expressed as a
structure like the following :
{0x4c1ae3e8,0x736e,0x4750,{0x9d,0x08,0x48,0xcd,0xc3,0x3e,0x66,0xfa}
- It is essentially a series of bytes.
- Hence to replace all occurrences of IID_ISimpleCOMClass
in a DLL, our program can simply search for such byte sequences and directly
replace them.
6.4 This program is best done in C# due to the rich
functionality of the .NET class libraries.
6.5 The following is a listing of the C# program
:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO; namespace ConsoleGUIDReplacer
{ class Program { // Code for the following algorithm taken from : // Most efficient way to replace one sequence of the bytes with some other sequence // http://stackoverflow.com/questions/10702514/most-efficient-way-to-replace-one-sequence-of-the-bytes-with-some-other-sequence private static byte[] Replace(byte[] input, byte[] pattern, byte[] replacement) { if (pattern.Length == 0) { return input; } List<byte> result = new List<byte>(); int i; for (i = 0; i <= input.Length - pattern.Length; i++) { bool foundMatch = true; for (int j = 0; j < pattern.Length; j++) { if (input[i + j] != pattern[j]) { foundMatch = false; break; } } if (foundMatch) { result.AddRange(replacement); i += pattern.Length - 1; } else { result.Add(input[i]); } } for (; i < input.Length; i++) { result.Add(input[i]); } return result.ToArray(); } static void Main(string[] args) { string strCOMServerTargetPath = args[0]; string strCOMServerNewPath = args[1]; Guid guid_search = new Guid(args[2]); Guid guid_replace = new Guid(args[3]); byte[] byCOMServerBytesTarget = File.ReadAllBytes(strCOMServerTargetPath); byte[] byCOMServerBytesNew = Replace(byCOMServerBytesTarget, guid_search.ToByteArray(), guid_replace.ToByteArray()); File.WriteAllBytes(strCOMServerNewPath, byCOMServerBytesNew); } }
}
- Note that the code for the Replace() method is taken
directly from the following StackOverflow discussion thread :
Most efficient way to replace one sequence of the bytes
with some other sequence.
6.6 The program expects 4 runtime arguments :
- The path to the original DLL.
- The path to the a new DLL that will contain the replaced
UUID. - The original UUID in string form.
- The replacement UUID in string form.
The following is a sample command line :
ConsoleGUIDReplacer.exe SimpleATLCOMServerNew.dll SimpleATLCOMServerNew.01.dll 4C1AE3E8-736E-4750-9D08-48CDC33E66FA 78A36043-6DAE-4457-95D8-A4425ECF84DA
- The above command will change all occurrences of the
original IID of ISimpleCOMClass with a new one that we have
generated. - A new DLL SimpleATLCOMServerNew.01.dll will
be created with the new IID. - We will have to call ConsoleGUIDReplacer.exe 4
times in order to replace all original UUIDs with the new ones. - Each time we run ConsoleGUIDReplacer.exe,
a new version of the SimpleATLCOMServerNew DLL will be generated. - Eventually, we will emerge with a
complete SimpleATLCOMServerNew.dll with
all original UUIDs replaced with new ones.
6.7 The availability of structures like Guid in .NET
goes a long way towards simplifying things :
- It provides a constructor that takes a UUID in string
form (perfect for us). - It provides a ToByteArray() method that simplifies the
process of expressing the UUID as a series of bytes (again, perfect for
us).
7. Registering the new DLL.
7.1 Not to forget : we must also register the
new SimpleATLCOMServerNew.dll.
7.2 This is necessary because it is, in the eyes of COM,
completely distinct from the original SimpleATLCOMServer.dll.
7.3 Run regsvr32.exe as per normal.
8. Test Program.
8.1 The following is a general game plan for the test
:
- We write a C++ console program that imports the
original SimpleATLCOMServer.dll. - In the test program, we will create an instance of the
SimpleCOMClass coclass. - Using its ISimpleCOMClass interface, we call
TestMethod01(). - We will also write an event handler class and receive
the TestEvent01() event. - We then modify the test program and import the
new SimpleATLCOMServerNew.dll. - We then re-compile and run the program once
again. - The same result will be observed.
8.2 The listing for the test program is as follows
:
// ConsoleClientApp.cpp : Defines the entry point for the console application.
// #include "stdafx.h" // Comment in/out the import and using statement according
// to which version of the DLL is to be used.
#import "SimpleATLCOMServer.dll" raw_interfaces_only
using namespace SimpleATLCOMServerLib; //#import "SimpleATLCOMServerNew.dll" raw_interfaces_only
//using namespace SimpleATLCOMServerNewLib; #include "TEventHandler.h"
using namespace TEventHandlerNamespace; class EventHandler; typedef TEventHandler<EventHandler, ISimpleCOMClass, _ISimpleCOMClassEvents> ISimpleCOMClassEventHandler; class EventHandler
{
public : EventHandler(ISimpleCOMClassPtr spISimpleCOMClass) { // ***** Create an instance of an object which implements IEventFiringObject. ***** m_spISimpleCOMClass = spISimpleCOMClass; // ***** Instantiate an IEventFiringObjectEventHandler object. ***** m_pISimpleCOMClassEventHandler = new ISimpleCOMClassEventHandler(*this, m_spISimpleCOMClass,
&EventHandler::OnSimpleCOMClassInvoke); } ~EventHandler() { if (m_pISimpleCOMClassEventHandler) { m_pISimpleCOMClassEventHandler->ShutdownConnectionPoint(); m_pISimpleCOMClassEventHandler->Release(); m_pISimpleCOMClassEventHandler = NULL; } if (m_spISimpleCOMClass) { m_spISimpleCOMClass = NULL; } } ISimpleCOMClassPtr m_spISimpleCOMClass; // ***** Declare a pointer to a TEventHandler class which is specially tailored ***** // ***** to receiving events from the _IEventFiringObjectEvents events of an ***** // ***** IEventFiringObject object. ***** ISimpleCOMClassEventHandler* m_pISimpleCOMClassEventHandler; HRESULT EventHandler::OnSimpleCOMClassInvoke ( ISimpleCOMClassEventHandler* pEventHandler, DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr ) { if (dispidMember == 0x01) // Event1 event. { // 1st param : [in] BSTR strParam. VARIANT varValue; VariantInit(&varValue); varValue = (pdispparams->rgvarg)[0]; _bstr_t _bst(V_BSTR(&varValue), true); char szMessage[256]; sprintf_s(szMessage, sizeof(szMessage), "Event 1 is fired with value : %s.", (LPCTSTR)_bst); ::MessageBox(NULL, szMessage, "Event", MB_OK); } return S_OK; }
}; void DoTest()
{ ISimpleCOMClassPtr spISimpleCOMClass = NULL; spISimpleCOMClass.CreateInstance(__uuidof(SimpleCOMClass)); EventHandler event_handler(spISimpleCOMClass); BSTR bstr = ::SysAllocString(L"Hello World"); if (bstr) { spISimpleCOMClass->TestMethod01(bstr); ::SysFreeString(bstr); bstr = NULL; }
} int main()
{ ::CoInitialize(NULL); DoTest(); ::CoUninitialize(); return 0;
}
8.3 For the purposes of the test, I have copied the
original and new DLLs into the same folder as the project of the test
program.
8.4 Notice that when we import SimpleATLCOMServerNew.dll,
we use the SimpleATLCOMServerNewLib namespace.
8.5 This is because of what we did in point 4.2 where we
changed the name of the library statement in the new IDL from
SimpleATLCOMServerLib to SimpleATLCOMServerNewLib.
8.6 For handling COM events, I have created the
EventHandler class and have used the TEventHandler class
(see Understanding
COM Event Handling) to simplify handling IDispatch-based event
interfaces.
8.7 When we run the above code, the following will occur
:
- As TestMethod01() is called, the following dialog box
will be displayed :
- Then TestMethod01() will fire the TestEvent01() event
which will cause our event handler to display the following dialog box
:
8.8 Next, comment out the import of
the SimpleATLCOMServer.dll and
comment in the import of SimpleATLCOMServerNew.dll :
// Comment in/out the import and using statement according
// to which version of the DLL is to be used.
//#import "SimpleATLCOMServer.dll" raw_interfaces_only
//using namespace SimpleATLCOMServerLib; #import "SimpleATLCOMServerNew.dll" raw_interfaces_only
using namespace SimpleATLCOMServerNewLib;
- Re-compile the test program.
- Run it again.
You will see that the same dialog boxes will be
displayed.
8.9 As an additional step that we can take to ensure
that these 2 DLLs are truly distinct, we can modify the
original SimpleATLCOMServer.dllby
changing the code for TestMethod01() as follows :
STDMETHODIMP CSimpleCOMClass::TestMethod01(BSTR strParam)
{ // TODO: Add your implementation code here _bstr_t _bst(strParam, true); LPCTSTR lpszParam = (LPCTSTR)_bst; MessageBox(NULL, lpszParam, "CSimpleCOMClass Original", MB_OK); Fire_TestEvent01(strParam); return S_OK;
}
We simply change the dialog box title to
“CSimpleCOMClass Original”.
8.10 Thereafter, modify ConsoleClientApp.cpp once
again to import SimpleATLCOMServer.dll,
compile the test program and run it :
- This time, when TestMethod01() is called, the following
will be displayed :
8.11 Now, once again import SimpleATLCOMServerNew.dll,
re-compile and run the program :
- When TestMethod01() is called, the original dialog box
will be displayed :
9. In Summary.
9.1 In summary, we can see that complete replacement of
UUIDs in a COM DLL server is possible. However, note well :
- As mentioned previously, we are merely changing the
UUIDs of COM types which have already been implemented in the
server. - We are not attempting to change the logic of the
implementation code. - If the implementation code references other CLSIDs,
IIDs, LIBIDs or any other UUIDs other than the ones we already know, we do not
modify these (in fact, we shouldn’t).
9.2 Note well that, with the exception of COM servers
written in a managed language, regardless of whatever tool was used to generate
a COM DLL server, the following are common requirements of the DLL :
- All COM DLLs must have its type library embedded as a
resource. This is to ensure that the COM types in the DLL can be referenced by
development tools like Visual Studio (e.g. via the #import statement in
C++). - All COM DLLs (whatever tool was used to create it), must
be self-registrable.
Hence at minimum, it should be no problem to at least
modify the embedded type libraries contained inside a COM DLL. Modifying the
self-registration code will require some further research.
9.3 The techniques for modification of UUIDs in runtime
code will also likely be varied.
9.4 I hope to research into these in the
future.
10. Source Codes.
10.1 The source codes for this blog can be downloaded
from here.
[转]Replace all UUIDs in an ATL COM DLL.的更多相关文章
- 用ATL和MFC来创建ActiveX控件
摘要:目前MFC和ATL代表了两种框架,分别面向不同类型的基于Windows的开发.MFC代表了创建独立的Windows应用的一种简单.一致的方法:ATL提供了一种框架来实现创建COM客户机和服务器所 ...
- ARCGIS SDE空间化处理
在 Oracle 中,ST_Geometry 和 ST_Raster 的 SQL 函数使用通过 Oracle 的外部过程代理(即 extproc)访问的共享库.要将 SQL 和 ST_Geometry ...
- 第22章 DLL注入和API拦截(3)
22.6 API拦截的一个例子 22.6.1 通过覆盖代码来拦截API (1)实现过程 ①在内存中对要拦截的函数(假设是Kernel32.dll中的ExitProcess)进行定位,从而得到它的内存地 ...
- VS 2005部署应用程序提示“应用程序无法正常启动( 0x0150002)” 解决方案
遇到这个问题,一定是缺少了CRT.MFC.ATL的DLL,不同版本的VS是不一样的.系统自带这些库的Release版,如果没有自带,打补丁就有了:系统不自带这些库的Debug版,所以Debug版的程序 ...
- VLD(Visual LeakDetector)内存泄露库的使用
VLD简介 由于C/C++语言没有所谓的垃圾收集器,内存的分配和释放都需要程序员自己来控制,这会给C/C++程序员带来一定的困难.当您的程序越来越复杂时,它的内存管理也会变得越来越困难.内存泄漏.内存 ...
- 如何往IE工具条添加按钮(转载)
如何往IE工具条添加按钮 问题提出:金山词霸.网络蚂蚁等软件安装后会向IE的工具条添加自己的按钮.按下按钮后还会作出相应的动作,这种功能是如何实现的呢?读完本文,您也可以将自己应用程序的按钮添加到IE ...
- JAVA判断32位还是64位,调用不同的DLL(转)
源:JAVA判断32位还是64位,调用不同的DLL 通过获取sun.arch.data.model可判断是32还是64的JAVA 将32或者64位的DLL放不同的目录,实现自适应调用DLL Prope ...
- [zz]VC2005-应用程序正常初始化失败-0xc0150002
最近几天被这个问题困惑了许久. 不禁感叹微软的东东真是越做越烂了,也终于明白了时隔12年大家仍然死守VC6的原因.. 用VC2005编译的程序,编译时没有任何错误,但是运行时就是提示“应用程序正常初始 ...
- 配置Oracle访问SQL地理数据库
Oracle访问空间数据 ArcSDE是ArcGIS的空间数据引擎,它是在关系数据库管理系统(RDBMS)中存储和管理多用户空间数据库的通路.以前连接方式有两种,服务连接与直接连接(简称"直 ...
随机推荐
- Spring Boot Oauth2
Oauth2是描述无状态授权的协议(授权框架),因为是无状态,所以我们不需要维护客户端和服务器之间的会话. Oauth2的工作原理: 此协议允许第三方客户端代表资源所有者访问受保护资源,Oauth2有 ...
- mina2中IoHandler
IoHandler 当我们通过IoSession执行相关操作的时候,如写数据,这些事件会触发Mina框架抽象的IoService实例,从而调用Mina框架底层的相关组件进行处理.这时,配置的IoHan ...
- python学习(三) 使用字符串
第三章 使用字符串 ...
- Zabbix 客户端自定义端口监控
http://www.linuxidc.com/Linux/2013-05/83780.htm
- oracle的sqlldr时插入新列和固定数据
ctl文件加入固定值 region CONSTANT '31', 加入默认时间 RECORD_DATE "sysdate" 最好数据也设置RECORD_DATE的默认值为sysda ...
- 第十九章 MySQL Cluster(待续)
··········
- js(react.js) button click 事件无法触发
今天遇到一个诡异的问题.button 上的点击事件触发不了. 找个几个小时,原因是 js 报错了. <Button type="primary" htmlType=" ...
- oracle10g Error in invoking target 'install' of makefile
oracle10g series error error in invoking target 'install' of makefile /u01/app/oracle/oracle/product ...
- leetcode421
public class Solution { public int FindMaximumXOR(int[] nums) { , mask = ; ; i >= ; i--) { mask = ...
- ffmpeg码率控制
一.VBR与CBR的含义和区别 VBR是动态码率.CBR是静态码率. VBR(Variable Bitrate)动态比特率.也就是没有固定的比特率,压缩软件在压缩时根据音频数据即时确定使用什么比特率, ...