Nov 16

VS2005出现编译错误: fatal error C1902: Program database manager mismatch; please check your installation

复制3个文件(mspdb80.dll, mspdbsrv.exe and mspdbcore.dll), 从C:Program FilesMicrosoft Visual Studio 8Common7IDE 到 C:Program FilesMicrosoft Visual Studio 8VCbin

即可.其中mspdb80.dll可能会已经存在,无所谓了.

Tags: ,
Nov 11

C++使用 void extern __declspec(dllexport) 函数名()定义的输出函数, 在C#中调用时, 如前文所述, 使用
[DllImport("D:\VS2005Projects\Dev_PetroSim2010b\Dev_AMDBR\Debug\Dev_DR_AMDBR.dll", EntryPoint = "#1")]
public static extern void amDBRSurfaceTensionEX(int compCount, int[] components, int modelID, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] double[] Z, ref int errorID);
来调用.

这里注意的是,定义函数入口点的参数EntryPoint = "#1", C#中有2种方式可以定义入口点, 一种是以序号加前缀"#",这是我一直用的,另一种是用EntryPoint="函数名",这种方法我试了很多次却无法实现,C#编译器总会说在DLL中没有找到函数.

如何找到函数所对应的EntryPoint编号呢?我用的是一个叫DLLExportViewer的软件,可以告诉你各个函数的Ordinal,即编号,照此调用即可,但是问题是,如果原DLL进行编辑之后,增加或减少输出函数之后,各个函数的编号会重新打乱,使原程序无法进行.所以对这种情况,即DLL尚在编辑之中时,还是以函数名作为EntryPoint比较好.

在C:Program FilesMicrosoft Visual Studio 8VCbin目录中,有一个文件dumpbin.exe文件和DLLExportViewer一样可以查看DLL的输出函数,但是在运行时,居然跳出一个错误窗口
查找后发现,mspdb80.dll文件是在C:Program FilesCommon FilesMicrosoft SharedVSA8.0VsaEnv中,将此文件复制到C:Program FilesMicrosoft Visual Studio 8VCbin目录,再运行时错误消失.

查阅dumpbin的输出,发现输出函数说明及如下

ordinal hint RVA name
7 6 0002D591 ?amDBRSurfaceTensionEX@@YAXHPAHHPANAAH@Z = @ILT+1420(?amDBRSurfaceTensionEX@@YAXHPAHHPANAAH@Z)
 

前面的ordinal 7即为函数的输出序号, name列即为可用的函数名,在C#中,改函数声明为如下即可用函数名作为EntryPoint

[DllImport("D:VS2005ProjectsDev_PetroSim2010bDev_AMDBRDebugDev_DR_AMDBR.dll", EntryPoint = "?amDBRSurfaceTensionEX@@YAXHPAHHPANAAH@Z")]
 

============================================

照上述做法,导出函数可以成功,但是在C#中调用却是相当麻烦,因为函数的入口名称太过繁杂且不可理解,因此,还是要解决在C++中的函数输出,以使在C#中能直接以函数名作为入口.

上述问题中,实际上是在C++中函数输出时,默认输出名是使用C++的mangled name, 要使用C的命名方式方可直接使用其输出名,这时,函数输出声明应改为如下:
extern "C" __declspec(dllexport) void amDBREnthalpyEX(int CompCount, int* streamComp, int modelID, double* streamInfo, int& errorID)

这样,可以看到DLLExportViewer的查看结果了,以此方式声明的amDBREnthalpyEX函数和以原方式声明的其他函数的名称的不同如下图所示.

这时,在C#中,就可以以函数名称作为入口点了:
[DllImport("D:VS2005ProjectsDev_PetroSim2010bDev_AMDBRDebugDev_DR_AMDBR.dll", EntryPoint = "amDBREnthalpyEX")]
public static extern void amDBREnthalpyEX(int compCount, int[] components, int modelID, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] double[] Z, ref int errorID);
 

Tags: , ,
Oct 30

数组MARSHALLING 不指定

kcao , 12:14 , 技术 , 评论(0) , 引用(0) , 阅读(4723) , Via 本站原创

在托管代码和本地代码之间传递数组,是interop marshaling中间比较复杂的一个问题。本文从数组的定义开始,介绍数组marshalling的三种方法,并对blittable类型等概念做进一步的讨论。

当托管代码需要和本地代码互操作时,我们就进入了interop的领域。interop的场景形形色色,不变的是我们需要把数据从一个世界marshal到另一个世界。

在讨论数组marshalling之前,请各位和我一起思考一个问题,什么是数组?之所以要讨论这个问题,原因在于不同的术语在不同的语境中含有不同的意思。在使用c语言的时候,我认为数组就是一个指针。但是熟悉c#的朋友可能不同意我的观点,数组是System.Array或者Object[]。我认为,这两种回答都是出自语言领域的正确观点。那么如果有一个项目含有两个模块,一个用本地代码撰写,另一个用托管代码撰写,两者之间的接口要求传递一个数组,这个”数组”包含着怎样的语义呢?我觉得有两点是很重要的:

1. 如何访问数组元素。就好比c语言中的数组指针,c#中的数组引用,都是访问数组必不可少的线索。
2. 数组的大小。数组的大小不仅仅是System.Array.Length。它还可以包括诸如数组的维数,每个维上的启始边界和结束边界。

.NET在marshal数组的时候,很大程度上也是从以上两点出发,架起托管世界和本地代码之间的桥梁。根据操作的具体数据类型不同,数组marshal又可以分为以下两个大类,三个小类,我们分别介绍:

1. 数组作为参数传递
a) c/c++类型的数组
c类型的数组,也就是由指针指明存储空间首地址的数组,是一个自描述很低的数据结构。尽管有些编译器支持在固定偏移量上写入数组的长度,但是因为各个编译器处理的具体方法不同,没有一个标准让CLR来参考。所以我们在marshal一个c类型的数组的时候,不得不用其他方法考虑传递数组的大小,有以下两种:

1) 约定指针数组长度
这种方法需要调用者和被调用者之间有一个约定,给出一个数组长度的固定值。在托管端声明一个interop方法的时候,只需要用SizeConst这个属性,把这个约定告诉CLR。CLR在进行Marshal的时候,会根据这个值,在本地堆上分配相应的空间。

public static extern void Ex([In, Out][MarshalAs(UnmanagedType.LPArray, SizeParamConst=3)]string[] a);

2)通过一个额外的参数指定数组长度
可能有的朋友觉得,约定一个静态的数组长度还不够灵活,希望能够动态的传递数组的长度,从而使得数组marshalling不必受制于固定数组长度的限制。我们先来看普通的函数调用是如何解决这个问题的:caller和callee通过约定一个额外的参数,来传递数组的长度,这可以被视作是一个调用者和被调用者的约定。由于marshalling需要clr的参与,那么就需要把这个约定用clr能够理解的方式,进行扩充,形成一个三方约定。CLR,用属性SizeParamIndex来描述此类约定。

public static extern void Ex2([In, Out][MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)]string[] a,int len);


b) SafeArray
SafeArray是COM引入的数据类型,是一个自描述度很高的数据结构。他可以很清楚的告诉用户,该数组的元素类型,数组包含了多少维,每一维的起始位置和终止位置。所以marshal这类safearray的时候,只需要通过设定属性,告诉CLR,当前array对应的本地代码是safearray即可。举例如下:


public void DumpSafeArrayStringIn( [In][MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_BSTR)]Object[] array);

大家可以看到,SafeArraySubType可以用来指定数组元素的类型


2. 数组作为字段传递
很久以来,对于interop,一直有这样的评价,简单数据结构的marshalling其实并不复杂,但是一旦进入了struct或者class这种你中有我,我中有你的层叠数据结构之后,marshalling就成了bug的温床。所以在这里,我们也要提提数组作为struct/class的一个字段的方法。在这里首先要给这个stuct/class加一个限制,是byval。由于这个限制,大家可以想象的出,CLR在marshal的时候,做的事情是类似于浅copy的内存复制,所以对数组marshal的时候,也就只支持固定长度的数组marshal。

C# 代码复制内容到剪贴板
  1. public class StructIntArray   
  2. {   
  3. [MarshalAs(UnmanagedType.ByValArray, SizeConst=4)]   
  4. public int[] array;   
  5. }  

 


数组作为一种常用的数据结构,各种高级语言都提供了相应的支持,在这些高级语言之间交互操作的时候,数组也是传送集合类型数据的重要结构,希望今天的内容能对大家有所帮助。

Tags: ,
Oct 19

帮老婆的弟媳做一个网站,下载了一份现成的PHP代码,不过都是加了密的.有些改动需要对PHP文件进行,可是发现这份东西是用了ZEND加密的,网上现成的DEZENDER的软件不少,绝大多数是基于黑刀改装的,效果不错,可是都不能对目录结构进行原样复制.找到一份梅花三弄版 DEZENDER据说可以保持原目录结构,可是不知是什么原因,居然在我的计算机上运行不起来.于是我就想自己写一个程序来做这事,顺便学习一下C#.

Form上的几个基本控件:

  • txtFolder: PHP文件所在的根目录, 新目录将自动取名为目录名_new
  • button1: txtFolder的browse按钮
  • CheckBox1: With Subfolders 标记, 即操作是否包括各级子目录
  • CheckBox2: Process PHP files only 标记, 即操作是否只针对PHP文件,如果要针对所有文件,则非PHP文件将被复制到指定目录
  • txtLog: 日志框, 输出所有信息
  • stsInfo: StatusBar, 显示一些提示信息
  • btnList: 显示所有文件到txtLog
  • btnbProcess: 对文件进行操作

几个private变量:

 

  • private bool WithSub = true; //对应checkbox1
  • private bool PhpOnly = false; //对应checkbox2
  • private string RootDir; //对应txtFolder

检查运行环境, PHP.EXE是黑刀的执行文件, 必须在当前目录下存在.

C# 代码复制内容到剪贴板
  1. private void Form1_Load(object sender, EventArgs e)    
  2. {    
  3. if (!File.Exists(".php.exe"))    
  4. {    
  5. MessageBox.Show("No php.exe found, the program may not run properly!");    
  6. Application.Exit();    
  7. }    
  8. dlgOpenFld.SelectedPath = "D:temp";    
  9. }    

 

另外, 在PHP.INI文件中, 要确认以下文件的路径名正确, 个人感觉用相对路径会好一些

PHP 代码复制内容到剪贴板
  1. [Zend]    
  2. zend_extension_manager.optimizer_ts="libOptimizer-3.3.0"    
  3. zend_extension_ts="libZendExtensionManager.dll"   

下面, BROWSE文件夹操作.

C# 代码复制内容到剪贴板
  1. private void button1_Click(object sender, EventArgs e)    
  2. {    
  3. if ( dlgOpenFld.ShowDialog() == DialogResult.OK )    
  4. {    
  5. txtFolder.Text = dlgOpenFld.SelectedPath;    
  6. }    
  7. }    

最重要的操作之一, 用递归取得文件列表, 在这一步里,用到了List<>这样的数据类型, 这是用于未知长度数组的, 可以看到, C#对于文件,目录的操作都与DELPHI有了非常大的不同, 这就是FRAMEWORK:

C# 代码复制内容到剪贴板
  1. private List<FileInfo> getFiles(string tDir, bool SubFolder)    
  2. {    
  3. List<FileInfo> FileList = new List<FileInfo>();    
  4. DirectoryInfo fDir = new DirectoryInfo(tDir);    
  5. DirectoryInfo[] subDir = fDir.GetDirectories();    
  6. FileInfo[] sFile = fDir.GetFiles();    
  7. if (SubFolder)    
  8. {    
  9. foreach (DirectoryInfo d in subDir)    
  10. {    
  11. FileList.AddRange(getFiles(tDir + "" + d.Name, SubFolder));    
  12. }    
  13. }    
  14. foreach (FileInfo f in sFile)    
  15. {    
  16. FileList.Add(f);    
  17. }    
  18. return FileList;    
  19. }    

下一步, 就是对取得的文件列表进行操作了,新文件夹自动取名为XXX_NEW, 并且对文件列表按规则进行操作, 即是只解密PHP文件, 还是要同时复制其他非PHP文件:

C# 代码复制内容到剪贴板
  1. private void button1_Click_1(object sender, EventArgs e)    
  2. {    
  3. if (!Directory.Exists(txtFolder.Text)||(txtFolder.Text.IndexOf(" ")>0))    
  4. {    
  5. MessageBox.Show("Directory "" + txtFolder.Text + "" is invalid! (No space allowed)""Invalid folder selection", MessageBoxButtons.OK,MessageBoxIcon.Error);    
  6. return;    
  7. }    
  8. RootDir = txtFolder.Text;    
  9. string newDir=RootDir + "_new";    
  10. List<FileInfo> FileList = new List<FileInfo>();    
  11. FileList = getFiles(txtFolder.Text, WithSub);    
  12.   
  13. for (int i = 0; i < FileList.Count; i++)    
  14. {    
  15. string tNewDir = FileList[i].DirectoryName.Replace(RootDir, newDir);    
  16. if (!Directory.Exists(tNewDir))    
  17. {    
  18. Directory.CreateDirectory(tNewDir);    
  19. }    
  20. if (FileList[i].Extension != ".php")//&&(FileList[i].    
  21. {    
  22. File.Copy(FileList[i].DirectoryName + "" + FileList[i].Name, tNewDir + "" + FileList[i].Name);    
  23. txtLog.AppendText("COPIED! " + i.ToString() + " - " + FileList[i].DirectoryName + "" + FileList[i].Name + "nn");    
  24. }    
  25. else    
  26. {    
  27. if (runphp(FileList[i].DirectoryName + "" + FileList[i].Name, tNewDir))    
  28. {    
  29. txtLog.AppendText("DECRYPTED! " + i.ToString() + " - " + FileList[i].DirectoryName + "" + FileList[i].Name + "nn");    
  30. }    
  31. else    
  32. {    
  33. txtLog.AppendText("FAILED TO DECRYPT! " + i.ToString() + " - " + FileList[i].DirectoryName + "" + FileList[i].Name + "nn");    
  34. }    
  35. }    
  36. }    
  37. }   

这是解码PHP文件, 通过建立新进程来调用外部EXE文件:

C# 代码复制内容到剪贴板
  1. private bool runphp(string filename, string NewFolder)    
  2. {    
  3. try    
  4. {    
  5. string EXE_PATH = @".";    
  6. System.Diagnostics.Process process = new System.Diagnostics.Process();    
  7. process.StartInfo.FileName = "php.exe";    
  8. process.StartInfo.WorkingDirectory = EXE_PATH;    
  9. process.StartInfo.CreateNoWindow = true;    
  10. process.StartInfo.Arguments = filename + " /tab /indent:1 /path:" + NewFolder + " /ext:* /noexpire";    
  11. process.Start();    
  12. if (process.HasExited)    
  13. {    
  14. //txtLog.AppendText("finished!nn");    
  15. //return true;    
  16. }    
  17. return true;    
  18. }    
  19. catch (Exception e)    
  20. {    
  21. throw e;    
  22. //return false;    
  23. }    
  24.   
  25. }    

其他的代码就不一一罗列了. 只是临时使用的代码, 功能还非常简单.

 

Tags: , ,
分页: 6/6 第一页 上页 1 2 3 4 5 6 最后页 [ 显示模式: 摘要 | 列表 ]