Jul 17

4年前用VS2005的C#编写了一个应用程序,用于调试VC++写的AMINE计算包。自从发布出去以后,就已经很久没有用过了。这两天有要求要重新改良一下这个软件,于是把这个程序移植到了VS2010,在Windows 7 64bit下重新编译通过,但是当运行case时,却发现出问题了。

界面每次调用DLL中的amDBRInitialize()进行初始化时,就报错。试了一下放在我的VM下的32bit的WIN7,XP下,也都会出这问题。但是在别人的windows XP下就是好的,在我另一台XP下也是好的。更奇怪的时,用以前vs2005编译的界面和DLL,也都存在同样的问题。

还好VS下抓错误信息很方便,错误为An attempt was made to load a program with an incorrect format.

查找后发现,这还是因为x86和x64兼容性的问题。因为dll是32位编译的,而编译界面时,无论以前的VS2005还是现在的VS2010,用的都是any cpu,结果在此64位计算机上,就出现了调用不谐调--64位的程序调用32位的DLL。所以,在VS2010上,把编译指令从ANY CPU改成X86就能解决问题。

修改以后,错误消失,这个问题算是解决了。但是奇怪的是,为什么之前在VM的32位的OS也一样不行呢?

Tags: , , , , , ,
Jun 2

在安装时自动注册.NET开发的DLL文件,需要在Registration Type中选择"Extract COM information",再勾选"COM Interop".

Dec 16

DELPHI开发调用WEBSERVICE的一个简单例子,先转帖过来,代码还没有验证其正确性
原帖地址: http://kb.cnblogs.com/a/1505053/

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

Webservice技术的出现将各种开发技术和语言完全的融合了,下面就这种融合在C#和delphi之间的交互做一次全面的体现

1.使用C#创建一个Webservice服务。
使用vs2005的模板创建C#的webservice非常容易。原文件如下:
[WebService(Namespace = "http://localhost/webserver/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

public class Service : System.Web.Services.WebService
{
public Service () {
//如果使用设计的组件,请取消注释以下行
InitializeComponent();
}

#region Component Designer generated code
private void InitializeComponent()
{

}
//Web 服务设计器所必需的
private IContainer components = null;

protected override void Dispose(bool disposing)
{
if (disposing && components != null)
{
components.Dispose();
}
base.Dispose(disposing);
}
#endregion
//这个是自动生成的一个webservice函数,可以不要。
[WebMethod]
public string HelloWorld() {
return "Hello World";
}
//这个才是我们自己创建的,
[WebMethod]
public int addnumber(int a, int b)
{
return = a + b;
}
}
2.使用delphi创建一个dll(非com的dll),该dll调用上面的webserivce服务。
使用delphi调用C#的webservice过程也很容易,但是对于新手可能比较麻烦(我就是这么过来的)
第一步:创建一个dll单元:
{$R *.res}
function GetNum(a,b:integer):integer stdcall; [Page]
var
ireturn :Integer;
begin
ireturn:=GetServiceSoap().addnumber(a,b); //这个GetServiceSoap是什么,看后面...
result:=ireturn;
end;
exports
GetNum name ’GetNum’;

begin
end.
//如果是delphi调用该dll必须使用下面的代码。C#调用则不需要了(C#还是要牛一些,呵呵)
initialization
coinitialize(nil);
finalization
counInitializ
第二步:将webserivce的WSDL导入到该dll工程中,如何导,方法至少有两种,我说简单的一种:
file->new->other->WebService->WSDL Importer,(将C#的WSDL输入)然后delphi会自动给你生成了一个pas文件,
function GetServiceSoap(UseWSDL: Boolean; Addr: string; HTTPRIO: THTTPRIO): ServiceSoap;
const
defWSDL = ’http://localhost/webserver/Service.asmx?WSDL’;
defURL = ’http://localhost/webserver/Service.asmx’;
defSvc = ’Service’;
defPrt = ’ServiceSoap’;
var
RIO: THTTPRIO;
begin
Result := nil;
if (Addr = ’’) then
begin
if UseWSDL then
Addr := defWSDL
else
Addr := defURL;
end;
if HTTPRIO = nil then
RIO := THTTPRIO.Create(nil)
else
RIO := HTTPRIO;
try
//RIO.HTTPWebNode.UseUTF8InHeader:=True; //在此添加一句,修改编码方案。
Result := (RIO as ServiceSoap);
if UseWSDL then
begin
RIO.WSDLLocation := Addr;
RIO.Service := defSvc;

RIO.Port := defPrt;
end else
RIO.URL := Addr;
finally
if (Result = nil) and (HTTPRIO = nil) then
RIO.Free;
end;
end;

initialization
InvRegistry.RegisterInterface(TypeInfo(ServiceSoap), ’http://localhost/webserver/’, ’utf-8’); [Page]
InvRegistry.RegisterDefaultSOAPAction(TypeInfo(ServiceSoap), ’http://localhost/webserver/%operationName%’);
//对于无法识别传入的参数的问题,需要手工加上这一句>......
InvRegistry.RegisterInvokeOptions(TypeInfo(ServiceSoap), ioDocument);

这段代码基本上你不用关心,但是,有两个地方需要特别注意:
1.RIO.HTTPWebNode.UseUTF8InHeader:=True;对于中文参数必须加上
2.InvRegistry.RegisterInvokeOptions(TypeInfo(ServiceSoap), ioDocument);
如果传入的参数不能被webservice识别时,多半是因为你没有加上这一句。

3.使用delphi调用上面的dll
就一个函数,没有什么好说的:
procedure TForm1.Button1Click(Sender: TObject);
type
GetNumTotal=function(a,b:integer):integer;stdcall;
var
Th:Thandle;
Tf:GetNumTotal;
Tp:TFarProc;
begin
Th:=LoadLibrary(’mywebservice.dll’); {装载DLL}
if Th>0 then
try
Tp:=GetProcAddress(Th,PChar(’GetNum’));
if Tp<>nil
then begin
Tf:=GetNumTotal(Tp);
Edit1.Text:=IntToStr(Tf(1,3)); {调用GetNumTotal函数}
end
else
ShowMessage(’GetNumTotal函数没有找到’);
finally
FreeLibrary(Th); {释放DLL}
end
else
ShowMessage(’mywebservice.dll没有找到’);
end;

4.使用C#调用上面的dll

[DllImport("mywebservice.dll", EntryPoint = "GetNum")]
public static extern int GetNum(int a, int b);
private void button1_Click(object sender, EventArgs e)
{
int a,b,i;
a=10;
b =20;
i=GetNum(a,b); //第一次比较慢(webserivce的唯一弊端!!!!)
textBox1.Text = i.ToString();
}

Tags: , , ,
Dec 2

前文"C#调用C++函数入口点的问题"说了一点关于使用DLLImport进行导入函数的事. C#调用C++的函数其实不止这一种方法, 还有一种方法是用delegate申明函数委托进行调用,这种方法略显麻烦,但是可以进行回调并应用指针.

在C#中,首先先要定义一个类,用来把DLL中函数地址转换成委托:

HiddenCopy Code To Clipboard
  1. public class DLLWrapper
  2. {
  3. ///<summary>
  4. /// API LoadLibrary
  5. ///</summary>
  6. [DllImport("Kernel32")]
  7. public static extern int LoadLibrary(String funcname);
  8.  
  9. ///<summary>
  10. /// API GetProcAddress
  11. ///</summary>
  12. [DllImport("Kernel32")]
  13. public static extern int GetProcAddress(int handle, String funcname);
  14.  
  15. ///<summary>
  16. /// API FreeLibrary
  17. ///</summary>
  18. [DllImport("Kernel32")]
  19. public static extern int FreeLibrary(int handle);
  20.  
  21. ///<summary>
  22. ///通过非托管函数名转换为对应的委托, by jingzhongrong
  23. ///</summary>
  24. ///<param name="dllModule">Get DLL handle by LoadLibrary</param>
  25. ///<param name="functionName">Unmanaged function name</param>
  26. ///<param name="t">ManageR type对应的委托类型</param>
  27. ///<returns>委托实例,可强制转换为适当的委托类型</returns>
  28. public static Delegate GetFunctionAddress(int dllModule, string functionName, Type t)
  29. {
  30. int address = GetProcAddress(dllModule, functionName);
  31. if (address == 0)
  32. return null;
  33. else
  34. return Marshal.GetDelegateForFunctionPointer(new IntPtr(address), t);
  35. }
  36.  
  37. ///<summary>
  38. ///将表示函数地址的IntPtr实例转换成对应的委托, by jingzhongrong
  39. ///</summary>
  40. public static Delegate GetDelegateFromIntPtr(IntPtr address, Type t)
  41. {
  42. if (address == IntPtr.Zero)
  43. return null;
  44. else
  45. return Marshal.GetDelegateForFunctionPointer(address, t);
  46. }
  47.  
  48. ///<summary>
  49. ///将表示函数地址的int转换成对应的委托,by jingzhongrong
  50. ///</summary>
  51. public static Delegate GetDelegateFromIntPtr(int address, Type t)
  52. {
  53. if (address == 0)
  54. return null;
  55. else
  56. return Marshal.GetDelegateForFunctionPointer(new IntPtr(address), t);
  57. }
  58. }

然后, 用delegate声明函数:

HiddenCopy Code To Clipboard
  1. delegate void _amDBRSetThermoModel(int mid, ref int errid);

再然后, 自己写个private的函数封装DLL中的函数, hModule()函数的作用是取得DLL的地址,用在多个输出函数中

HiddenCopy Code To Clipboard
  1. private int hModule()
  2. {
  3. int _hModule = DLLWrapper.LoadLibrary(DLLPATH);
  4. if (_hModule == 0)
  5. {
  6. return 0;
  7. }
  8. return _hModule;
  9. }
  10.  
  11. private void amDBRInitialize()
  12. {
  13. try
  14. {
  15. _amDBRInitialize amf = (_amDBRInitialize)DLLWrapper.GetFunctionAddress(hModule(), "amDBRInitialize", typeof(_amDBRInitialize));
  16. amf();
  17. }
  18. catch (Exception e)
  19. {
  20. throw e;
  21. }
  22. }

 

Tags: , , , ,
Dec 2

C++编写的DLL函数被C#所写的应用程序调用, 使用VS2005进行DEBUG时, 所设的断点无效, 系统信息显示"The breakpoint will not currently be hit. No symbols have been loaded for this document."

查阅无数资料, 大多写的是关于PDB文件如何如何, 试过都没有作用.

后来发现,其实只要在project properties中更改一下debugger type 就可以了. 如下图所示, 把debugger type从AUTO改到MIXED, 断点就可以用了, 不过要注意改完并DEBUG刚开始时, 断点还是空心的, 只有当DLL被调用时, 断点标记才会变成实心并被激活.

Tags: , , ,
分页: 1/1 第一页 1 最后页 [ 显示模式: 摘要 | 列表 ]