为了实现应用程序的多语言显示,本人将相应语言的资源文件做成dll文件,在程序的InitInstance中通过LoadLibrary调用资源dll文件,然后用AfxSetResourceHandle();来装载资源dll文件。
但是这种方法必须重新运行应用程序,才能实现更换语言。
请问如何在程序运行过程中装卸资源文件?

解决方案 »

  1.   

    在Delphi程序中调用资源文件
    资源文件在Delphi中的关键字为hinstance.下面给出具体用法
    <1>光标的调用
    首先在程序中定义一个值大于0的常量,因为Delphi本身用0-负
    16来索引 默认的光标,所以我们制定的光标应从表面上1开始索引。然后
    在窗口的Oncreat事件中添加以下代码:
    screen.cursor[35]:Load cursor (hinstance,'mycur');
    其中35为大于1的常量,mycur为光标在资源文件中的名字。如
    果希望在 其他控件上使用定制光标,例如Panel控件,只需在程序的适当
    处加入以下代码:
    Panel1.cursor:=35;
    <2>位图的调用
    新建一项工程,添加一Timage控件,在需要显示的地方写以下代码:
    Var mymap:Hbitmap;
    begin 
    hmymap:=LoadBitmap(hinstance,'mypic');
    Image1.picture.Bitmap.Handle:=mymap;
    end;
    其中"mypic"为位图资源文件中的名称。
    〈3〉AVI文件的调用
    新建一工程,添加一Animate控件,在需要的地方加入:
    animater1.resname:='myAVI';
    animater1.Active:=true;
    其中myAVI为视频文件在资源文件中的名称。
    〈4〉调用WAV文件
    在uses中加入mmsystm单元,以便在程序中播放WAV文件。播放时Playsound
    (pchar('mywav'),hinstance,sndsync or snd_resource);其中mywav为声音
    文件在资源中的名称。
    〈5〉加入光标
    加入光标比较容易,只要将res文件加入单元文件中即可。但需注意,名称
    最好取"W"."WW"等,使第一个字母尽量靠后,以免与主程序的图标顺序颠倒。
    补充:1.资源类型除上述类型外,还可以字体文件,字符串文件等。
      

  2.   

    你所讲的的确很不错。可是我现在需要动态装载已经打成dll文件的资源,只需要装载这个dll文件就可以了。
    不知道应该如何实现呢?
      

  3.   

    装载完DLL之后,通过该DLL返回的MOUDLE为对象调用就可以了
    eg:
    var
      h :integer;
    begin
       h := LoadLibrary('936.dll');
       if (h <> 0)
       begin
          s := LoadString(h, 100, p);
       end;
    end;
      

  4.   

    楼主:不要在InitInstance装载Dll。卸载时用: freelibrary。
      

  5.   

    装载时除了loadlibrary外,还可以用SafeLoadLibrary
      

  6.   

    LoadLibrary与FreeLibrary是成对出现的, 先用FreeLibrary释放Handle,然后用LoadLibrary重新载入.
      

  7.   

    多谢各位的帮助,可是我按照各位所说的试过了,不知道是不是我哪里做错了,结果是不行的。我的具体做法是:
    在主程序中调用菜单命令,如下:void CSalesListApp::OnViewChinese() 
    {
             //m_hLangDLL是资源句柄
    ::FreeLibrary(m_hLangDLL);
    m_hLangDLL = ::LoadLibrary("Chinese.dll");
    AfxSetResourceHandle(m_hLangDLL);
    }这样程序是没有反应的。还请朋友指点。多谢了!如果解决了这个问题,我可以奉送200分。
      

  8.   

    (或者)你少调用了一次FreeLibrary,上面程序应改一下, 用GetModuleHandle来判断当前内存中是否还有对应的DLL,然后用FreeLibrary或Loadlibrary
    procedure TForm1.Button1Click(Sender: TObject);
    var
      mdl : LongWord;
    begin
      While true do
      begin
        mdl := GetModuleHandle('Chinese.dll');
        if mdl > 0 then
          FreeLibrary(mdl)
        else
          Break;
      end;
      mdl := Loadlibrary('Chinese.dll');
    end;
      

  9.   

    在FreeLibrary(m_hLangDLL); 
    后要把m_hLangDLL置为0,如下
    m_hLangDLL:= 0;
      

  10.   

    少说了一句:补充 Wnyu(西门吹水) 说的。
      

  11.   

    经过这几天的学习,我大致掌握了一些知识,在这里共享一下学习成果。我使用的是c语言的格式,但是由于调用的都是api,所以和delphi里的使用是一样的。在这里要感谢诸位尤其是西门吹水的提示。不过我还有遗留的问题,就是如何使用dll文件中资源,比如菜单。 HINSTANCE m_hLangDLL3; // handle to LoadLibrary from .DLL file 
         HRSRC hResource; // handle for FindResource  
    HGLOBAL hMem; // handle for LoadResource 
    LPVOID lpResource; // address of resource data  // ::FreeLibrary("Chinese.dll"); // Load the file from which to copy the resource. 
    // 获取应用程序.EXE或dll的文件句柄,
    // 该句柄用于在.EXE或dll文件中寻找资源
    m_hLangDLL3 = ::LoadLibrary("English.dll"); //第一个参数是模块句柄
    //第二个是要查找的资源名字,如"MYDIALOG"
    //第三个是资源类型
    //返回该资源句柄
    //LoadResouce以该句柄为参数装入资源
    //寻找具有指定资源ID和指定资源类型的资源文件中的资源位置,返回值为有名称的资源
    //在动态链接库中查找资源类型为RT_MENU,资源名为128的资源
    hResource = ::FindResource(m_hLangDLL3, MAKEINTRESOURCE(128), RT_MENU);
    if (hResource == NULL) 
    AfxMessageBox("Error!");
    // Load and lock the resource directory.
    // first parameter: resource-module handle
    // second parameter: resource handle
    // 将该资源装入内存
    // 返回值标识了用于接受资源数据的全局数据块
    hMem = ::LoadResource(m_hLangDLL3, hResource);
    if (hMem == NULL) 

    FreeResource(hResource); 
    AfxMessageBox("Error!"); 
    }  //锁定该资源
    //锁定hg所标定的内存块,并返回所标定内存块的虚拟内存地址
    //返回值指向该资源开始处的第一个字节
    lpResource = ::LockResource(hMem); 
    if (lpResource == NULL) 

    FreeResource(hResource); 
    AfxMessageBox("Error!"); 
    }  //若上述四步中的任何一步发生问题,则返回并释放相应的内存。
    //接下去要做的事情就是根据文件数据类型进行数据加载
    //.......
    //举例
    //如何loadmenu并体现出来?请提示
         UnlockResource(hMem);
         FreeResource(hMem);
      

  12.   

    由于我对C不熟, 只能说说我的思路, 只作参考:
    在Delphi中, 我用的是一个TMainMenu的控件(它已提供动态增减菜单的函数), 然后有运行时动态加入菜单项, 并从Resource中读出字符串来设置它的Caption, hint等的可视内容.
    在VC中, 好像也有这样的菜单类...
      

  13.   

    感谢各位的帮助,在大家的提示下,我已经实现了动态更换资源的功能。
    现将学习成功共享如下:
    更换菜单:
    void CMainFrame::OnViewEnglish() 
    {    HMODULE hCurrentModule;
        
        if (m_hLanguageDLL)
        {
            FreeLibrary(m_hLanguageDLL); 
            m_hLanguageDLL=NULL;
            hCurrentModule=GetModuleHandle(NULL);
    }
        else
    //        hCurrentModule=m_hLanguageDLL=LoadLibrary(_T("scribdeu"));
    hCurrentModule=m_hLanguageDLL=LoadLibrary(_T("English.dll"));    ASSERT(hCurrentModule); //is the resource DLL existent?
        
        AfxSetResourceHandle(hCurrentModule); CMenu DefaultMenu;    CMenu *pMenu = GetMenu();
        ASSERT(pMenu ); DefaultMenu.LoadMenu(IDR_MAINFRAME); SetMenu(&DefaultMenu); DefaultMenu.Detach();
    }更换按钮的文字:
    void CAboutDlg::OnEnglish() 
    {
    // TODO: Add your control notification handler code here
     HINSTANCE m_htest;
     m_htest = NULL;
     char* buf = NULL;
     int buflen = 200;
     buf = new char[buflen];  HINSTANCE m_hLangDLL3; // handle to LoadLibrary from .DLL file      m_hLangDLL3 = ::LoadLibrary("English.dll");
     
     if ( !(::LoadString(m_hLangDLL3, IDS_RESTART, buf, buflen)) )
     {
      AfxMessageBox("Load string error");
     }
     else
     {
    //   AfxMessageBox(buf);
      m_ctlChange1.SetWindowText(buf);
     }
    }