shuai 的个人资料娱乐精神照片日志 工具 帮助
2007/10/26

强暴.net程序集 之五 (#~流的元数据表)

 
警告:本系列文章为本人原创,只作技术研究之用,您可以引用链接传播,禁止其它的转载方式,禁止用于商业或非法目的, 对于造成的一切后果本人概不负责

#~流是保存元数据的地方, 元数据以表的形式进行组织
当找到#~流之后,我们需要先得到元数据表的基本信息, 用于推算出每个表的位置
这个#~流的顶部格式是:
typedef struct _META_COMPOSITE_HEADER
{
    DWORD Reserved; 
    BYTE MajorVersion;
    BYTE MinorVersion;
    BYTE HeapSizes;
    BYTE Padding;
    ULONGLONG Valid;
    ULONGLONG Sorted;
} META_COMPOSITE_HEADER, *PMETA_COMPOSITE_HEADER;

在Partition II Metadata描述为:
Offset   Size     Field         Description
0        4        Reserved      Reserved, always 0 (§24.1).
4        1        MajorVersion  Major version of table schemata; shall be 2 (§24.1).
5        1        MinorVersion  Minor version of table schemata; shall be 0 (§24.1).
6        1        HeapSizes     Bit vector for heap sizes.
7        1        Reserved      Reserved, always 1 (§24.1).
8        8        Valid         Bit vector of present tables, let n be the number of bits that are 1.
16       8        Sorted        Bit vector of sorted tables.
24       4*n      Rows          Array of n 4-byte unsigned integers indicating the number of rows for each present table.
24+4*n            Tables        The sequence of physical tables.

最值得注意是
Valid字段,它的每一位代表了相应的元数据表是否存在,比如第21位表示Assembly表存在(索引编号为0x20,对应关系见TableType)
typedef enum TableType
{
    Module          = 0x00,
    TypeRef         = 0x01,
    TypeDef         = 0x02,
    FieldDef        = 0x04,
    MethodDef       = 0x06,
    ParamDef        = 0x08,
    //略
    Assembly        = 0x20,
    //略
    Unassigned      = -1
} TableType;

Rows数组的大小为有效表的个数,每一个Rows元素记录了该表的记录的行数
Tables是实际元数据表的起始位置

通过计算记录行数和每行大小可以得到每个表的地址

tableID = 0;
valid = compositeTable->Valid;
PDWORD rows = (PDWORD)(compositeTable + 1); //Rows的位置
PBYTE address = (PBYTE)(rows + tableCount); //第一个表的位置
while(valid)
{
 if(valid & 0x1)
 {
  tables[(TableType)tableID] = tableEntry;
  tables[(TableType)tableID].Address = address;
  tables[(TableType)tableID].Table = (TableType)tableID;
  tables[(TableType)tableID].Rows = rows[tableCount];
  tables[(TableType)tableID].HeapSizes = compositeTable->HeapSizes;
  tables[(TableType)tableID].Address = address;
  tables[(TableType)tableID].RowSize = TableRowSizes((TableType)tableID);

  //下一个表的位置
  address += tables[(TableType)tableID].RowSize * tables[(TableType)tableID].Rows;
 }
 valid = valid >> 1;
 tableID++;
}

上面程序有一个TableRowSizes函数用于计算某个表的行大小, 它将放在下一篇文章去描述

当然如果要使用元数据接口就更加方便, 可以调用 IMetaDataTables::GetTableInfo
获取位于指定表索引处的表的行大小、名称、行数和列数。
    HRESULT GetTableInfo (
        ULONG       ixTbl,
        ULONG       *pcbRow,
        ULONG       *pcRows,
        ULONG       *pcCols,
        ULONG       *piKey,
        const char  **ppName
    );
参数       说明 
ixTbl   [in]   要返回其属性的表的索引。
pcbRow  [out] 表行的大小(以字节为单位)。
pcRows  [out] 表中的行数。
pcCols  [out] 表中的列数。
piKey   [out] 键列的索引,或在表没有键列时为 -1。
ppName  [out] 表名称。

以及 IMetaDataTables::GetNumTables
获取在当前 IMetaDataTables 实例范围内的表个数。
    HRESULT GetNumTables (
        ULONG   *pcTables
    );
参数        说明 
pcTables [out] 在当前实例范围内的表的计数。

在ildasm中的dasm.cpp文件DumpStatistics 和 DumpTable 函数有一个实际调用的示例
g_pPubImport->QueryInterface(IID_IMetaDataTables, (void**)&pITables))
pITables->GetNumTables(&count);
pITables->GetTableInfo(TBL_Method, &sizeRec, NULL, NULL, NULL, NULL);

 

2007/9/28

那些声音和记忆

好吧我承认我又怀旧了
当离开我遥远的歌曲又回放的时候
记忆片断又再次浮现
有青春的残酷和爱

有些场景是永远无法抹去
宿命般的
就算沉在深处
但音乐就是有这样力量
它只要在某时某地回响
好像神灵的咒语一般
你就能恢复那时的感觉
那时的幸福感
喜悦, 无助, 感动
或是哀伤

好在我还不讨厌这种感觉

那一年他们单飞
一个世界, 分开的两个人
他叫光良 他叫品冠

 

2007/8/27

理解需求的本质

试想一个案例
历史(或聊天)记录是IM软件通常都具备的功能
“我们的产品需要一个历史记录功能”
这是以产品角度去考虑
实际上过早的提出了解决方案
这是解决方案,不是需求


为什么要有历史记录的功能
它的功能的本质是解决什么问题
是因为使用者会忘记以前聊天的内容
所以需要有某种方法进行回顾
这才是需求的本质


理解需求本质之后才应该提出解决方案
否则会提出错误的解决方案
或是错过了更好的解决方案
试想IM是否能提供一个更好的提示方法
比如当聊到某一特定内容时
自动列出之前的相关聊天信息
这是一个主动显示聊天记录的方案


理解需求的本质,而不要过早提出解决方案

 

2007/8/2

自定义窗体最大化时不盖住任务栏

 
自定义窗体最大化时不盖住任务栏
还原有时有问题,不管了
        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case WM_GETMINMAXINFO:
                    RECT area = new RECT();
                    SystemParametersInfo(SPI_GETWORKAREA, 0, ref area, 0);
                    MINMAXINFO info = (MINMAXINFO)m.GetLParam(typeof(MINMAXINFO));
                    info.ptMaxSize = new POINT(area.right, area.bottom);
                    info.ptMaxPosition = new POINT(0, 0);
                    info.ptMaxTrackSize = new POINT(area.right, area.bottom);
                    info.ptMinTrackSize = new POINT(100, 200);
                    Marshal.StructureToPtr(info, m.LParam, true);
                    m.Result = new IntPtr(0);       //must return 0;
                    return;
            }
           
            base.WndProc(ref m);

        } 
2007/7/12

清纯与性感


当我还是小孩的时候
我对宏定义和匈牙利命名,甚至是模版有莫名的感觉
是觉得它们丑陋么
年幼的我一直离她们远远的
那真是青涩少年
 
2007年
我越发对C#的清纯容颜感到不满
她太纯洁了
虽然很美
但时间长了没有味道
一开始的初恋感觉没有了
 
而那些性感的女郎们
黑色网袜
偶尔说两句脏话
或是抽抽烟
亦或是露出臂下的淡淡腋毛
那真是性感和迷人
 
hr = CoCreateInstance(CLSID_CSexy,
                           NULL,
                           CLSCTX_INPROC_SERVER,
                           IID_ISexy,
                           (void **) &pSexy);
if (SUCCEEDED(hr))
{
     pSexy->Attract(&me);
}
 
然而
Virgin v = new Virgin()
me.Say(v, "but, I still love you.");
2007/7/8

我想化成夏雨

我想化成夏雨
打湿你的白衣
溶入你肌体
溶入溶入
和你有同的温婉
化作一体
 
我想化成花尘
粘上你的白衣
溶入你肌体
溶入溶入
和你有同的芬香
和你是一体
 
在你心里写上铭记
以诗句作誓言
忘记生我的云朵
放弃我飘向的目的
一直和你在一起
 
 

有种痛苦叫思念

有种痛苦叫思念
思念
  思念
只分隔一秒就留恋
一秒就像千年
十指分开灵魂却相牵
在梦里缠绵

有种痛苦叫思念
思念
  思念
令心绪破茧
思念像箭
燃烧了我的冷淡
思念像火焰
 
 
 
 
2007/2/13

同步!! 不同!!

 

原子操作
 
InterlockedIncrement 和 InterlockedDecrement
相当于
Interlocked.Increment 和 Interlocked.Decrement
 
InterlockedExchange 和 InterlockedCompareExchange
相当于
Interlocked.Exchange 和 Interlocked.CompareExchange
 
 
线程
WaitForSingleObject(hThread, INFINITE)
相当于
thread.Join(Timeout.Infinite)
 
WaitForMultipleObject(n, hThreads, TRUE, INFINITE)
没有相对应的
(试试Manual/AutoResetEvent.WaitAll 和 Monitor.Wait)
 
SuspendThread(hThread) 和 ResumeThread(hThread)
相当于
thread.Suspend 和 thread.Resume()
 

关键段
EnterCriticalSection(&cs)
有点像
Monitor.Enter(object)
 
LeaveCriticalSection(&cs)
有点像
Monitor.Exit(object)
 
TryEnterCriticalSection(&cs)
有点像
Monitor.TryEnter(object)
 

事件对象
HANDLE hEvent = CreateEvent(&sa, TRUE, fInitialState, szName)
相当于
ManualResetEvent event = new ManualResetEvent(initialState)
 
HANDLE hEvent = CreateEvent(&sa, FALSE, fInitialState, szName)
相当于
AutoResetEvent event = new AutoResetEvent(initialState)
 
SetEvent(hEvent) 和 ResetEvent(hEvent)
相当于
event.Set() 和 event.Reset()
 
WaitForSingleObject(hEvent, INFINITE)
相当于
event.WaitOne()
 
WaitForMuSingleObject(n, hEvents, TRUE, INFINITE)
相当于
Manual/AutoResetEvent.WaitAll(events)
 
WaitForMultipleObject(n, hEvents, FALSE, INFINITE)
相当于
Manual/AutoResetEvent.WaitAny(events)

 
2007/1/16

让MessageQueue.BeginReceive()阻塞

 
让MessageQueue.BeginReceive()阻塞
我发现MessageQueue.BeginReceive()跟本不会阻塞
虽然文档上是这样写:
启动一个没有超时设定的异步接收操作。直到队列中出现消息时,才完成此操作。
但是事实证明不起作用
并且希望做到事件式触发
以及接收消息完一个后接收消息下一个
于是我使用了ManualResetEvent:
代码:
    public class Program
    {
        private static ManualResetEvent signal = new ManualResetEvent(false);       
        public static void Main()
        {
            ReceiveMessage();
        }
        public static void ReceiveMessage()
        {
            try
            {
                MessageQueue messageQueue = new MessageQueue(".\\Private$\\StaticPageQueue");
                messageQueue.Formatter = new BinaryMessageFormatter();
                messageQueue.ReceiveCompleted += new ReceiveCompletedEventHandler(ReceiveCompleted);
                while (true)
                {
                    Console.WriteLine("Receiving...");
                    messageQueue.BeginReceive();
                    signal.Reset();            //允许线程阻止
                    signal.WaitOne();        //阻止当前线程。直到收到信号
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
        private static void ReceiveCompleted(Object sender, ReceiveCompletedEventArgs asyncResult)
        {
            try
            {
                MessageQueue messageQueue = (MessageQueue)sender;
                Message message = messageQueue.EndReceive(asyncResult.AsyncResult);
                StaticPageMessage spMessage = (StaticPageMessage)message.Body;
                   
                Console.WriteLine(spMessage.StaticPageType);
                signal.Set();        //允许阻塞线程继续
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
    }
2006/12/21

密室杀人

杀人魔术夜色中上演
死神也未看到真凶一面
没有脚印,没有指纹
封禁的密室如何逃脱
手法高超无声无息
只留下炉火中烧焦的手卷
真相就在此刻迷失
 
 
画中的三口棺材意味深长
死人从地下复活的传说
有内幕重重的手足相残
每个人所言说的谎言
贝克街的夏洛克也只能茫然
面具下的恶灵将正义埋葬
 
 
邪恶之手再次指向深渊
暗暗小巷上演第二幕凶案
开阔空间上演密室杀人手法
戏剧般开场,又戏剧般结束
泰晤士河流淌着亡灵的鲜血
和着肖邦惆怅的夜曲
在月光下浸着伤痛哀唱
 
 
卡尔笔下的神探
划破夜空揭开光芒
真理以微笑溶化了迷雾
华丽的残酷从此止伤
西敏寺的慰藉钟声回响
在白色的雪上写下了安详
2006/12/20

放假

请注意看
 
12月30日(星期六)、12月31日(星期日)仍正常上班
01月01日(星期一)、01月02日(星期二)、01月03日(星期三)放假
 
这意味着又要上倒霉的、疲惫的、绝望的,连续七天的班
 
我不禁想骂两句
不过突然又想起我还有三天年假没休呢
 
哇哈哈
 
2006/10/21

基地系列之一《基地》


虽然我现在仍还会认为心理史学是一门统计学
只不过需要考虑相当多的变量:
政治、宗教、经济、科技的发展等等
我觉得,这门学科名字中的“心理”
或许指的是这些因素对于社会心理的影响吧
而社会心理则将影响历史的进程
 
作为这门学科的创始人
或许也是唯一真正能够应用的人
谢顿预言到了银河帝国即将分裂
从而进入长达三万年的黑暗的战乱时期
为了缩短这个时间
他指入了一个变量
这就是基地
基地使命就是传承人类的文明与科技
来重建银河
 
值得赞叹的是
谢顿预计到了基地在发展中需要遇到种种危机
而这些危机实际上会促进基地的发展
第一次
基地受到银河边缘的四个国家的武力威胁
哈定利用这些国家的相互制约化解了危机
并以先进的技术影响这些国家
第二次
哈定将技术以宗教面目控制这四个国家
化解了企图进攻基地的第二次危机
第三次
其他国家禁止基地的宗教进入该国
马洛以行商的身份同这些国家进行贸易
使用它们在经济上依赖于基地
从而化解了企图进攻基地的第三次危机
 
简单的说就是利用了:势力均衡、宗教崇拜、贸易依赖
所以这书活脱脱的就是一部分社会发展史
书中的政党矛盾、篡权野心等等又像是一部政治大戏
让人不得为阿西莫夫的宏大知识赞叹
不过书中描写的未来技术确实让人失望
毕竟作者写作本书时才刚刚产生电脑和原子弹嘛
 
 
 
 
 

 
2006/10/3

让CTRL+C无法中止控制台程序

 
为了玩深CLR Host
我又从win32api重新开始...
 
win32api确实很赞
我没有看错它
 
原来我一直在写梨花体
因为
我是一个诗人
 
 
#include <windows.h>
#include <tchar.h>
static BOOL WINAPI Handler(DWORD ctrlEvent);
static BOOL bExit = FALSE;
int main(int argc, char *argv[])
{
 if (!SetConsoleCtrlHandler(Handler, TRUE))
 {
  LPTSTR lpvSysMsg;
  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
   GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpvSysMsg, 0, NULL);
  _tprintf(_T("设置事件句柄时出错: %s\n"), lpvSysMsg);
 } 
 
 while (!bExit)
 {
  _tprintf(_T("不断输出不断输出...\n"));
  Sleep(1000);
 }
 
 return 0;
 
}

BOOL WINAPI Handler(DWORD ctrlEvent)
{
 bExit = FALSE;
 switch (ctrlEvent)
 {
  case CTRL_C_EVENT:
   _tprintf (_T ("你按了CTRL+C\n"));
   return TRUE;
  case CTRL_BREAK_EVENT:
   _tprintf (_T ("你按了CTRL+BREAK\n"));   
   return TRUE;
 }
}
2006/9/12

Windows Data Types

 

来源:MSDN

The data types supported by Microsoft® Windows® are used to define function return values, function and message parameters, and structure members. They define the size and meaning of these elements.

The following table contains the following types: character, integer, Boolean, pointer, and handle. The character, integer, and Boolean types are common to most C compilers. Most of the pointer-type names begin with a prefix of P or LP. Handles refer to a resource that has been loaded into memory. For more information about handling 64-bit integers, see Large Integers.

Data Types

Value Meaning
ATOM Atom. For more information, see Atoms.
BOOL Boolean variable (should be TRUE or FALSE).
BOOLEAN Boolean variable (should be TRUE or FALSE).
BYTE Byte (8 bits).
CALLBACK Calling convention for callback functions.
CHAR 8-bit Windows (ANSI) character. For more information, see Character Sets Used By Fonts.
COLORREF Red, green, blue (RGB) color value (32 bits). See COLORREF for information on this type.
CONST Variable whose value is to remain constant during execution.
CRITICAL_SECTION Critical-section object. For more information, see Critical Section Objects.
DWORD 32-bit unsigned integer.
DWORD_PTR Unsigned long type for pointer precision. Use when casting a pointer to a long type to perform pointer arithmetic. (Also commonly used for general 32-bit parameters that have been extended to 64 bits in 64-bit Windows. )
DWORD32 32-bit unsigned integer.
DWORD64 64-bit unsigned integer.
FLOAT Floating-point variable.
HACCEL Handle to an accelerator table.
HANDLE Handle to an object.
HBITMAP Handle to a bitmap.
HBRUSH Handle to a brush.
HCONV Handle to a dynamic data exchange (DDE) conversation.
HCONVLIST Handle to a DDE conversation list.
HCURSOR Handle to a cursor.
HDC Handle to a device context (DC).
HDDEDATA Handle to DDE data.
HDESK Handle to a desktop.
HDROP Handle to an internal drop structure.
HDWP Handle to a deferred window position structure.
HENHMETAFILE Handle to an enhanced metafile.
HFILE Handle to a file opened by OpenFile, not CreateFile.
HFONT Handle to a font.
HGDIOBJ Handle to a GDI object.
HGLOBAL Handle to a global memory block.
HHOOK Handle to a hook.
HICON Handle to an icon.
HIMAGELIST Handle to an image list.
HIMC Handle to input context.
HINSTANCE Handle to an instance.
HKEY Handle to a registry key.
HKL Input locale identifier.
HLOCAL Handle to a local memory block.
HMENU Handle to a menu.
HMETAFILE Handle to a metafile.
HMODULE Handle to a module. The value is the base address of the module.
HMONITOR Handle to a display monitor.
HPALETTE Handle to a palette.
HPEN Handle to a pen.
HRGN Handle to a region.
HRSRC Handle to a resource.
HSZ Handle to a DDE string.
HWINSTA Handle to a window station.
HWND Handle to a window.
INT 32-bit signed integer.
INT_PTR Signed integral type for pointer precision. Use when casting a pointer to an integer to perform pointer arithmetic.
INT32 32-bit signed integer.
INT64 64-bit signed integer.
LANGID Language identifier. For more information, see Locales.
LCID Locale identifier. For more information, see Locales.
LCTYPE Locale information type. For a list, see Locale and Language Information.
LONG 32-bit signed integer.
LONG_PTR Signed long type for pointer precision. Use when casting a pointer to a long to perform pointer arithmetic.
LONG32 32-bit signed integer.
LONG64 64-bit signed integer.
LONGLONG 64-bit signed integer.
LPARAM Message parameter.
LPBOOL Pointer to a BOOL.
LPBYTE Pointer to a BYTE.
LPCOLORREF Pointer to a COLORREF value.
LPCRITICAL_SECTION Pointer to a CRITICAL_SECTION.
LPCSTR Pointer to a constant null-terminated string of 8-bit Windows (ANSI) characters. For more information, see Character Sets Used By Fonts.
LPCTSTR An LPCWSTR if UNICODE is defined, an LPCTSTR otherwise.
LPCVOID Pointer to a constant of any type.
LPCWSTR Pointer to a constant null-terminated string of 16-bit Unicode characters. For more information, see Character Sets Used By Fonts.
LPDWORD Pointer to a DWORD.
LPHANDLE Pointer to a HANDLE.
LPINT Pointer to an INT.
LPLONG Pointer to a LONG.
LPSTR Pointer to a null-terminated string of 8-bit Windows (ANSI) characters. For more information, see Character Sets Used By Fonts.
LPTSTR An LPWSTR if UNICODE is defined, an LPSTR otherwise.
LPVOID Pointer to any type.
LPWORD Pointer to a WORD.
LPWSTR Pointer to a null-terminated string of 16-bit Unicode characters. For more information, see Character Sets Used By Fonts.
LRESULT Signed result of message processing.
LUID Locally unique identifier.
PBOOL Pointer to a BOOL.
PBOOLEAN Pointer to a BOOL.
PBYTE Pointer to a BYTE.
PCHAR Pointer to a CHAR.
PCRITICAL_SECTION Pointer to a CRITICAL_SECTION.
PCSTR Pointer to a constant null-terminated string of 8-bit Windows (ANSI) characters. For more information, see Character Sets Used By Fonts.
PCTSTR A PCWSTR if UNICODE is defined, a PCSTR otherwise.
PCWCH Pointer to a constant WCHAR.
PCWSTR Pointer to a constant null-terminated string of 16-bit Unicode characters. For more information, see Character Sets Used By Fonts.
PDWORD Pointer to a DWORD.
PFLOAT Pointer to a FLOAT.
PHANDLE Pointer to a HANDLE.
PHKEY Pointer to an HKEY.
PINT Pointer to an INT.
PLCID Pointer to an LCID.
PLONG Pointer to a LONG.
PLUID Pointer to a LUID.
POINTER_32 32-bit pointer. On a 32-bit system, this is a native pointer. On a 64-bit system, this is a truncated 64-bit pointer.
POINTER_64 64-bit pointer. On a 64-bit system, this is a native pointer. On a 32-bit system, this is a sign-extended 32-bit pointer.
PSHORT Pointer to a SHORT.
PSTR Pointer to a null-terminated string of 8-bit Windows (ANSI) characters. For more information, see Character Sets Used By Fonts.
PTBYTE Pointer to a TBYTE.
PTCHAR Pointer to a TCHAR.
PTSTR PWSTR if UNICODE is defined, a PSTR otherwise.
PTBYTE Pointer to a TBYTE.
PTCHAR Pointer to a TCHAR.
PTSTR A PWSTR if UNICODE is defined, a PSTR otherwise.
PUCHAR Pointer to a UCHAR.
PUINT Pointer to a UINT.
PULONG Pointer to a ULONG.
PUSHORT Pointer to a USHORT.
PVOID Pointer to any type.
PWCHAR Pointer to a WCHAR.
PWORD Pointer to a WORD.
PWSTR Pointer to a null-terminated string of 16-bit Unicode characters. For more information, see Character Sets Used By Fonts.
REGSAM Security access mask for registry key.
SC_HANDLE Handle to a service control manager database. For more information, see SCM Handles.
SC_LOCK Handle to a service control manager database lock. For more information, see SCM Handles.
SERVICE_STATUS_HANDLE Handle to a service status value. For more information, see SCM Handles.
SHORT Short integer (16 bits).
SIZE_T The maximum number of bytes to which a pointer can point. Use for a count that must span the full range of a pointer.
SSIZE_ T Signed SIZE_T.
TBYTE A WCHAR if UNICODE is defined, a CHAR otherwise.
TCHAR A WCHAR if UNICODE is defined, a CHAR otherwise.
UCHAR Unsigned CHAR.
UINT Unsigned INT.
UINT_PTR Unsigned INT_PTR.
UINT32 Unsigned INT32.
UINT64 Unsigned INT64.
ULONG Unsigned LONG.
ULONG_PTR Unsigned LONG_PTR.
ULONG32 Unsigned LONG32.
ULONG64 Unsigned LONG64.
ULONGLONG 64-bit unsigned integer.
UNSIGNED Unsigned attribute.
USHORT Unsigned SHORT.
VOID Any type.
WCHAR 16-bit Unicode character. For more information, see Character Sets Used By Fonts.
WINAPI Calling convention for system functions.
WORD 16-bit unsigned integer.
WPARAM Message parameter.
2006/8/30

难以理解的错误

今天我的程序出现了这个问题,比较绕:
A程序:建立了一个AppDomain, 在这个AppDomain中调用一个MarshalByRefObject的子类---B类
然后,我将A程序写入字节流保存
C程序将A程序从字节流中还原,并动态调用A程序中的方法,这时将报A程序中的B类无法加载的错误
 
一句话就是,反射调用的程序集中的其它应用程序域中的类无法调用
(为什么是其它应用程序域?因为A程序中的默认应用程序域中的其它类我都可以调用。)
看来序列化(MarshalByRefObject)有很多限制

这只是初步的想法,还需要证实一下
 
-----------------------------------------------------
解决了:
我把
AppDomain.CreateInstanceAndUnwrap(Assembly.GetCallingAssembly().FullName, typeof(TargetType).FullName);中的
Assembly.GetEntryAssembly()
换成了
Assembly.GetCallingAssembly()
 
不过又出现了无法将透明代理转换为目标类的错误,不过这下总算放心了
 
2006/8/27

得到PE文件信息 (下)


三、使用函数:
首先使用imagehlp.dll中的函数MapAndLoad
函数MapAndLoad将一个映像文件映射到虚拟地址空间中,并填充结构LOADED_IMAGE
定义如
下BOOL MapAndLoad(
   IN LPSTR ImageName,
   IN LPSTR DllPath,
   OUT LOADED_IMAGE LoadedImage,
   IN BOOL DotDll,
   IN BOOL ReadOnly
);
另外还有相对应的函数UnMapAndLoad

为了由相对虚拟地址得到虚拟地址,使用ImageRvaToVa:
LPVOID ImageRvaToVa(
   IN IMAGE_PE_FILEHEADER NtHeaders,
   IN LPVOID Base,
   IN DWORD Rva,
   IN OUT IMAGE_SECTION_HEADER *LastRvaSection
);
这个函数返回的是虚拟内存地址
四、得到导出名(VB代码仅供示例,无法运行):
'LOADED_IMAGE结构定义如下:
Public Type LOADED_IMAGE      '48个字节
   ModuleName As Long
   hFile As Long
   MappedAddress As Long      '映射文件基址
   pFileHeader As Long         'IMAGE_PE_FILE_HEADER的指针
   pLastRvaSection As Long      '第一个COFF段文件头的指针   ??
   NumberOfSections As Long
   pSections As Long         '第一个COFF段文件头的指针
   Characteristics As Long      '映像特征值
   fSystemImage As Byte
   fDosImage As Byte
   Links As LIST_ENTRY         '2个长整型
   SizeOfImage As Long
End Type
'检查&H3C偏移处是否为&H4550(PE文件标记)
Get #fr, &H3C+1, bSigOffset
Get #fr, bSigOffset+1, iSignature
If Not iSignature = &H4550 Then
   '非PE文件
   Close fr
   Exit Function
End if
'将文件映射到内存,并填充LOADED_IMAGE
Dim loadimage As LOADED_IMAGE
lret = MapAndLoad(sFile, "", loadimage, True, True)
'得到映像的基址
baseaddr = loadimage.MappedAddress
'将PE头复制到我们自已的变量peheader中
Dim peheader As IMAGE_PE_FILE_HEADER
CopyMemory ByVal VarPtr(peheader), ByVal loadimage.pFileHeader, 256
'由第一个数据目录的相对虚拟地址得到虚拟地址
rvaExportDirTable = peheader.OptionalHeader, DataDirectory(IMAGE_DIRECTORY_ENTRY_EXPORT).RVA
vaExportDirTable = ImageRvaToVa(loadimage.pFileHeader, loadimage.MappedAddress, rvaExportDirTable, 0&)
'将导出表复制出来
Dim exportdir As IMAGE_EXPORT_DIRECTORY_TABLE
CopyMemory ByVal VarPtr(exportdir), ByVal vaExportDirTable, LenB(exportdir)
'现在exportdir.ExportNamePointerTableRVA是这个导出名指针表的相对虚拟地址,我们转成虚拟地址
ExportNamePointerTableVa = ImageRvaToVa(loadimage.pFileHeader, loadimage.MappedAddress, exportdir.ExportNamePointerTableVa, 0&)
'输出导出表
pNextAddress = ExportnamePointerTableVa      '从起点开始
VBGetTaget lNextAddress, pNextAddress, 4   '得到下一个地址
For i=0 To exportdir.NumberOfNames
   '将该名称地址由相对虚拟地址转为虚拟地址
   lNextAddress =  ImageRvaToVa(loadimage.pFileHeader, loadimage.MappedAddress, lNextAddress, 0&)  
   sName = LPSTRtoBSTR(lNextAddress)   '将ANSI转为BSTR,得到名称
   pNextAddress = pNextAddress + 4      '指向表的下一个地址
   VBGetTarget lNextAddress, pNextAddress, 4   '得到地址
Next
'最后调用UnMapAndLoad

得到PE文件信息 (上)

一、PE文件格式:
1)PE文件头:
   MS-DOS占位符
   PE标记
   COFF文件头
   可选文件头(它并不是可选的,提供加栽器的信息):
      标准字段
      Windows专有字段
      数据索引表:它用来得到导出和导入表的相对虚拟地址
2)段表:是段的头,注意所有这些段头是相连的,段表的项目数目是通过COFF的NumberOfSections字段给出
3)段:
      正文段(.text 包括执行代码)
      数据段(.bss、.rdata、.data 包括文字串和常量)
      资源段(.rsrc)
      重定位段(.reloc 回填项目,即记录实际加载时基地址的调整)
      导出段(.edata 包括所有的导出函数和全局变量信息,由一个导出目录表开始)
      导入段(.idata 包括了文件导入的函数信息)


二、结构

'没有MS-DOS占位程序的PE文件头
Public Type IMAGE_PE_FILE_HEADER   '256个字节
   Signature As Long            'PE文件标记,4个字节
   FileHeader As IMAGE_COFF_HEADER   'COFF文件头,20个字节
   OptionalHeader As IMAGE_OPTIONAL_HEADER   '可选头,232个字节
End Type


'COFF文件头
Public Type IMAGE_COFF_HEADER      '20个字节
   Machine As Integer            '处理器类型
   NumberOfSections As Integer      '段的数目
   TimeDateStamp As Long         '文件建立时间
   PointerToSymbolTable As Long   'COFF文件符号表的偏移
   NumberOfSymbols As Long         '符号表中项目个数,可以用来定位字符串表它紧跟着符号表
   SizeOfOptionalHeader As Integer   'PE文件可选头的大小
   Characteristics As Integer
End Type

Public Type IMAGE_OPTIONAL_HEADER   '232个字节
   '标准字段
   Magic As Integer
   MajorLinkerVersion As Byte
   MinorLinkerVersion As Byte
   SizeOfCode As Long
   SizeOfInitializedData As Long
   AddressOfEntryPoint As Long
   BaseOfCode As Long
   BaseOfData As Long

   'Windows字段
   ImageBase As Long
   SectionAlignment As Long
   FileAlignment As Long
   MajorOperatingSystemVersion As Integer
   MinorOperatingSystemVersion As Integer
   MajorImageVersion As Integer
   MinorImageVersion As Integer
   MajorSubsystemVersion As Integer
   MinorSubsystemVersion As Integer
   Win32VersionValue As Long
   SizeOfImage As Long
   SizeOfHeaders As Long
   CheckSum As Long
   Subsystem As Integer
   DllCharacteristics As Integer
   SizeOfStackReserve As Long
   SizeOfStackCommit As Long
   SizeOfHeapReserve As Long
   SizeOfHeapCommit As Long
   LoaderFlags As Long
   NumberOfRvaAndSizes As Long      '96

   '数据目录(数据索引表)
   DataDirectory(0 To IMAGE_NUMBEROF_DIRECTORY_ENTRIES) As IMAGE_DATA_DIRECTORY      '17*8+96=232
End Type

'数据目录
Public Type IMAGE_DATA_DIRECTORY   '8字节
   RVA As Long
   Size As Long
End Type


'导出表
Public Type IMAGE_EXPORT_DIRECTORY_TABLE   '40字节
   Characteristics As Long            '导出标志(保留)
   TimeDateStamp As Long            '导出数据的时间
   MajorVersion As Integer
   MinorVersion As Integer
   Name As Long                  '包含这个DLL名称字符串的相对虚拟地址
   Base As Long                  '导出地址表的导出开始的序号
   NumberOfFunctions As Long        
   NumberOfNames As Long            '导出地址表中项目个数
   pAddressOfFunctions As Long         '导出地址表的相对虚拟地址
   ExportNamePointerTableRva As Long   '导出名称指针表的相对虚拟地址(保存了导出名称表位置)
   pAddressOfNameOrdinals As Long      '序号表的相对虚拟地址
End Type

 

2006/8/14

C#泛型-小心使用静态成员变量

旧贴转过来:
 
对于泛型类的声明
其中使用类型参数的构造类型,比如List<T>被称为开放构造类型(open constructed type)
而不使用类型参数的构造类型,例如List<int>被称为封闭构造类型(closed constructed type)。
特别要强调的是不同类型参数的封闭构造类型之间是不共享静态成员变量的。

举个例子

using System;

public class List<T>
{  
    public List(T t)
    {
        _value = t;
        _closedCount++;
    }

    public T Value
    {
        get { return _value; }
    }

    public int ClosedCount
    {
        get { return _closedCount; }
    }

    public static int StaticCount
    {
        get { return _closedCount; }
    }


    private T _value;
    private static int _closedCount = 0;
}

public class Test
{
    static void Main()
    {
        List<double> list1 = new List<double>(3.14);
        Console.WriteLine("List1 Value: {0} \t Closed Count: {1}", list1.Value, list1.ClosedCount);

        List<double> list2 = new List<double>(0.618);
        Console.WriteLine("List2 Value: {0} \t Closed Count: {1}", list2.Value, list2.ClosedCount);

        List<string> list3 = new List<string>("divino");
        Console.WriteLine("List3 Value: {0} \t Closed Count: {1}", list3.Value, list3.ClosedCount);

        Console.WriteLine();

        Console.WriteLine("List<double> Count: {0}", List<double>.StaticCount);
        Console.WriteLine("List<string> Count: {0}", List<string>.StaticCount);
    }
}

输出结果:
List1 Value: 3.14         Closed Count: 1
List2 Value: 0.618        Closed Count: 2
List3 Value: divino       Closed Count: 1

List<double> Count: 2
List<string> Count: 1

其中:
list1与list2同为List<double>,它们之间共用静态成员_closedCount
而类型为List<string>的list3不能使用_closedCount
我们从最后两行的输出也可看出结果
即:不同类型参数的封闭构造类型之间是不共享静态成员变量的。

 

2006/7/31

X的悲剧和Y的悲剧

最近一口气看完了X的悲剧和Y的悲剧
这是奎恩的推理名篇
这两个小说的共同之处
就是都有一个无法想到的凶手
这个凶手属于不被人关注的角落角色
所以当我看到迷底时被深深震撼了
而这种震撼
是不同于看了行人的馆系列后的被骗之感
是彻底的折服和赞叹
 
同Y的悲剧相比
X的悲剧更有可读性和故事性
所以非常具有阅读时的吸引感
和可重复阅读性
当小说已经进入尾声
而我仍还在云里雾里
当看雷恩化妆成死者隆斯崔戏剧性的抓到凶手后
我真是被突然出现的凶手震撼
原来是他,那个角落角色
我无论如何无法想到
而雷恩早在隆斯崔被杀后就知道了
我却没有注意到那个细节
 
Y的悲剧的故事性相比就逊色一些
奎恩故意把让读者引向了错误判断:
凶手误杀错了人、死者儿女们的遗产纠纷
以及那位值得怀疑的身份的家庭教师
在最后,雷恩说凶手已经死了,并揭露迷底时
我被压抑了几章的不爽之感彻底喷发
由此Y的悲剧更像是黄金时代的推理小说
(本来就是黄金时代的推理小说)
----用19章的压抑换来一章的畅快
现在我非常期待奎恩的另一名篇
希腊棺材之谜
2006/7/24

Endless Sadness

上次看完NANA
我的心理就出现了问题
 
今天又听到Endless Story
NANA的插曲
我觉得比中岛的Glamorous Sky有力量多了
青春的残酷
辗转迷茫
温暖而坚定
全部浸入在那曲子的每个音符中
我的心理就又出现了问题
 
是不是因为追逐而放弃的太多了
 
if you haven't change your mind
想要你在身边 tonight
早已疲倦了逞强
曾经太过年少 everytime i think about you baby
直到现在才能说出口 i miss you
it is hard to say i'm sorry
不为任何人 只为你
唱这首歌
永不完结的story延续在这光芒之中
always 想要告诉你
memories of our time together
不要忘记 留在此刻 don't go away
用温暖融化 只为了确定
点滴的温柔 泛起心中的涟漪
如此的痛苦 i'm missin'you
握紧的手 不要放开
如果可以 希望再次为你 唱这首歌
永不完结的 story 从未消逝的想念
tell me why 请告诉我 直到永远