主程序调用DLL窗体cannot assign a class to a class问题的彻底解决方案

转自http://topic.csdn.net/u/20091216/14/0906d982-c004-417a-becb-07efdbea81ae.html

 经验共享:
  主程序调用DLL窗体 cannot assign a TFont to a TFont 问题的彻底解决方案

在网上搜索N久,总结并实战出来的经验和大家分享
  1、中国的网站链接大多建议的方案是 project->options选项的packages标签页面勾选 'Buidl with runtime packages'
我个人在D7中测试确实能够解决问题。但是程序发布的时候需要带很多bpl包。
  2、在国外网站搜索到另一种解决方案,就是通过修改系统的controls.pas和graphics.pas两个文件来彻底解决上述问题。
  具体链接地址为:http://tengco.spaces.live.com/Blog/cns!689EE398F7BFBE58!150.entry
  http://www.delphi3000.com/articles/article_4957.asp?SK=

  下面是我的程序做法:
  首先、把系统的controls.pas和graphics.pas拷贝到自己的工程目录,并做如下修改
  第一步、在controls.pas 的声明部分加入
  function GetControlAtom : pointer;
  第二步、在controls.pas 的实现部分加入
  function GetControlAtom : pointer;
  begin
  result := @ControlAtom;
  end;
  第三步、修改graphics.pas的TCanvas.SetFont函数
procedure TCanvas.SetFont(Value: TFont); 
begin 
  FFont.Assign(Value); 
end; 

给上面的代码加上 try..except保护,编程如下:

procedure TCanvas.SetFont(Value: TFont); 
begin 
  try 
  FFont.Assign(Value); 
  except 
  on Exception do; 
  end; 
end; 

  第四步、在DLL工程中引入我们修改好的两个文件;
  第五步、DLL工程的初始化
procedure myDllProc(dWseason: DWORD);
var
  p:^word;
begin
  case dWseason of
  DLL_PROCESS_ATTACH: begin
  oldApp := Application; //保存DLL的Application
  oldScr := Screen; //保存DLL的Screen
  p := Controls.GetControlAtom;
  OldControlAtom := p^;
  CoInitialize(nil); //使用了ADO控件所以需要调用此方法
  end;
  DLL_PROCESS_DETACH: begin
  p := Controls.GetControlAtom;
  p^ := OldControlAtom;
  application := oldApp; //恢复Dll的Application
  Screen := oldScr; //恢复Dll的Screen
  CoUninitialize(); //使用了ADO控件所以需要调用此方法
  end;
  end;
end;

procedure InitDll(var app:tapplication; var scr:Tscreen; RealControlAtom:integer);
var
  p:^word;
begin
  p := controls.GetControlAtom;
  if scr <> nil then screen := scr;
  application := app;
  p^ := RealControlAtom;
end;


library testdll;

{ Important note about DLL memory management: ShareMem must be the
  first unit in your library's USES clause AND your project's (select
  Project-View Source) USES clause if your DLL exports any procedures or
  functions that pass strings as parameters or function results. This
  applies to all strings passed to and from your DLL--even those that
  are nested in records and classes. ShareMem is the interface unit to
  the BORLNDMM.DLL shared memory manager, which must be deployed along
  with your DLL. To avoid using BORLNDMM.DLL, pass string information
  using PChar or ShortString parameters. }

uses
  ShareMem,
  SysUtils,
  Classes,
  windows,
  Controls in 'Controls.pas',
  Graphics in 'Graphics.pas';  

exports
  InitDll;

begin
  DllProc := @myDllProc;
  myDllProc(DLL_PROCESS_ATTACH); //DLL入口初始化
end.

主程序调用示例:
  ...
  p := controls.GetControlAtom;
  InitDll(application,screen,p^);
  ...


<think>好的,我现在需要解决Java中无法给final变量providerInfo赋值的问题。首先,我得回顾一下final关键字在Java中的作用。根据所学知识,final变量一旦被初始化后就不能再被修改,无论是基本类型还是引用类型。这意味着如果变量被声明为final,在赋值后再次赋值会导致编译错误。 用户提到的错误信息是“cannot assign a value to final variable providerInfo”,这说明他们可能在尝试给一个已经初始化的final变量重新赋值。我需要先确定变量providerInfo的声明位置和初始化方式。通常,final变量可以在声明时直接初始化,或者在构造方法中初始化(对于实例变量),或者在静态代码块中初始化(对于静态变量)。 接下来,我需要检查代码中是否有对providerInfo的多次赋值。例如,可能在某个方法中试图修改它的值,或者在构造方法之外的地方进行初始化。比如,如果providerInfo是一个实例变量,但没有在构造方法中初始化,而在其他方法中赋值,这会导致错误,因为final变量必须在构造方法完成之前被初始化。 另外,如果providerInfo是局部变量,那么它必须在声明时初始化,并且之后不能再修改。例如,在方法内部定义的final局部变量,如果在后续代码中有重新赋值的操作,就会报错。 可能还需要考虑变量的作用域。比如,如果在不同的代码块中重复声明了同名的final变量,虽然这在某些情况下可能合法,但需要检查是否有冲突。 解决方案方面,首先需要确保final变量只被赋值一次。如果是实例变量,确保在构造方法中初始化,或者使用初始化块。如果是静态变量,则在静态代码块中初始化。同时,检查是否有任何地方不小心重复赋值,比如在setter方法或其他方法中试图修改final变量。 另外,如果providerInfo需要动态赋值,可能需要重新设计代码,去掉final修饰符,或者使用不可变对象模式,确保对象状态在初始化后不再改变。例如,可以使用Builder模式或者工厂方法来创建对象,而不是在后期修改final字段。 还需要注意,final引用类型变量的引用不能改变,但对象内部的状态可能可以改变,除非对象本身是不可变的。比如,final List<String> list = new ArrayList<>();之后不能将list指向另一个ArrayList,但可以添加元素。不过这可能与用户的问题无关,因为用户的问题是关于直接赋值。 总结可能的解决步骤: 1. 检查providerInfo的声明位置和初始化方式。 2. 确保在所有可能的代码路径中,final变量只被赋值一次。 3. 如果需要在运行时确定值,考虑在构造方法或静态块中初始化。 4. 移除任何对providerInfo的重复赋值操作。 5. 如果必须修改变量值,考虑移除final修饰符,并确保线程安全等其他问题。 可能用户的问题出现在尝试在方法中对final变量进行二次赋值,例如在setter方法中,或者在某些条件分支中多次初始化。需要具体代码示例才能更准确判断,但根据常见情况,上述步骤应该能解决问题。</think>在Java中,`final`变量表示不可变常量,其赋值规则需要遵循以下原则: ### 问题分析 1. **声明即赋值**:`final`变量必须在声明时直接初始化,或在构造方法(实例变量)/静态代码块(静态变量)中完成初始化 2. **禁止重复赋值**:所有`final`变量只能被赋值一次,后续修改会触发编译错误`final variable cannot be assigned` 3. **作用域限制**:局部`final`变量必须在声明时初始化,方法参数中的`final`变量不能二次赋值 ### 解决方案 #### 情况1:实例变量 ```java class ServiceProvider { // 声明时直接初始化 private final String providerInfo = "default"; // 或在构造方法中初始化 public ServiceProvider(String info) { this.providerInfo = info; // 合法 } public void updateInfo() { providerInfo = "new value"; // 编译错误[^1] } } ``` **修改建议**:移除`final`修饰符,或通过构造新对象实现"修改" #### 情况2:静态变量 ```java class Config { static final String providerInfo; static { providerInfo = "init value"; // 静态代码块中初始化合法 } public static void reload() { providerInfo = "reloaded"; // 编译错误 } } ``` **修改建议**:使用单例模式或配置文件重载机制 #### 情况3:局部变量 ```java public void process() { final int retryCount; retryCount = 3; // 合法(首次赋值) if(condition) { retryCount = 5; // 编译错误[^1] } } ``` **修改建议**:改用普通变量或重构逻辑避免重复赋值 ### 最佳实践 1. 对需要后期修改的变量**避免使用`final`** 2. 对配置类参数使用`final`+构造方法强制初始化 3. 对线程共享变量考虑`final`+`volatile`组合 4. 使用不可变集合处理集合类`final`变量: ```java final List<String> data = Collections.unmodifiableList(new ArrayList<>()); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值