Delphi 对话框实现源码分析
Delphi 对话框实现源码分析
简介
在这篇文章中,我将大概的从Delphi XE2 的Dialogs单元入手,分析ShowMessage,MessageBox等对话框运行原理,希望能帮助你理解Delphi,不求你爱上她,只求让你能快速地解决问题。
跟踪代码
为了了解这些对话框的运行原理,我们需要跟踪进源代码中去,为此,你需要做如下设置
1. 简单创建一个使用了ShowMessage的VCL应用程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class (TForm) Edit1: TEdit; Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end ; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1 . Button1Click(Sender: TObject); begin ShowMessage(Edit1 . Text); MessageBox(Self . Handle, PChar (Edit1 . Text), PChar (Application . Title), MB_ICONINFORMATION or MB_OK); MessageDlg(Edit1 . Text,mtInformation,[mbOK,mbCancel], 0 ); end ; end . |
2. 在29行里设置一个断点, 再在Edit里输入一些内容,按下Message Box按钮, 按F7跟踪到Dialogs单元, 经过一段时间的仔细跟踪, 你会发现程序运行到下面一段代码:
1
2
3
4
5
6
7
8
9
10
11
|
function MessageDlgPosHelp( const Msg: string ; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; HelpCtx: Longint ; X, Y: Integer ; const HelpFileName: string ): Integer ; begin if (Win32MajorVersion >= 6 ) and UseLatestCommonDialogs and ThemeServices . ThemesEnabled then Result := DoTaskMessageDlgPosHelp( '' , Msg, DlgType, Buttons, HelpCtx, X, Y, HelpFileName) else Result := DoMessageDlgPosHelp(CreateMessageDialog(Msg, DlgType, Buttons), HelpCtx, X, Y, HelpFileName); end ; |
函数MessageDlgPosHelp指出, 如果当前系统是Vista,sever2008或以上版本的系统,那就调用DoTaskMessageDlgPosHelp函数进行对话框显示, 否则调用DoMessageDlgPosHelp显示对话框. 继续跟踪DoTaskMessageDlgPosHelp函数, 你会发现如下一段代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
function TCustomTaskDialog . DoExecute(ParentWnd: HWND): Boolean ; const CTaskDlgFlags: array [TTaskDialogFlag] of Cardinal = ( TDF_Enable_Hyperlinks, TDF_Use_Hicon_Main, tdf_Use_Hicon_Footer, TDF_ALLOW_DIALOG_CANCELLATION, TDF_USE_COMMAND_LINKS, TDF_USE_COMMAND_LINKS_NO_ICON, TDF_EXPAND_FOOTER_AREA, TDF_EXPANDED_BY_DEFAULT, TDF_VERIFICATION_FLAG_CHECKED, TDF_SHOW_PROGRESS_BAR, TDF_SHOW_MARQUEE_PROGRESS_BAR, TDF_CALLBACK_TIMER, TDF_POSITION_RELATIVE_TO_WINDOW, TDF_RTL_LAYOUT, TDF_NO_DEFAULT_RADIO_BUTTON, TDF_CAN_BE_MINIMIZED); CTaskDlgCommonButtons: array [TTaskDialogCommonButton] of Cardinal = ( TDCBF_OK_BUTTON, TDCBF_YES_BUTTON, TDCBF_NO_BUTTON, TDCBF_CANCEL_BUTTON, TDCBF_RETRY_BUTTON, TDCBF_CLOSE_BUTTON); CTaskDlgDefaultButtons: array [TTaskDialogCommonButton] of Integer = ( IDOK, IDYES, IDNO, IDCANCEL, IDRETRY, IDCLOSE); var LWindowList: TTaskWindowList; LModalResult: Integer ; LRadioButton: Integer ; LFlag: TTaskDialogFlag; LFocusState: TFocusState; LVerificationChecked: LongBool; LTaskDialog: TTaskDialogConfig; LCommonButton: TTaskDialogCommonButton; begin if Win32MajorVersion < 6 then raise EPlatformVersionException . CreateResFmt( {$IFNDEF CLR}@{$ENDIF} SWindowsVistaRequired, [ClassName]); if not ThemeServices . ThemesEnabled then raise Exception . CreateResFmt( {$IFNDEF CLR}@{$ENDIF} SXPThemesRequired, [ClassName]); {$IF NOT DEFINED(CLR)} FillChar(LTaskDialog, SizeOf(LTaskDialog), 0 ); { $IFEND } with LTaskDialog do begin // Set Size, Parent window, Flags cbSize := SizeOf(LTaskDialog); hwndParent := ParentWnd; dwFlags := 0 ; for LFlag := Low(TTaskDialogFlag) to High(TTaskDialogFlag) do if LFlag in FFlags then dwFlags := dwFlags or CTaskDlgFlags[LFlag]; // Set CommonButtons dwCommonButtons := 0 ; for LCommonButton := Low(TTaskDialogCommonButton) to High(TTaskDialogCommonButton) do if LCommonButton in FCommonButtons then dwCommonButtons := dwCommonButtons or CTaskDlgCommonButtons[LCommonButton]; // Set Content, MainInstruction, Title, MainIcon, DefaultButton if FText <> '' then pszContent := {$IFNDEF CLR}PWideChar{$ENDIF} ( WideString (FText)); if FTitle <> '' then pszMainInstruction := {$IFNDEF CLR}PWideChar{$ENDIF} ( WideString (FTitle)); if FCaption <> '' then pszWindowTitle := {$IFNDEF CLR}PWideChar{$ENDIF} ( WideString (FCaption)); if tfUseHiconMain in FFlags then hMainIcon := FCustomMainIcon . Handle else begin if FMainIcon in [tdiNone .. tdiShield] then pszMainIcon := LPCWSTR(CTaskDlgIcons[FMainIcon]) else pszMainIcon := LPCWSTR(MakeIntResourceW( Word (FMainIcon))); end ; nDefaultButton := CTaskDlgDefaultButtons[FDefaultButton]; // Set Footer, FooterIcon if FFooterText <> '' then pszFooter := {$IFNDEF CLR}PWideChar{$ENDIF} ( WideString (FFooterText)); if tfUseHiconFooter in FFlags then hFooterIcon := FCustomFooterIcon . Handle else begin if FFooterIcon in [tdiNone .. tdiShield] then pszFooterIcon := LPCWSTR(CTaskDlgIcons[FFooterIcon]) else pszFooterIcon := LPCWSTR(MakeIntResourceW( Word (FFooterIcon))); end ; // Set VerificationText, ExpandedInformation, CollapsedControlText if FVerificationText <> '' then pszVerificationText := {$IFNDEF CLR}PWideChar{$ENDIF} ( WideString (FVerificationText)); if FExpandedText <> '' then pszExpandedInformation := {$IFNDEF CLR}PWideChar{$ENDIF} ( WideString (FExpandedText)); if FExpandButtonCaption <> '' then pszCollapsedControlText := {$IFNDEF CLR}PWideChar{$ENDIF} ( WideString (FExpandButtonCaption)); // Set Buttons cButtons := FButtons . Count; if cButtons > 0 then pButtons := FButtons . Buttons; if FButtons . DefaultButton <> nil then nDefaultButton := FButtons . DefaultButton . ModalResult; // Set RadioButtons cRadioButtons := FRadioButtons . Count; if cRadioButtons > 0 then pRadioButtons := FRadioButtons . Buttons; if not (tfNoDefaultRadioButton in FFlags) and (FRadioButtons . DefaultButton <> nil ) then nDefaultRadioButton := FRadioButtons . DefaultButton . ModalResult; // Prepare callback {$IF DEFINED(CLR)} pfCallBack := @CallbackProc; { $ELSE } lpCallbackData := LONG_PTR(Self); pfCallback := @TaskDialogCallbackProc; { $IFEND } end ; LWindowList := DisableTaskWindows(ParentWnd); LFocusState := SaveFocusState; try Result := TaskDialogIndirect(LTaskDialog, {$IFNDEF CLR}@{$ENDIF} LModalResult, {$IFNDEF CLR}@{$ENDIF}LRadioButton, {$IFNDEF CLR}@{$ENDIF} LVerificationChecked) = S_OK; FModalResult := LModalResult; if Result then begin FButton := TTaskDialogButtonItem(FButtons . FindButton(FModalResult)); FRadioButton := TTaskDialogRadioButtonItem(FRadioButtons . FindButton(LRadioButton)); if LVerificationChecked then Include(FFlags, tfVerificationFlagChecked) else Exclude(FFlags, tfVerificationFlagChecked); end ; finally EnableTaskWindows(LWindowList); SetActiveWindow(ParentWnd); RestoreFocusState(LFocusState); end ; end ; |
上面这段代码在Dialogs单元的第5407行, 该函数先进行可用性判断, 然后填充
1
|
LTaskDialog: TTaskDialogConfig; |
一个TTaskDialogConfig的结构体, 该结构体定义在CommCtrl单元第9550行, 其定义如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
type { $EXTERNALSYM TASKDIALOGCONFIG} TASKDIALOGCONFIG = packed record cbSize: UINT; hwndParent: HWND; hInstance: HINST; // used for MAKEINTRESOURCE() strings dwFlags: DWORD; // TASKDIALOG_FLAGS (TDF_XXX) flags dwCommonButtons: DWORD; // TASKDIALOG_COMMON_BUTTON (TDCBF_XXX) flags pszWindowTitle: LPCWSTR; // string or MAKEINTRESOURCE() case Integer of 0 : (hMainIcon: HICON); 1 : (pszMainIcon: LPCWSTR; pszMainInstruction: LPCWSTR; pszContent: LPCWSTR; cButtons: UINT; pButtons: PTaskDialogButton; nDefaultButton: Integer ; cRadioButtons: UINT; pRadioButtons: PTaskDialogButton; nDefaultRadioButton: Integer ; pszVerificationText: LPCWSTR; pszExpandedInformation: LPCWSTR; pszExpandedControlText: LPCWSTR; pszCollapsedControlText: LPCWSTR; case Integer of 0 : (hFooterIcon: HICON); 1 : (pszFooterIcon: LPCWSTR; pszFooter: LPCWSTR; pfCallback: TFTaskDialogCallback; lpCallbackData: LONG_PTR; cxWidth: UINT // width of the Task Dialog's client area in DLU's. // If 0, Task Dialog will calculate the ideal width. ); ); end ; {$EXTERNALSYM _TASKDIALOGCONFIG} _TASKDIALOGCONFIG = TASKDIALOGCONFIG; PTaskDialogConfig = ^TTaskDialogConfig; TTaskDialogConfig = TASKDIALOGCONFIG; |
该结构体其实是从MSDN里翻译过来的, 定义在CommCtrl.h 头文件里(需要Windows Vista, Windows Server 2008及以上版本, 我是用Windows 7 64位进行的测试), 详细说明可以查看MSDN.
TCustomTaskDialog.DoExecute 填充完LTaskDialog结构体后, 直接调用:
1
2
|
Result := TaskDialogIndirect(LTaskDialog, {$IFNDEF CLR}@{$ENDIF} LModalResult, {$IFNDEF CLR}@{$ENDIF}LRadioButton, {$IFNDEF CLR}@{$ENDIF} LVerificationChecked) = S_OK; |
TaskDialogIndirect显示对话框, TaskDialogIndirect定义在CommCtrl单元, 其代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
{ Task Dialog } var _TaskDialogIndirect: function ( const pTaskConfig: TTaskDialogConfig; pnButton: PInteger; pnRadioButton: PInteger; pfVerificationFlagChecked: PBOOL): HRESULT; stdcall; _TaskDialog: function (hwndParent: HWND; hInstance: HINST; pszWindowTitle: LPCWSTR; pszMainInstruction: LPCWSTR; pszContent: LPCWSTR; dwCommonButtons: DWORD; pszIcon: LPCWSTR; pnButton: PInteger): HRESULT; stdcall; function TaskDialogIndirect( const pTaskConfig: TTaskDialogConfig; pnButton: PInteger; pnRadioButton: PInteger; pfVerificationFlagChecked: PBOOL): HRESULT; begin if Assigned(_TaskDialogIndirect) then Result := _TaskDialogIndirect(pTaskConfig, pnButton, pnRadioButton, pfVerificationFlagChecked) else begin InitComCtl; Result := E_NOTIMPL; if ComCtl32DLL <> 0 then begin @_TaskDialogIndirect := GetProcAddress(ComCtl32DLL, 'TaskDialogIndirect' ); if Assigned(_TaskDialogIndirect) then Result := _TaskDialogIndirect(pTaskConfig, pnButton, pnRadioButton, pfVerificationFlagChecked) end ; end ; end ; |
查看代码知道, TaskDialogIndirect 直接调用ComCtrl32.Dll里的函数:TaskDialogIndirect 显示对话框. 通过查询MSDN了解TaskDialogIndirect API的用途与用法:
The TaskDialogIndirect function creates, displays, and operates a task dialog. The task dialog contains application-defined icons, messages, title, verification check box, command links, push buttons, and radio buttons. This function can register a callback function to receive notification messages.
函数TaskDialogIndirect 用于创建, 显示, 运行一个任务对话框, 这个任务对话框可以包括由应用程序定义的图标,消息,标题,复选框,按钮,单选框. 该函数还可以接收一个回调函数用于接收通知信息
看到这里你或许会问:
如果我的系统是xp或其他低于Vista, server2008的系统呢? 由上文中可知, 如果是低版本的系统, 则调用DoMessageDlgPosHelp 函数进行对话框显示, 调用代码如下:
1
2
|
Result := DoMessageDlgPosHelp(CreateMessageDialog(Msg, DlgType, Buttons), HelpCtx, X, Y, HelpFileName); |
DoMessageDlgPosHelp代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
function DoMessageDlgPosHelp(MessageDialog: TForm; HelpCtx: Longint ; X, Y: Integer ; const HelpFileName: string ): Integer ; begin with MessageDialog do try HelpContext := HelpCtx; HelpFile := HelpFileName; if X >= 0 then Left := X; if Y >= 0 then Top := Y; if (Y < 0 ) and (X < 0 ) then Position := poScreenCenter; Result := ShowModal; finally Free; end ; end ; |
从DoMessageDlgPosHelp代码中可见, 该函数只是简单的将传递进来的TForm以模式窗口的形式显示在指定的位置.
下面是CreateMessageDialog代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
function CreateMessageDialog( const Msg: string ; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; DefaultButton: TMsgDlgBtn): TForm; const mcHorzMargin = 8 ; mcVertMargin = 8 ; mcHorzSpacing = 10 ; mcVertSpacing = 10 ; mcButtonWidth = 50 ; mcButtonHeight = 14 ; mcButtonSpacing = 4 ; var DialogUnits: TPoint; HorzMargin, VertMargin, HorzSpacing, VertSpacing, ButtonWidth, ButtonHeight, ButtonSpacing, ButtonCount, ButtonGroupWidth, IconTextWidth, IconTextHeight, X, ALeft: Integer ; B, CancelButton: TMsgDlgBtn; {$IF DEFINED(CLR)} IconID: Integer ; { $ELSE } IconID: PChar ; { $IFEND } TextRect: TRect; LButton: TButton; begin Result := TMessageForm . CreateNew(Application); with Result do begin BiDiMode := Application . BiDiMode; BorderStyle := bsDialog; Canvas . Font := Font; KeyPreview := True ; PopupMode := pmAuto; Position := poDesigned; OnKeyDown := TMessageForm(Result).CustomKeyDown; DialogUnits := GetAveCharSize(Canvas); HorzMargin := MulDiv(mcHorzMargin, DialogUnits . X, 4 ); VertMargin := MulDiv(mcVertMargin, DialogUnits . Y, 8 ); HorzSpacing := MulDiv(mcHorzSpacing, DialogUnits . X, 4 ); VertSpacing := MulDiv(mcVertSpacing, DialogUnits . Y, 8 ); ButtonWidth := MulDiv(mcButtonWidth, DialogUnits . X, 4 ); for B := Low(TMsgDlgBtn) to High(TMsgDlgBtn) do begin if B in Buttons then begin if ButtonWidths[B] = 0 then begin TextRect := Rect( 0 , 0 , 0 , 0 ); Windows . DrawText( canvas . handle, {$IF DEFINED(CLR)} ButtonCaptions[B], - 1 , { $ELSE } PChar (LoadResString(ButtonCaptions[B])), - 1 , { $IFEND } TextRect, DT_CALCRECT or DT_LEFT or DT_SINGLELINE or DrawTextBiDiModeFlagsReadingOnly); with TextRect do ButtonWidths[B] := Right - Left + 8 ; end ; if ButtonWidths[B] > ButtonWidth then ButtonWidth := ButtonWidths[B]; end ; end ; ButtonHeight := MulDiv(mcButtonHeight, DialogUnits . Y, 8 ); ButtonSpacing := MulDiv(mcButtonSpacing, DialogUnits . X, 4 ); SetRect(TextRect, 0 , 0 , Screen . Width div 2 , 0 ); DrawText(Canvas . Handle, Msg, Length(Msg)+ 1 , TextRect, DT_EXPANDTABS or DT_CALCRECT or DT_WORDBREAK or DrawTextBiDiModeFlagsReadingOnly); IconID := IconIDs[DlgType]; IconTextWidth := TextRect . Right; IconTextHeight := TextRect . Bottom; {$IF DEFINED(CLR)} if DlgType <> mtCustom then { $ELSE } if IconID <> nil then { $IFEND } begin Inc(IconTextWidth, 32 + HorzSpacing); if IconTextHeight < 32 then IconTextHeight := 32 ; end ; ButtonCount := 0 ; for B := Low(TMsgDlgBtn) to High(TMsgDlgBtn) do if B in Buttons then Inc(ButtonCount); ButtonGroupWidth := 0 ; if ButtonCount <> 0 then ButtonGroupWidth := ButtonWidth * ButtonCount + ButtonSpacing * (ButtonCount - 1 ); ClientWidth := Max(IconTextWidth, ButtonGroupWidth) + HorzMargin * 2 ; ClientHeight := IconTextHeight + ButtonHeight + VertSpacing + VertMargin * 2 ; Left := (Screen . Width div 2 ) - (Width div 2 ); Top := (Screen . Height div 2 ) - (Height div 2 ); if DlgType <> mtCustom then {$IF DEFINED(CLR)} Caption := Captions[DlgType] else Caption := Application . Title; if DlgType <> mtCustom then { $ELSE } Caption := LoadResString(Captions[DlgType]) else Caption := Application . Title; if IconID <> nil then { $IFEND } with TImage . Create(Result) do begin Name := 'Image' ; Parent := Result; Picture . Icon . Handle := LoadIcon( 0 , IconID); SetBounds(HorzMargin, VertMargin, 32 , 32 ); end ; TMessageForm(Result).Message := TLabel . Create(Result); with TMessageForm(Result).Message do begin Name := 'Message' ; Parent := Result; WordWrap := True ; Caption := Msg; BoundsRect := TextRect; BiDiMode := Result . BiDiMode; ALeft := IconTextWidth - TextRect . Right + HorzMargin; if UseRightToLeftAlignment then ALeft := Result . ClientWidth - ALeft - Width; SetBounds(ALeft, VertMargin, TextRect . Right, TextRect . Bottom); end ; if mbCancel in Buttons then CancelButton := mbCancel else if mbNo in Buttons then CancelButton := mbNo else CancelButton := mbOk; X := (ClientWidth - ButtonGroupWidth) div 2 ; for B := Low(TMsgDlgBtn) to High(TMsgDlgBtn) do if B in Buttons then begin LButton := TButton . Create(Result); with LButton do begin Name := ButtonNames[B]; Parent := Result; {$IF DEFINED(CLR)} Caption := ButtonCaptions[B]; { $ELSE } Caption := LoadResString(ButtonCaptions[B]); { $IFEND } ModalResult := ModalResults[B]; if B = DefaultButton then begin Default := True ; ActiveControl := LButton; end ; if B = CancelButton then Cancel := True ; SetBounds(X, IconTextHeight + VertMargin + VertSpacing, ButtonWidth, ButtonHeight); Inc(X, ButtonWidth + ButtonSpacing); if B = mbHelp then OnClick := TMessageForm(Result).HelpButtonClick; end ; end ; end ; end ; |
由代码可见, CreateMessageDialog只是创建了一个TMessageForm, 然后动态地添加了一些设置. 写到这里或许可以解答一些人的问题: 对话框是不是一个窗口? 答案是:是.
你还可能会问: 为什么对话框可以停留在那一行代码直到用户操作完毕后再往下执行, 这里就需要了解一下模态窗口的知识: 请参见这篇文章 Delphi ShowModal解析
参考:
http://www.cnblogs.com/neugls/archive/2011/09/14/2176733.html
Delphi 对话框实现源码分析的更多相关文章
- 《深入理解Spark:核心思想与源码分析》(前言及第1章)
自己牺牲了7个月的周末和下班空闲时间,通过研究Spark源码和原理,总结整理的<深入理解Spark:核心思想与源码分析>一书现在已经正式出版上市,目前亚马逊.京东.当当.天猫等网站均有销售 ...
- Android源码分析-全面理解Context
前言 Context在android中的作用不言而喻,当我们访问当前应用的资源,启动一个新的activity的时候都需要提供Context,而这个Context到底是什么呢,这个问题好像很好回答又好像 ...
- YII框架源码分析(百度PHP大牛创作-原版-无广告无水印)
YII 框架源码分析 百度联盟事业部——黄银锋 目 录 1. 引言 3 1.1.Yii 简介 3 1.2.本文内容与结构 3 2.组件化与模块化 4 2.1.框架加载和运行流程 4 ...
- Robotium源码分析之运行原理
从上一章<Robotium源码分析之Instrumentation进阶>中我们了解到了Robotium所基于的Instrumentation的一些进阶基础,比如它注入事件的原理等,但Rob ...
- Kettle 4.2源码分析第四讲--KettleJob机制与Database插件简介(含讲解PPT)
1. Job机制 一个job项代表ETL控制流中的一项逻辑任务.Job项将会顺序执行,每个job项会产生一个结果,能作为别的分支上job项的条件. 图 1 job项示例 1.1. Job类图简介 图 ...
- TeamTalk源码分析(十一) —— pc客户端源码分析
--写在前面的话 在要不要写这篇文章的纠结中挣扎了好久,就我个人而已,我接触windows编程,已经六七个年头了,尤其是在我读研的三年内,基本心思都是花在学习和研究windows程序上 ...
- 一个由正则表达式引发的血案 vs2017使用rdlc实现批量打印 vs2017使用rdlc [asp.net core 源码分析] 01 - Session SignalR sql for xml path用法 MemCahe C# 操作Excel图形——绘制、读取、隐藏、删除图形 IOC,DIP,DI,IoC容器
1. 血案由来 近期我在为Lazada卖家中心做一个自助注册的项目,其中的shop name校验规则较为复杂,要求:1. 英文字母大小写2. 数字3. 越南文4. 一些特殊字符,如“&”,“- ...
- 转载-FileZilla Server源码分析(1)
FileZilla Server源码分析(1) 分类: VC 2012-03-27 17:32 2363人阅读 评论(0) 收藏 举报 serversocketftp服务器usersockets工作 ...
- 鸿蒙内核源码分析(文件系统篇) | 用图书管理说文件系统 | 百篇博客分析OpenHarmony源码 | v63.01
百篇博客系列篇.本篇为: v63.xx 鸿蒙内核源码分析(文件系统篇) | 用图书管理说文件系统 | 51.c.h.o 文件系统相关篇为: v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么说一 ...
随机推荐
- java读取properties文件,并在配置文件中设置默认浏览器驱动
java中的properties文件是一种配置文件,主要用于表达配置信息,文件类型为*.properties,格式为文本文件,文件的内容是格式是"键=值"的格式,在properti ...
- Python从2.7.5升级到3.6.5
Python从2.7.5升级到3.6.5学习了:https://blog.csdn.net/liang19890820/article/details/51079633 wget https://ww ...
- Windows远程CentOS桌面
Windows远程CentOS桌面 1.VNC 服务器配置 1) 安装vncserver yum install -y vnc-server 2) 修改配置 vi /etc/sysconfig/vnc ...
- python——Container之字典(dict)详解
字典(dictionary)是除列表以外python之中最灵活的内置数据结构类型.列表是有序的对象结合,字典是无序的对象集合.两者之间的区别在于:字典当中的元素是通过键来存取的,而不是通过偏移存取. ...
- 安卓使用Socket发送中文,C语言服务端接收乱码问题解决方式
今天用安卓通过Socket发送数据到电脑上使用C语言写的服务端,发送英文没有问题,可当把数据改变成中文时,服务端接收到的数据确是乱码. 突然想到.VS的预处理使用的是ANSI编码.而安卓网络数据都是U ...
- first core data
// // TableViewController.swift // TestCoreData // // import CoreData import UIKit class TableViewCo ...
- 为什么 Linux 的 htop 命令完胜 top 命令
在 Linux 系统中,top 命令用来显示系统中正在运行的进程的实时状态,它显示了一些非常有用的信息,比如 CPU 利用情况.内存消耗情况,以及每个进程情况等.但是,你知道吗?还有另外一个命令行工具 ...
- C#中的隐藏方法
在C#中要重写基类的方法,C#提倡在基类中使用virtual来标记要被重写的方法,在子类也就是派生类中用voerride关键字来修饰重写的方法. 如果要是项目中前期考虑不足,我没有在基类(ClassA ...
- MongoDB启动及用户名密码设置
1.服务启动 下载后的安装步骤,请参见mongoDB安装详细教程 启动服务NET START MongoDB 关闭服务NET STOP MongoDB 启动客户端mongo MongoDB shell ...
- 无需Root实现Android手机屏幕流畅投影到电脑进行演示(附软件下载)
近期要在公司的会议上演示App,须要在投影仪上显示出来给大家演示.因为投影仪不是智能投影仪,仅仅能将App先投影到自己的笔记本上.然后再将笔记本上的内容投影到投影仪上.该App是个游戏,实时交互性比較 ...