DELPHI资源文件使用

) 初级应用篇 :
 
资源文件一般为扩展名为 res 的文件 . VC 中资源文件用得非常普遍 , Delphi 在其联机帮助中对资源文件没作什么介绍 , 其实利用其自带的资源编译工具 BRCC32.EXE( 一般位于 /Delphi/BIN 目录下) , 我们完全可以做出跟 VC 一样效果的文件来。
 
资源文件最大的好处是能将一些在必要时才调用的文件跟可执行文件一起编译 , 生成一个文件 . 这样做最大的好处就是使外部文件免遭破坏 . 例如在一条程序中你要临时调用一幅图片 , 一般作法是把图片放在某一路径下(通常是主程序所在路径) , 但如果用户路径误删你的图片文件 , 则可能使程序找不到相应文件而出错崩溃 . 另外 , 如果你想自己的程序界面美观 , 想用一些自定义光标 , 也要用到资源文件。

) 初级应用篇 :
 
资源文件一般为扩展名为 res 的文件 . VC 中资源文件用得非常普遍 , Delphi 在其联机帮助中对资源文件没作什么介绍 , 其实利用其自带的资源编译工具 BRCC32.EXE( 一般位于 /Delphi/BIN 目录下) , 我们完全可以做出跟 VC 一样效果的文件来。
 
资源文件最大的好处是能将一些在必要时才调用的文件跟可执行文件一起编译 , 生成一个文件 . 这样做最大的好处就是使外部文件免遭破坏 . 例如在一条程序中你要临时调用一幅图片 , 一般作法是把图片放在某一路径下(通常是主程序所在路径) , 但如果用户路径误删你的图片文件 , 则可能使程序找不到相应文件而出错崩溃 . 另外 , 如果你想自己的程序界面美观 , 想用一些自定义光标 , 也要用到资源文件。
 
资源文件的使用步骤为:
1.
编写 rc 脚本文本
用记事本或其它文本编辑器编写一个扩展名为 rc 的文件。例如:

mycur cursor move.cur // 加入光标
mypic Bitmap Water.BMP //
加入位图
mywav WAVE happy.wav //
加入声音
myAVI AVI EPOEN.AVI //
加入视频
myIco ICON CJT.ICO //
加入图标

  格式分别为在资源文件中的名称 -> 类型 -> 实际文件名称,例如上面第一行定义一个名为 mycur 的光标,实际名称为加入光标 move.cur.
2.
rc 文件编译成 res 资源文件
 
将脚本文件和实际文件拷到 Brcc32.EXE 所在目录,执行 DOS 命令。格式为: Brcc32 脚本文件 ( 回车 ) ,例如有一名为 myfirst.rc 的脚本文件,则执行 Brcc32 myfirst.rc( 回车 ) 即可。如果你是懒人,也可新建一批处理文件,内容只有一行: Brcc32 mufist.rc.( 因为 Delphi 安装后一般会在自动批处理文件中指明搜索路径的。 ) 如果编译成功,则会生成一个结尾为 res 的文件,这个文件就是我们需要的资源文件。
3.
Delphi 单元中加入资源文件
 
将生成的 res 资源文件拷贝到你所编程序的路径下,在单元文件 {$R *DFM} 后加上一句 {$R mufirst.res} ,则将 res 文件加入去,编译后资 源文件即已包含在可执行文件中了。若你有多个资源文件,也按上法依次加入。
4.
Delphi 程序中调用资源文件
 
资源文件在 Delphi 中的关键字为 hinstance. 下面给出具体用法 .
<1>
光标的调用
 
首先在程序中定义一个值大于 0 的常量,因为 Delphi 本身用 0- 16 来索引默认的光标,所以我们制定的光标应从表面上 1 开始索引。然后在窗口的 Oncreat 事件中添加以下代码:
screen.cursor[35]:=Loadcursor (hinstance,''mycur'');
 
其中 35 为大于 1 的常量, mycur 为光标在资源文件中的名字。如果希望在其他控件上使用定制光标,例如 Panel 控件,只需在程序的适当处加入以下代码:
Panel1.cursor:=35;
<2>
位图的调用
 
新建一项工程,添加一 Timage 控件,在需要显示的地方写以下代码:
Var mymap:Hbitmap;
begin
mymap:=LoadBitmap(hinstance,''mypic'');
Image1.picture.Bitmap.Handle:=mymap

end;
 
其中 "mypic" 为位图资源文件中的名称。
3 AVI 文件的调用
新建一工程,添加一 Animate 控件,在需要的地方加入:
animater1.resname:=''myAVI'';
animater1.Active:=true;
其中 myAVI 为视频文件在资源文件中的名称。
4 〉调用 WAV 文件
 
uses 中加入 mmsystem 单元,以便在程序中播放 WAV 文件。播放时 Playsound(pchar(''mywav''),hinstance,sndsync or snd_resource); 其中 mywav 为声音文件在资源中的名称。
5 〉加入光标
 
加入光标比较容易,只要将 res 文件加入单元文件中即可。但需注意 , 名称最好取 "W"."WW" 等,使第一个字母尽量靠后,以免与主程序的图标顺序颠倒。这样一来,别人在使用你的程序时如果想选择其它图标就有很多选择了。
补充:
1.
资源类型除上述类型外,还可以字体文件,字符串文件等。
2.
资源文件不但可以在标准图形界面下使用还可在控制台下使用。
下面我们来试验一下:
 
新建一工程,将唯一的一个 Form 删除,然后修改工程文件。增加一句 {$Apptype console}, uses 子句中加入 mmsystem, 并将其它引用单元删掉。将 Begin end 之间语句删掉。至此,我们就可和 Turbo PASCAL 下编程序一样,且还可以调用 windows API 和资源。将资源文件 ----{$R myfist.res} 加入。在 Begin end 之间写下:
writeln(''
演示程序,按任意键开始! '');
readln;
playsound(pchar(''mywav''),hinstance,snd_sync or snd_resource);
writeln(''
演示结束! '');
 
运行程序,将弹出一个标准 DOS 窗口,按任意键播放声音文件。是不是很 COOL ! 我曾下载过一个播放器,在其安装目录下我发现有一 "DOS 程序 ", 用鼠标双击它便弹出一个 DOS 窗口,显示 DOS 时代特有的画图,并有背景音乐!可能就是用这个方法做的。
3.Delphi
本身自带了一个叫 Image Editor 的工具,同样可以编辑资源文本,但和本文的方法比较,可得出下表:

***********************************************************
Image Editor                Brcc32

BMP                  16 位色          任意色

光标                   黑白两色                    任意色

ICO                             16 位色             任意色

AVI                 不支持                          支持

WAV              不支持                          支持

字体
字符串           不支持                          支持
其他
**************************************************************

  上面说的是直接在程序本身的调用。其实资源文件还有其它用法。比如说在你的程序携带其它文件,要用的时候释放出来。
例如 : myexe exefile ''ha1.exe''// 脚本文件
下面是自定义释放函数 ExtractRes ,本例中使用如下 :
ExtractRes(''exefile'',''myexe'',''c:/new.exe'');
就把 ha1.exe new.exe 为名字保存到 C 盘根目录下了 .

function TForm1.ExtractRes(ResType, ResName, ResNewName: string): boolean;
var
Res: TResourceStream;
begin
try
Res := TResourceStream.Create(Hinstance, Resname, Pchar(ResType));
try
Res.SavetoFile(ResNewName);
Result := true;
finally
Res.Free;
end;
except
Result := false;
end;
----------------------------------------------------------------------
( ) 中级应用篇 :
 
上面我们已经知道如何把一副 BMP 图像从资源文件里面读出来 , 但是 BMP 文件太大了 ,JPG 文件应用的相对较多 . 那么如何把 JPG 图像读出来呢 ? 用资源文件加流方式即可。具体方法如下 :
(1)MyJpg JPEG
  My.JPG
(2)Var
    Stream:TStream;
    MyJpg:TJpegImage;
   Begin
    Stream := TResourceStream.Cceat(HINSTANCE,''MyJpg'',''JPEG'');
    Try
      MyJpg:=TJpegImage.Create;
     Try
       MyJpg.LoadfromStream(Stream);
       Image1.Picture.Assignc(MyJpg);
     Finally
       MyJpg.Free;
     end;
    Finally
     Stream.Free;
    end;
   end;
 
读取其它图片文件也是一样的 . 比如说 gif 动画文件,当然前提是你有一个 gif.pas ,这个单元很多站点都有的,可以自己去找找。实际应用中我还发现用上面的代码可以直接显示资源文件中的 ICON BMP.
 
说到图形处理 , 实际上还可以用 Delphi 创建、调用纯图标资源的 DLL. 比如说你可以看看超级解霸目录下的 Dll, 很多就是纯图标资源而已。具体方法如下 :
(1):
创建一个 Hicon.RES 文件 , 这里不再重复 .
(2):
新建一文本文件 Icon.dpr, 内容如下 :
library Icon;
{$R Icon.RES}
begin
end.
Delphi 打开编译即可得到 Icon.dll.
(3):
实际调用方法如下 :
......
  Private
   Hinst:THANDLE;
......
  Var   Hicon:THANDLE;
begin
  Hinst:=Loadlibrary(''Icon.dll'');
  If   Hinst=0   Then   Exit
  Hicon:=Loadicon(Hinst,Pchar(Edit1.Text));
If
  Hicon<>0   Then   Image1.Picture.Icon.Handle:=Hicon;
  FreeLibrary(Hinst);
end;
 
如果你的程序想在国际上供使用不同语言的人使用的话 , Dll 来存放字符资源将是一个好方法 . 因为 Dll 不象 ini 文件那样可以被人随便修改 , 特别是有时侯如果想保存一些版权信息的话用 Dll 就再好不过了。比如说你准备开发一个 " 汉字简繁体翻译器 " 软件 , 准备提供 Gb32,Big5 码和英文三种语言菜单给用户 , 那么你可以试试用 Dll 来保存字符资源 .
 
我们需要建立三个 Dll. 第一步当然是写 Rc 文件 , Gb32 码为例 , 内容如下 :
/*MySc.rc*/
#define IDS_MainForm_Caption 1
#define IDS_BtnOpen_Caption 2
#define IDS_BtnSave_Caption 3
#define IDS_BtnBig5_Caption 4
#define IDS_BtnGb32_Caption 5
#define IDS_BtnHelp_Caption 6
#define IDS_Help_Shelp 7
Stringtable
{
IDS_MainForm_Caption,"
汉字简繁体翻译器 "
IDS_BtnOpen_Caption,"
打开文件 "
IDS_BtnSave_Caption,"
保存文件 "
IDS_BtnBig5_Caption,"
转换成 Big5"
IDS_BtnGb32_Caption,"
转换成 Gb32"
IDS_BtnHelp_Caption,"
帮助 "
IDS_Help_Shelp,"
输入文字或打开文件后按需要点击按钮即可转换 !"
}
 
第二步是 Brcc32 编译为 Res 文件后用上面的方法得到 Dll 文件 , 另外两个 Dll 用同样的方法生成 . 下面来应用一下 :
 
新建一个工程 , 放上五个 Button:BtnOpen,BtnSave,BtnBig5,BtnGb32 BtnHelp. 还有一个 TComboBox:CbSelect 用来选择语言种类的 .
具体代码如下 :
unit Unit1;
interface
......
private
SHelp: string;
function SearchLanguagePack: TStrings;
procedure SetActiveLanguage(LanguageName: string);
{ Private declarations }
......
implementation
procedure TForm1.CbSelectChange(Sender: TObject);
begin
SetActiveLanguage(CbSelect.Text);//
调用相应 Dll 文件读取相应字符 .
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
CbSelect.Items.AddStrings(SearchLanguagePack);//
搜索当前目录下所有的 Dll 文件名称
end;
function TForm1.SearchLanguagePack: TStrings;
var
ResultStrings: TStrings;
DosError: integer;
SearchRec: TsearchRec;
begin
ResultStrings := TStringList.Create;
DosError := FindFirst(ExtractFilePath(ParamStr(0)) + ''*.dll'', faAnyFile, SearchRec);
while DosError = 0 do
begin
ResultStrings.Add(ChangeFileExt(SearchRec.Name, ''''));
DosError := FindNext(SearchRec);
end;
FindClose(SearchRec);
Result := ResultStrings;
end;

procedure TForm1.SetActiveLanguage(LanguageName: string);
var
Hdll: Hmodule;
MyChar: array[0..254] of char;
DllFileName: string;
begin
DllFileName := ExtractFilePath(ParamStr(0)) + LanguageName + ''.dll'';
if not FileExists(DllFileName) then Exit;
Hdll := loadlibrary(Pchar(DllFileName));

Loadstring(hdll, 1, MyChar, 254);
Self.Caption := MyChar;
//
读取字符资源, 1 表示资源文件中定义的 1
Loadstring(hdll, 1, MyChar, 254);
Self.Caption := MyChar;

Loadstring(hdll, 2, MyChar, 254);
BtnOpen.Caption := MyChar;

Loadstring(hdll, 3, MyChar, 254);
BtnSave.Caption := MyChar;

Loadstring(hdll, 4, MyChar, 254);
BtnBig5.Caption := MyChar;

Loadstring(hdll, 5, MyChar, 254);
BtnGb32.Caption := MyChar;

Loadstring(hdll, 6, MyChar, 254);
BtnHelp.Caption := MyChar;

Loadstring(hdll, 7, MyChar, 254);
SHelp := MyChar;

Freelibrary(hdll);
Application.Title := Self.Caption;
//------------------------
BtnOpen.Visible := True;
BtnSave.Visible := True;
BtnBig5.Visible := True;
BtnGb32.Visible := True;
BtnHelp.Visible := True;
//------------------------
end;
procedure TForm1.BtnHelpClick(Sender: TObject);
begin
Application.MessageBox(Pchar(SHelp), ''Http://lovejingtao.126.com'', MB_ICONINFORMATION);
end;
end.
 
可能你会说 , 这种方法还不如我自己在程序中直接定义三种具体的值来的方便 . 甚至我自己自定义一个结构好了,用不着用 DLL 那么麻烦的。但是如果你的程序要用的字符很多呢 ? 比如说 Windows 操作系统 , 本身就有简体中文 , 繁体中文 , 英文等等版本 , Dll 的话只要直接替换 DLL 即可 , 而不用每发行一个版本就打开代码来修改一次。这样一来可以大大减少工作量和出错的机会 . 说到这里 , 再多说一句 :Windows 系统本身很多 Dll 带有了图片等资源 , 我们可以在程序中直接调用 , 这样一来我们的 EXE 也可以减少不少 ! 当然最小的方法是实时生成技术 . 老外曾经写了一个 67KB 的程序就是利用了这个方法 . 感兴趣的朋友可以到 http://go4.163.com/lovejingtao/ha1.exe 下载 .
----------------------------------------------------------------------
( ) 高级应用篇 :
   Delphi
是个很有效率的开发工具 , 但是它有一个缺点就是生成的 EXE 文件太大 . 一个程序就算只有一个空窗口体积也有 286KB. 如果直接用 API 来写的话程序体积是小了 , 但是又太繁琐 , 无法立即看到界面效果 , 根本谈不上是可视化开发 . 其实并非 " 鱼与熊掌不可兼得 ", 利用资源文件我们就可以轻松达到这个目的 .
 
在开始之前 , 我们需要一个可以编辑资源文件的工具 . 这类工具很多 , 比如说 Resource WorkShop 就是非常好的一个 . 如果一时找不到 , 利用 VC 的编辑器来也是可以的 . 下面我们就以 VC 的为例示范如何创建一个窗口资源文件 . 运行 VC, 打开菜单 File-->New, 将出现一个多项选择页 . 我们选择 Files-->ResourceTemplate, 在右边的 File 填上 Demo,Location 选择保存路径 , 然后点击按钮 OK 返回 VC 开发环境 .
 
选择菜单 Insert-->Resource, 将出现一个资源类型选择框 . 我们把鼠标移到 Dialog 上面 . 不用展开 , 点击右边的 New 即可 , 这时候返回 VC 开发环境并出现一个只有关闭按钮和两个 Button 的窗体 . 将鼠标选定窗体 , 击右键选择最后一项 Properties, 将出现一个设置窗口 , ID 改为 "MAINFORM"( 注意 : 跟下面添加的其它控件的属性设置方法不同 , 主窗口的 ID 必须把双引号写上去 , 而且名称必须为大写 . 否则程序将找不到资源 . 程序会一运行就退出了 .)Caption 改为 " 安装程序 ", 这时候可以立刻看到窗口的标题变成了 " 安装程序 ", Styles Minimize box 选上 ,More Styles Center 勾上使程序运行时的位置居中 . 当然你也可以设置它的坐标 . 其它保留默认值即可 . 回到开发环境 , 在控件框里面分别选择一个 Static Text, 一个 Edit Box, 一个 Button 和一个 Group Box 添加到窗体上面 . 把它们按照自己的爱好排列整齐 . 然后逐个修改它们的属性 . 方法就是按照上面说的选定控件后击右键选择最后一项 Properties, 在出现的属性框里面修改 . 其中属性如下 :Group Box Caption 属性清空 ,Static Text Caption 属性改为 " 请选择安装目录 :",Edit Box ID 改为 10001. 第一个 Button ID 10002,Caption 属性为 " 选择 ", 第二个 Button ID 10003, Caption 属性为 " 安装 ", 第三个 Button ID 10004,Caption 属性为 " 退出 ". 为了使程序更加完美 , 我们为它再添加一个菜单 IDR_MENU1. 选择 Insert-->Resource-->Menu, 我们这里只简单添加一项 " 文件 --> 退出 ", 其中 " 退出 " ID 10005. 然后在主窗口的属性 Menu 设定为 IDR_MENU1 即可 .
 
为了使程序更加美观 , 我们再添加一个小图标 , 同时这也将是我们程序的图标 . 选择 Insert-->Resource-->Icon-- >Import, 选择一个图标文件 . 并将它的 ID 设置为 "MAINICON"( 注意 : 必须把双引号写上而且字母为大写 ), 为窗口添加一个 Picture 控件并设置它的属性 Type:Icon,Image 下拉选择刚才的图标 MainIcon 即可 .
 
如果你想为程序在鼠标添加一些信息也是可以的 . 选择 Insert-->Resource-->Version 即可 .
 
到这里我们已经完成了一个简单的 " 安装程序 " 的窗体设计 . 实际上我们现在就可以在 Delphi 中调用它了 . 我们先把 " 劳动成果 " 保存起来 . 选择 File- ->Save As, 在文件类型里选择 "32-bit Resource File(.res)" 保存为 "Demo.res", 文件大小大约为 2.65KB.
新建一个扩展名为 dpr 的文本文件 MyDemo.Dpr, 键入如下代码 :
Uses Windows,Messages;
{$R Demo.Res}
function MainDialogProc(DlgWin:hWnd;DlgMessage:UINT;DlgWParam:WPARAM;DlgLParam:LPARAM):integer;stdcall;
begin
Result := 0;
case DlgMessage of
WM_Close:
begin
PostQuitMessage(0);
Exit;
end;
end;
end;
begin
DialogBox(hInstance, ''MAINFORM'', 0, @MainDialogProc);
end.
 
Delphi 打开它编译一次即可产生一个大小为 19KB EXE. 是不是很小 ! 实际上 , 你甚至只用一行代码就把它 Show 出来 , 不过程序无法关闭而已 .
Uses Windows;
{$R Demo.Res}
function MainDialogProc: integer;
begin
Result := 0;
end;
begin
DialogBox(hInstance, ''MAINFORM'', 0, @MainDialogProc);
end.
 
上面的程序只不过是一个空窗口而已 , 现在我们来写代码响应按下相应按钮响应的事件 . 完整代码如下 :
program MyDemo;
uses Windows, Messages, shlobj;
const
ID_Edit = 10001;
ID_Selet = 10002;
ID_Setup = 10003;
ID_Quit = 10004;
ID_Exit = 10005;
{$R Demo.Res}
var
MainWin: HWND;

function My_Gettext: string;
var
Textlength: Integer;
Text: PChar;
s: string;
begin
TextLength := GetWindowTextLength(GetDlgItem(MainWin, ID_Edit));
GetMem(Text, TextLength + 1);
GetWindowText(GetDlgItem(MainWin, ID_Edit), Text, TextLength + 1);
s := text;
FreeMem(Text, TextLength + 1);
Result := s;
end;

function Getmyname: string;
var
i, j: integer;
begin
J := 3;
for i := 1 to length(ParamStr(0)) do
if ParamStr(0)[i] = ''/'' then J := I;
Result := copy(ParamStr(0), J + 1, length(ParamStr(0)) - J);
end;

function SelectDirectory(handle: hwnd; const Caption: string; const Root:WideString;outDirectory:string): Boolean;
var
lpbi: _browseinfo;
buf: array[0..MAX_PATH] of char;
id: ishellfolder;
eaten, att: cardinal;
rt: pitemidlist;
initdir: pwidechar;
begin
result := false;
lpbi.hwndOwner := handle;
lpbi.lpfn := nil;
lpbi.lpszTitle := pchar(caption);
lpbi.ulFlags := BIF_RETURNONLYFSDIRS + BIF_EDITBOX;
SHGetDesktopFolder(id);
initdir := pwchar(root);
id.ParseDisplayName(0, nil, initdir, eaten, rt, att);
lpbi.pidlRoot := rt;
getmem(lpbi.pszDisplayName, MAX_PATH);
try
result := shgetpathfromidlist(shbrowseforfolder(lpbi), buf);
except
freemem(lpbi.pszDisplayName);
end;
if result then
begin
directory := buf;
if length(directory) <> 3 then directory := directory + ''/'';
end;
end;

function MainDialogProc(
DlgWin: hWnd;
DlgMessage: UINT;
DlgWParam: WPARAM;
DlgLParam: LPARAM
)
: integer; stdcall;
var
MyIcon: HICON;
Sdir: string;
begin
Result := 0;
case DlgMessage of
WM_INITDIALOG:
begin
MyIcon := LoadIcon(hInstance, ''MainIcon'');
SetClassLONG(DlgWin, GCL_HICON, MyIcon);
MainWin := DlgWin;
end;
WM_Close:
begin
PostQuitMessage(0);
Exit;
end;
WM_COMMAND:
case LOWORD(DlgWParam) of

ID_Selet:
begin
if SelectDirectory(DlgWin, ''
请选择安装目录 '', '''', Sdir)
then SendMessage(GetDlgItem(DlgWin, ID_Edit), WM_SETTEXT, 0, lParam(pChar(Sdir)));
end;
ID_Setup:
begin
if My_Gettext = '''' then
begin
MessageBox(DlgWin, ''
请先选择安装文件夹 !'', '' 信息 '', MB_ICONINFORMATION + MB_OK);
Exit;
end;
CopyFile(pchar(ParamStr(0)), pchar(My_Gettext + Getmyname), false);
MessageBox(DlgWin, ''
安装完毕 !'', '' 信息 '', MB_ICONINFORMATION + MB_OK);
PostQuitMessage(0);
Exit;
end;
ID_Quit:
begin
PostQuitMessage(0);
EXIT;
end;
ID_Exit:
begin
if MessageBox(DlgWin, ''
你点击了菜单 " 退出 " ,你确定退出程序吗 ?'', '' 信息 '', MB_ICONQUESTION + MB_OKCANCEL) = IDOK then
PostQuitMessage(0);
Exit;
end;
end;
end;
end;
begin
DialogBox(hInstance, ''MAINFORM'', 0, @MainDialogProc);
end.
 
其中 SelectDirectory 函数的作用是返回一个选择的文件路径 . 然后把自己拷贝到选择的目录下 , 当然很多处理没有写 , 读者可以自行添加 . 文件编译后大小为 22KB, 如果直接用 Delphi VCL 来写的话 , 将为 338KB! 完整代码可以在我的主页上下载 :http: //go4.163.com/lovejingtao/setup2.zip. 代码中的消息处理相信大家看的懂 . 如果不用资源文件而直接用 API 来写将对它更加理解深刻 .
 
全部代码在 Delphi+Pwin2000 下通过 .

 

 

 

 

 

 

 

资源文件可以用程序执行来编译   

1/ BeginUpdateResource        // 获得被编辑的 EXE 文件的句柄

2/ UpdateResource              // 更新被编辑 EXE 的资源文件

3/ EndUpdateRescource        // 结束更新

                               是否删除已存在的资源 FALSE 保留原来资源 /TRUE 删除原来资源

BeginUpdateResource(EXE 文件名 , FALSE  )     返回句柄

                    类型 资源名   资源编号 更新内容 ( 指针 )      内容长度

UpdateResource( 句柄 , 'TXT' , 'MYKEY' , 2052 , PChar(key_name) , length(key_name))    返回 BOOLEAN

                        是否写入已存在的资源 FALSE 写入

EndUpdateResource( 句柄 ,  false );   返回 BOOLEAN

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值