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.的更多相关文章

  1. 用ATL和MFC来创建ActiveX控件

    摘要:目前MFC和ATL代表了两种框架,分别面向不同类型的基于Windows的开发.MFC代表了创建独立的Windows应用的一种简单.一致的方法:ATL提供了一种框架来实现创建COM客户机和服务器所 ...

  2. ARCGIS SDE空间化处理

    在 Oracle 中,ST_Geometry 和 ST_Raster 的 SQL 函数使用通过 Oracle 的外部过程代理(即 extproc)访问的共享库.要将 SQL 和 ST_Geometry ...

  3. 第22章 DLL注入和API拦截(3)

    22.6 API拦截的一个例子 22.6.1 通过覆盖代码来拦截API (1)实现过程 ①在内存中对要拦截的函数(假设是Kernel32.dll中的ExitProcess)进行定位,从而得到它的内存地 ...

  4. VS 2005部署应用程序提示“应用程序无法正常启动( 0x0150002)” 解决方案

    遇到这个问题,一定是缺少了CRT.MFC.ATL的DLL,不同版本的VS是不一样的.系统自带这些库的Release版,如果没有自带,打补丁就有了:系统不自带这些库的Debug版,所以Debug版的程序 ...

  5. VLD(Visual LeakDetector)内存泄露库的使用

    VLD简介 由于C/C++语言没有所谓的垃圾收集器,内存的分配和释放都需要程序员自己来控制,这会给C/C++程序员带来一定的困难.当您的程序越来越复杂时,它的内存管理也会变得越来越困难.内存泄漏.内存 ...

  6. 如何往IE工具条添加按钮(转载)

    如何往IE工具条添加按钮 问题提出:金山词霸.网络蚂蚁等软件安装后会向IE的工具条添加自己的按钮.按下按钮后还会作出相应的动作,这种功能是如何实现的呢?读完本文,您也可以将自己应用程序的按钮添加到IE ...

  7. JAVA判断32位还是64位,调用不同的DLL(转)

    源:JAVA判断32位还是64位,调用不同的DLL 通过获取sun.arch.data.model可判断是32还是64的JAVA 将32或者64位的DLL放不同的目录,实现自适应调用DLL Prope ...

  8. [zz]VC2005-应用程序正常初始化失败-0xc0150002

    最近几天被这个问题困惑了许久. 不禁感叹微软的东东真是越做越烂了,也终于明白了时隔12年大家仍然死守VC6的原因.. 用VC2005编译的程序,编译时没有任何错误,但是运行时就是提示“应用程序正常初始 ...

  9. 配置Oracle访问SQL地理数据库

    Oracle访问空间数据 ArcSDE是ArcGIS的空间数据引擎,它是在关系数据库管理系统(RDBMS)中存储和管理多用户空间数据库的通路.以前连接方式有两种,服务连接与直接连接(简称"直 ...

随机推荐

  1. (转)VS2008 VMware联合调试

    本文转载自:http://www.cnblogs.com/ziwuge/archive/2012/04/03/2431162.html 一.前期准备: 1. 安装VS2008 2. 安装VM8.0,在 ...

  2. Java-Maven-Runoob:Maven Web 应用

    ylbtech-Java-Maven-Runoob:Maven Web 应用 1.返回顶部 1. Maven Web 应用 本章节我们将学习如何使用版本控制系统 Maven 来管理一个基于 web 的 ...

  3. 转载:细说oracle 11g rac 的ip地址

    本文转载自:细说oracle 11g rac 的ip地址 http://blog.sina.com.cn/s/blog_4fe6d4250102v5fa.html 以前搭建oracle rac的时候( ...

  4. JS比较实用的时间控件

    使用方法: 下载下来压缩包,文件的地方不要改变,就可以了 http://www.my97.net/dp/down.asp html的代码: <input readonly="reado ...

  5. java中的 equals 与 ==

    Java中的"=="永远比较的是两个对象是否是同一个对象(引用指向同一块内存就是同一个对象) Java中equals() 在使用必须与类挂上钩,不能单独使用.有的人这样理解&quo ...

  6. 一个页面中内嵌页面 iframe元素

    iframe.html: <!DOCTYPE html><html lang="en"><head> <meta charset=&quo ...

  7. 【原创】7. MYSQL++中的查询结果获取(各种Result类型)

    在本节中,我将首先介绍MYSQL++中的查询的几个简单例子用法,然后看一下mysqlpp::Query中的几个与查询相关的方法原型(重点关注返回值),最后对几个关键类型进行解释. 1. MYSQL++ ...

  8. 【HDU 6031]】 Innumerable Ancestors

    题意 有一棵有n个结点的树,这里有m个询问,每个询问给出两个非空的结点集合A和B,有些结点可能同时在这两个集合当中.你需要从A和B中分别选择一个节点x和y(可以是同一个结点)你的目标是使LCA(x,y ...

  9. 使用Dom4j操作XML数据

    --------------siwuxie095                             dom4j 是一个非常优秀的 Java XML 的 API, 用来读写 XML 文件 和操作 ...

  10. Solidity oraclize query apikey加密

    solidity 程序中如果用到oraclize query,api调用需要apikey,则最好加密apikey,否则公开solidity代码时会连同apikey一起公开. 加密方法: https:/ ...