我在Delphi中调用为MO设置自定义线性,用了网上下载的符号编辑器,需要调用DLL中函数,他提供的VB例子如下:
VB:
Private Sub Command1_Click()
Dim layer As MapObjects2.MapLayer
Dim ps As New MOSYMBOLLib.MoPenset
ps.Load ("sample.lin")
Set layer = Map1.Layers(0)
For i = 0 To ps.Count - 1
    layer.Symbol.Custom = ps.Item(i)
    Map1.Refresh
    MsgBox ("continue...")
Next
layer.Symbol.Custom = Nothing
Map1.Refresh
End Sub对应的C#代码:
private void button1_Click(object sender, System.EventArgs e)
{
MOSYMBOLLib.MoPenset ps = new MOSYMBOLLib.MoPensetClass();
ps.Load("sample.lin");
ESRI.MapObjects2.Core.MapLayer lyr = axMap1.Layers.Item(0) as ESRI.MapObjects2.Core.MapLayer;
for(int i=0;i<ps.Count ;i++)
{
lyr.Symbol.Custom = ps.get_Item(i);
axMap1.CtlRefresh();
System.Windows.Forms.MessageBox.Show(this,"OK");
}//end for
lyr.Symbol.Custom = null;
axMap1.CtlRefresh();
}
以上两种代码均成功执行但是我改写为Delphi代码:
procedure TForm1.Button1Click(Sender: TObject);
var
  ps,p1:OleVariant;
  lyr:MapLayer;
begin
  ps:=CreateOleObject('MoSymbol.MoPenset.1');
  ps.Load('sample.lin');
  lyr:= map1.Layers.Item(0) as MapLayer;
  ShowMessage(ps.Count);         //正常显示符号总数
  lyr.Symbol.Custom := ps.Item(1);    //错误信息:找不得成员。
  lyr.Symbol.Custom := ps.Get_item(1);  //错误信息:Method 'Get_item' not supported by automation object.
  map1.Refresh;
  ShowMessage('OK');
  lyr.Symbol.Custom := nil;
  map1.Refresh;
end;
使用VB的ps.Item方式提示:找不得成员。
用C#的ps.Get_item方式提示:Method 'Get_item' not supported by automation object.
请问该如何改写?

解决方案 »

  1.   

    静态调用DLL的输出函数,如:
    function StartSigCheck(chanelNo: integer): Integer; stdcall; far external 'Tc08a32.dll';
    function StopSigCheck(chanelNo: integer): Integer; stdcall; far external 'Tc08a32.dll';
      

  2.   

    动态调用
    type afunc1=procedure( short a, short b) of object;var myfun:afunc1;
    begin
      if FDLLPath[length(FDLLPath)]<>'\' then FDLLPath:=FDLLpath+'\';
      DLLHandle := LoadLibrary(pchar(FDLLPath+'aaa.dll'));
      if DLLHandle <> 0 then  @myfun:=GetProcAddress(DLLHandle, 'func1');
    end;
      

  3.   

    能说的明白一点吗?
    我是DLL中一个类的函数。
      

  4.   

    DELPHI中如果是静态调用的话,要在前面做一个声明的,动态就不用
    静态调用:
    unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;type
      TForm1 = class(TForm)
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;
      procedure showform;External 'Project1.dll';{静态调用}
    implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
    begin
    showform;
    end;end动态调用:
    unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;type
      TForm1 = class(TForm)
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
    var
      Sabout:THandle;
      ShowA:procedure;
    begin
      Sabout := LoadLibrary('Project1.dll');
      if  Sabout=0 then begin
        Application.MessageBox('动态连接库Project1.dll文件不存在!','错误',64);
        exit;
       end;
       ShowA := GetProcAddress(Sabout,'showform');
       showA;
       FreeLibrary(Sabout);
    end;end.
      

  5.   

    楼主看看《Delphi5开发人员指南》
      

  6.   

    我是想调用DLL中一个类的函数,
    在VB中调用此类的Item(1)函数,
    在C#中使用Get_Item(1)的方式,
    在Delphi中我用此两种方法都报错,在运行时会弹出错误对话框,错误内容如下:
    使用Item方式提示:找不得成员。
    用Get_item方式提示:Method 'Get_item' not supported by automation 
    我获取此类的成员变量的值Count成功,调用类的其他函数也成功,说明类创建是正常的,只有Item方法错误,不知道是什么问题。PS:我如何修改我的帖子?
      

  7.   

    这个帖子大幅翁上多了去了,这是我在以前大幅翁上找到的帖子,应该很全了
    Delphi中DLL的创建和使用 1.DLL简介; 2.调用DLL; 3.创建DLL; 4.两个技巧; 5.初始化; 6.例外处理。 
    1、DLL简介 
      DLL是Dynamic-Link Libraries(动态链接库)的缩写,库里面是一些可执行的模块以及资源(如位图、图标等)。可以认为DLL和EXE基本上是一回事,只是DLL不能直接执行,而必须由应用程序或者其他DLL调用。DLL为应用程序间的资源共享提供了方便,同时也是多语言混合编程的重要手段。由此可见学习使用DLL是Windows程序员必须掌握的一项重要技术。 2、如何调用DLL 
      在Delphi中有两种方法调用DLL中的函数和过程,即外部声明或者动态加载。 <1>外部声明 
      在Delphi中外部声明是访问外部例程最容易和最常用的方式,有两种声明方式:通过名字、通过索引号。举例如下:在MYDLL.DLL中有两个函数和一个过程,则其外部声明可以写成: function test1:integer;external 'mydll'; 
    //直接通过名称调用test1(注意名称大小写敏感)。 
    function test11:integer;external 'mydll' name 'test1'; 
    //通过名称调用test1,在程序中使用新名称(原名称仍然大小写敏感)。 
    procedure test2;external 'mydll' index 1; 
    //通过索引号调用TEST2。程序中可以用与DLL中不一样的名称. 
      使用外部声明的缺点是程序启动时如果找不到mydll.dll将无法运行,即使没有调用其中的模块。 动态加载的方法可以避免这种情况。 <2>动态加载 
      通过调用Windows API中的相关函数,将DLL调入内存并获得指向函数或过程的指针,执行完模块后释放内存。除了节约内存外,这种方法的一个很大的优点是能处理找不到dll或者在装入过程中出错的情况。这样即使某个dll有问题,应用程序的其他部分仍然能够正常运行。动态加载的例子如下: var hDll:THandle; 
      Test1:function:integer; 
    begin 
      hDll:=LoadLibrary('mydll.dll'); 
      if hDll<32 then exit;//如果Dll无法加载则跳出 
      @Test1:=GetProcAddress(hDll,MakeIntResource(1)); 
        //取得mydll中的第一个函数的地址。 
      ... 
      FreeLibrary(hDll); 
    end; 3、用Delphi创建DLL 
      用Delphi创建一个DLL是十分简单的,首先需要新建一个DLL的Porject(如果使用Delphi3.0则可以在File->New对话框中选择DLL),当然也可以自己写,现在这个Project是这样的: library Project1; 
    uses SysUtils,Classes; 
    begin 
    end.   当然这是一个空DLL,现在让我们来加入一个函数,让他成为我们的第一个可以使用的DLL。完成后的文件是这样的: library dll1; 
    uses SysUtils,Classes; function Test1(a,b:integer):integer; 
    begin 
    Result:=a+b; 
    end; exports 
    Test1 index 1; begin 
    end.   在这个DLL里我们声明了一个加法函数,然后用exports语句输出它,只有被输出的函数或过程能被其他程序调用。exports语句后的语法是:函数名 [index ],index 是为函数手工指定索引号,以便其他程序确定函数地址;也可以不指定,如果没有使用Index关键字,Delphi将按照exports后的顺序从1开始自动分配索引号。现在我们可以调用这个DLL了,下面给出一个实例,运行后form1的标题将变成“1+2=3”: 声明部分:function Test1(a,b:integer):integer;external 'dll1'; 
           注意此处是大小写敏感的。 
    运行部分:form1.caption:='1+2='+inttostr(test1(1,2)); 4、使用DLL的两个技巧 
    <1>把现有的项目改成DLL 
      学会制作DLL以前,大多数程序员手中都积攒下来不少已经完成了的项目,如果现在需要把这些项目做成DLL而不是可执行文件,重新写一遍显然是没有必要的,只要按照下面的步骤对已有的项目文件进行修改就可以了: 
      ① 打开项目文件(.DPR),删除单元底部begin和end.之间的所有语句(一般情况下这些语句是由Delphi自动生成的)。如果项目中没有用到Form,则从uses子句中删除表单单元(Form),然后转到第③步。 
      ② 对项目进行修改,令除Main Form之外的所有Form都是动态生成的,这样我们只要在DLL输出的一个函数或者过程中生成Main Form,即可调用执行整个项目。我们假设Main Form的名字是MyMainForm,项目的名字是MyDll,现在在单元底部的begin语句之前加入一个过程,过程的名字为RunMyDll,这个过程将动态生成Main Form,从而运行整个项目。RunMyDll的写法如下: 
        procedure InitDll2; 
        begin 
        Application.CreateForm(TMyMainForm, MyMainForm); 
        MyMainForm.Show; //如果MyMainForm不可视则需要这一句. 
        end; 
      ③ 如果想要输出其他函数或者过程,而原来的项目中没有,则可以在单元底部的begin语句之前加入这些代码。 
      ④ 在单元底部的begin语句之前加入一个exports小节,然后写出所有想要输出的函数或过程的名字(最好指定索引号)。注意如果执行了第②步,一定要输出RunMyDll过程。 
      ⑤ 将项目文件顶部的保留字program改为library。 
      ⑥ 编译。 
      现在就可以在其他程序中调用本项目中的函数和过程了,只要执行RunMyDll就可以执行这个项目,和执行原来的可执行文件一模一样。 <2>创建一个引入文件 
      如果DLL比较复杂,则为它的声明专门创建一个引入程序单元将是十分有意义的,并且会使这个DLL变得更加容易维护。引入单元的格式如下: 
      unit MyImport; {Import unit for MyDll.Dll} 
      interface 
      procedure RunMyDll; 
      implementation 
      procedure RunMyDll;external 'MyDll' index 1; 
      end. 
    这样以后想要使用MyDll中的例程时,只要简单的在程序模块中的uses子句中加上MyImport即可。 5、DLL的初始化和善后工作 
      一般的DLL不需要做初始化和善后工作,因此大部分读者可以跳过这一节。但如果你想让你的DLL在被载入时先作一些初始设定,或者退出时释放资源,则可以有三种方法达到目的: <1>利用Unit的Initalization与Finalization这两个小节 
      可以在Unit的这两个小节中安排Unit的进入和退出,但是Program与Library并没有这两个部分,所以只能写在Unit中。 <2>利用ExitProc变量 
      在Library的begin..end.中间是可以写代码的,这里可以放置DLL初始化代码。如果想要做善后工作,则可以利用ExitProc变量。我们首先在初始化代码中把ExitProc中包含的默认的善后过程地址保存下来,然后把自定义的过程的地址赋给它,这样DLL退出时就会执行我们制定的程序;在自定义的过程的最后,把ExitProc恢复原来的默认值,以便DLL能够继续完成原来默认的善后工作。下面是示例: 
      library MyDLL; 
      ... 
      OldExitProc: pointer; 
      ... 
      procedure MyExitProc; 
      begin 
      ... //善后程序 
      ExitProc := OldExitProc; 
      end; 
      ... 
      begin 
      ... //初始化程序 
      OldExitProc := ExitProc; 
      ExitProc := @MyExitProc; 
      end. <3>利用DllProc变量 
      和ExitProc一样,DllProc也是一个在Systemd单元中预定义的变量。在使用DLLProc时, 必须先写好一个具有以下原型的程序: 
      procedure DLLHandler(Reason: integer); 
    并在library的begin..end.之间, 将这个DLLHandler程序的执行地址赋给DLLProc中, 这时就可以根据参数Reason的值分别作出相应的处理。另外注意要将Windows单元加入uses子句。示例如下: 
      library TestDLL; 
      ... 
      procedure MyDLLHandler(Reason: integer); 
      begin 
       case Reason of 
        DLL_Process_Attach: //整个DLL的初始化代码 
        DLL_Process_Detach: //整个DLL的善後程序 
        DLL_Thread_Attach: //当主叫端开始一个Thread时 
        DLL_Thread_Detach: //当主叫端终止一个Thread时 
       end; 
      end; 
      ... 
      begin 
      ... //初始化代码 
      DLLProc := @MyDLLHandler; 
      MyDLLHandle(DLL_Process_Attach); 
      end. 
    由上例可以知道,当DLL支援多进程(Thread)的处理时, DllProc非常适合使用。 6、DLL中的例外处理 
      在用Delphi制作DLL时, 在例外处理方面请留意以下三点: 如果uses子句中没有SysUtils话,无法使用例外处理。 
    如果DLL中没有对例外进行处理的话,这个例外会想完传导到主叫端的应用程序。如果该应用程序也是Delphi写的话, 这个例外可以由主叫端进行处理。 
    承上, 如果主叫端的程式不是Delphi或Borland C++ Builder,则例外以作业系统错误的形式来处理,例外编号是$0EEDFACE,ExceptionInformation中第一个进入点是例外发生的地址,第二个进入点是指向的Delphi例外物件的引用。 
    本文参考了钱达智先生(Wolfgang Chien)的技术文章,以及《Delphi for Windows Power Toolkie》([美]Harold Davis著)
      

  8.   

    问题已经解决,
    用ps.item[1]的方式,不是用ps.item(1)的方式。
      

  9.   

    用Project菜单的Import Type Library导入DLL文件,查看Delphi生成的TLB文件的定义。