-
Android上9patch对话框制作与使用
2014-05-21 17:43:56看到qq等app上的那些popup很是让人渴望制作,但是呢,到底怎么才能得到那些对话框,以及怎么才能制作呢。我们没有美工,图片在网上有不太容易找到想要的(只有人家的实例图片),此时就想到一个讨巧的方法。下面就和...最近因为要开发安卓应用,于是乎,显而易见的要碰到一些用popupwindow做的控件,本身提供的那些外形和图片背景都不是太近人意的。看到qq等app上的那些popup很是让人渴望制作,但是呢,到底怎么才能得到那些对话框,以及怎么才能制作呢。我们没有美工,图片在网上有不太容易找到想要的(只有人家的实例图片),此时就想到一个讨巧的方法。下面就和大家具体说说怎么才能把这个9patch制作出来和使用好。
下图是QQ上的对话框:
1.我们需要一个word(2010版本以上的),随便新建一个新文件,找到插入形状,然后找到圆角对话框,在word上画出来,不需要太大,然后进行顶点微调,调制中间,然后最后一步是选择填充颜色就好了。这边我为了和qq对应,也选择了一个渐变黑色。将图用截图工具保存下来为PNG格式,qq截图就行了,要保存。
下图为我已经截图玩好的图:
2.这时候我们就需要用PS(Photoshop)了,只需要基础操作就可以了,我们把图加载到ps中去,用抠图工具把,对话框抠出来,我这边选用的是快速选图,然后移到新建的图布中(背景注意需要透明),这些都做好了,我们就需要把图上面那个回车标志去掉,具体怎么去,智者见智,只要行的通就好,我是用污点修复工具,当然在第一步也可在word隐藏回车,作者懒得没弄设置,所以在这边去掉。最后我们适当把图的像素调小一点,注重程序优化和空间节省,已经这个空间不需要高清背景,因为9patch可以扩展自己要求的内容。
下图是经过ps修复的图:
3.这时候我们一个对话框就出来了,接下来就是到了安卓部分了。我们打开9patch工具。这里我来详细教大家怎么使用这个对话框9patch设置。用图说明一步一步,注意看所设置的像素线。
(1).
(2).
(3).
如此设置好就可以了,这样一个9patch对话框就算完成了。
下面我给大家简单实例一下这个图片的使用:
好了,希望对各位程序爱好者有少许帮助,第一次写博客。有什么不足的还望大家谅解,转载,copy请注明出处,谢谢!
-
10分钟制作制作炫酷Windows Android IOS Dialogs对话框FMX界面,带透明度,可以将提示的内容问题和截屏任意...
2019-11-07 19:03:5410分钟制作制作炫酷Windows Android IOSDialogs对话框FMX界面 带透明度,可以将提示的内容问题和截屏任意分享至社交App 一、先看代码 unit CustomDialogsSimple1; interface uses System.SysUtils, System....10分钟制作制作炫酷Windows Android IOS Dialogs对话框FMX界面
带透明度,可以将提示的内容问题和截屏任意分享至社交App
一、先看代码
unit CustomDialogsSimple1;
interface
uses
System.SysUtils, System.Types, System.UITypes,
System.Classes, System.Variants, System.Actions,
System.Rtti,//:运行时刻库
FMX.Types, FMX.Graphics, FMX.Controls,
FMX.Forms, FMX.Dialogs, FMX.StdCtrls,
FMX.Edit, FMX.Effects, FMX.Controls.Presentation,
FMX.Objects, FMX.Layouts,
FMX.ScrollBox, FMX.Memo,
FMX.ActnList, FMX.StdActns, ,FMX.Platform //:平台服务
;type
TframeCustomDialogsSimple1 = class(TFrame)
LayoutDiologTranslucent: TLayout;
RectDiologTranslucent: TRectangle;
RectDiolog: TRectangle;
RectDiologTitle: TRectangle;
lblDiologTitle: TLabel;
RectDiologToolbar: TRectangle;
GlowEffect1: TGlowEffect;
lblRectDiologContentTips: TLabel;
imgDiologTitle: TImage;
LayoutRectDiologContent: TLayout;
MemoTips: TMemo;
LayoutRectDiologContentTips: TLayout;
imgRectDiologContentTips: TImage;
RectBtnOk: TRectangle;
imgBtnOk: TImage;
lblBtnOk: TLabel;
RectBtnCancel: TRectangle;
imgBtnCancel: TImage;
lblBtnCancel: TLabel;
btnCancel: TRectangle;
btnOk: TRectangle;
RectDiologContentTips: TRectangle;
RectBtnHelpme: TRectangle;
imgBtnHelpme: TImage;
lblBtnHelpme: TLabel;
btnHelpme: TRectangle;
imgShare: TImage;
LayoutShare: TLayout;
RectShare: TRectangle;
RectBtnShareText: TRectangle;
imgBtnShareText: TImage;
lblBtnShareText: TLabel;
BtnShareText: TRectangle;
RectBtnShareTo: TRectangle;
imgBtnShareTo: TImage;
lblBtnShareTo: TLabel;
BtnShareTo: TRectangle;
LayoutShareText: TLayout;
MemoShareText: TMemo;
LayoutShareTextTips: TLayout;
RectShareTextTips: TRectangle;
imgShareTextTips: TImage;
lblShareTextTips: TLabel;
RectShareText: TRectangle;
lblRectShare: TLabel;
RectLayoutShare: TRectangle;
SpBtnShareTo: TSpeedButton;
procedure btnOkClick(Sender: TObject);
procedure btnCancelClick(Sender: TObject);
procedure btnHelpmeClick(Sender: TObject);
procedure BtnShareTextClick(Sender: TObject);
procedure BtnShareToClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
//供调用者传入的回调参数:
//FTips:string;
frameCustomDialogsSimple1:TframeCustomDialogsSimple1;
FTControl:TControl;//:供调用者传入的截屏控件
end;
type
TAProc<T> = reference to procedure(const Arg :T);
TAFunc<T,TResult> = reference to function(const Arg :T):T;var FTips:string;//:传出变量
///<summary>本单元通用截屏方法-可做入全局库:</summary>
procedure FMakeScreenshot(
ATControl:TControl;AImage:TImage);implementation
uses myFuc_UnifiedPlatForm; // :我的通用库
{$R *.fmx}procedure TframeCustomDialogsSimple1.btnCancelClick(Sender: TObject);
var LAProc:TAProc<string>;
LAFunc:TAFunc<string,Boolean>;
begin
//MemoRectDiologContent.Lines.Add(' 你点了取消,你要做什么在你的继承代码中写匿名过程TAProc<T>或写匿名函数TAFunc<T>');
FTips:=sLineBreak+'你点了取消:'+sLineBreak
+' 你点了取消,你要做什么在你的继承代码中调用你写好的过程或函数';
//:FTips:回调测试用
self.SendToBack;
self.Visible:=false;
end;procedure TframeCustomDialogsSimple1.btnOkClick(Sender: TObject);
var LAProc:TAProc<string>;
LAFunc:TAFunc<string,Boolean>;
begin
//MemoRectDiologContent.Lines.Add(' 你点了确定,你要做什么在你的继承代码中写匿名过程TAProc<T>或写匿名函数TAFunc<T>');
FTips:=sLineBreak+'你点了确定:'+sLineBreak
+' 你点了确定,你要做什么在你的继承代码中调用你写好的过程或函数';
//:FTips:回调测试用
self.SendToBack;
self.Visible:=false;
end;procedure TframeCustomDialogsSimple1.btnHelpmeClick(Sender: TObject);
begin
FMakeScreenshot(self.FTControl,self.imgShare);//:调截屏方法
FTips:=sLineBreak+'你点了询问:'+sLineBreak
+' 你点了询问,你可以用此接口截屏分享给需要帮助您的人';
//:FTips:回调测试用
LayoutDiologTranslucent.Visible:=true;
RectDiolog.Visible:=false;LayoutShare.BringToFront;
LayoutShare.Visible:=true;
end;procedure TframeCustomDialogsSimple1.BtnShareTextClick(Sender: TObject);
begin
LayoutShareText.Visible:=not(LayoutShareText.Visible);
end;procedure TframeCustomDialogsSimple1.BtnShareToClick(Sender: TObject);
var LClipBoard:IFMXClipboardService; //:剪切板接口 //: FMX.Platform
LTValue:TValue;//:设置剪切板的泛型值 //: System.Rtti
begin
if MemoShareText.Lines.Text.Trim<>'' then
if TPlatformServices.Current.SupportsPlatformService(
IFMXClipboardService,IInterface(LClipBoard) ) then
begin
LTValue := TValue.From(MemoShareText.Lines.Text);
LClipBoard.SetClipboard(LTValue);
end;
//:剪切复制说两句的内容;界面显示处理:
LayoutShareText.Visible:=false;LayoutShare.SendToBack;
LayoutShare.Visible:=false;
imgShare.Visible:=false;LayoutDiologTranslucent.Visible:=true;
RectDiolog.Visible:=true;
end;procedure FMakeScreenshot(
ATControl:TControl;AImage:TImage);
//本单元通用截屏方法-可做入全局库:
var LTBitmap:TBitmap;
begin
LTBitmap:=ATControl.MakeScreenshot;
//:FTControl:回调控件截屏
AImage.Bitmap.SetSize(LTBitmap.Size);
AImage.Bitmap.CopyFromBitmap(LTBitmap);
AImage.Visible:=true;
end;
end.做出的效果:
二、怎么做的呢?步骤:
1、先用FMX Form临时窗体画UI界面(javaUI做的事情):
底层Layout给透明度:
这样布局:
注意layer层之间Bringfront和SendToBack属性,
画出这样的效果:
2、创建Frame(javaUI做的事情):
3、把你刚才在Form临时窗体中画的UI界面复制粘贴到上面的Frame(javaUI做的事情):
这样的效果:
4、Frame UI界面简单的点击事件控制界面显示规则(java前端做的事情):
// 几句话代码(见上面蓝色标注):
5、将上述Frame界面拖入加载到你的APP应用窗体(javaUI做的事情)
6、写你的调用代码及逻辑代码(java后端开发做的事情):
按钮事件代码:
分享代码:
一次一个分享动作:图片和文字只能二选一(除非 你做了多个动作代码,被某个Action连续调用,或者将文字画到图片中去):
截屏传参:
大功告成!是不是很简单呀!
三、下面是在上述基础之上,附加:1、WIndows下拉起QQ、TIM、微信;2、访问注册表
3.1、全平台拉起QQ、TIM、微信等进行分享截屏及消息对话框内容
unit CustomDialogsSimple1;
interface
uses
{$IFDEF MSWINDOWS}
Winapi.ShellAPI,Winapi.Windows,
RegistryWin32,
{$ENDIF MSWINDOWS}
System.SysUtils, System.Types, System.UITypes,
System.Classes, System.Variants, System.Actions,
System.IOUtils,System.Rtti,//:运行时刻库
FMX.Types, FMX.Graphics, FMX.Controls,
FMX.Forms, FMX.Dialogs, FMX.StdCtrls,
FMX.Edit, FMX.Effects, FMX.Controls.Presentation,
FMX.Objects, FMX.Layouts,
FMX.ScrollBox, FMX.Memo,
FMX.ActnList, FMX.StdActns,
FMX.Ani
,FMX.ImgList
,FMX.Platform //:平台服务
,myFuc_UnifiedPlatForm
;type
TframeCustomDialogsSimple1 = class(TFrame)
LayoutDiologTranslucent: TLayout;
RectDiologTranslucent: TRectangle;
RectDiolog: TRectangle;
RectDiologTitle: TRectangle;
lblDiologTitle: TLabel;
RectDiologToolbar: TRectangle;
GlowEffect1: TGlowEffect;
lblRectDiologContentTips: TLabel;
imgDiologTitle: TImage;
LayoutRectDiologContent: TLayout;
MemoTips: TMemo;
LayoutRectDiologContentTips: TLayout;
imgRectDiologContentTips: TImage;
RectBtnOk: TRectangle;
imgBtnOk: TImage;
lblBtnOk: TLabel;
RectBtnCancel: TRectangle;
imgBtnCancel: TImage;
lblBtnCancel: TLabel;
btnCancel: TRectangle;
btnOk: TRectangle;
RectDiologContentTips: TRectangle;
RectBtnHelpme: TRectangle;
imgBtnHelpme: TImage;
lblBtnHelpme: TLabel;
btnHelpme: TRectangle;
imgShare: TImage;
LayoutShare: TLayout;
RectShare: TRectangle;
RectBtnShareText: TRectangle;
imgBtnShareText: TImage;
lblBtnShareText: TLabel;
BtnShareText: TRectangle;
RectBtnShareTo: TRectangle;
imgBtnShareTo: TImage;
lblBtnShareTo: TLabel;
BtnShareTo: TRectangle;
LayoutShareText: TLayout;
MemoShareText: TMemo;
LayoutShareTextTips: TLayout;
RectShareTextTips: TRectangle;
imgShareTextTips: TImage;
lblShareTextTips: TLabel;
RectShareText: TRectangle;
lblRectShare: TLabel;
RectLayoutShare: TRectangle;
SpBtnShareTo: TSpeedButton;
HorzScrollBox1: THorzScrollBox;
PopupShareWindows: TPopup;
Layout1: TLayout;
Layout2: TLayout;
Layout3: TLayout;
Layout4: TLayout;
Layout101: TLayout;
Layout104: TLayout;
Layout103: TLayout;
Layout102: TLayout;
Layout201: TLayout;
Layout204: TLayout;
Layout203: TLayout;
Layout202: TLayout;
Image101: TImage;
Label101: TLabel;
Image102: TImage;
Label102: TLabel;
btnQQ: TSpeedButton;
btnWechat: TSpeedButton;
ActionListShareWindows: TActionList;
ActPopUpShareWindows: TControlAction;
btnTIM: TSpeedButton;
Image103: TImage;
Label103: TLabel;
procedure btnOkClick(Sender: TObject);
procedure btnCancelClick(Sender: TObject);
procedure btnHelpmeClick(Sender: TObject);
procedure BtnShareTextClick(Sender: TObject);
procedure BtnShareToClick(Sender: TObject);
procedure ActPopUpShareWindowsExecute(Sender: TObject);
private
{ Private declarations }public
{ Public declarations }
//供调用者传入的回调参数:
//FTips:string;
frameCustomDialogsSimple1:TframeCustomDialogsSimple1;
FTControl:TControl; //:供调用者传入的截屏控件
FCallmeForm:TForm; //:供调用者传入的调用本frame的窗体
FQQisRunning:Boolean; //:QQ是否手动登录(QQ不像微信,App拉起会被腾讯安全警告,只能由浏览器打开)
FTIMisRunning:Boolean;
end;
type
TAProc<T> = reference to procedure(const Arg :T);
TAFunc<T,TResult> = reference to function(const Arg :T):T;var FTips:string;//:传出变量
FCurrShareName:string;///<summary>本单元通用截屏方法-可做入全局库:</summary>
procedure FMakeScreenshot(
ATControl:TControl;AImage:TImage);//function SetRegStr(const ARootKey,AKeyName,AName,AValue
//,AValueType:string):string;external 'ProDllWin32.dll' name 'SetRegStr';
//:Dll方式需解决回调问题:Dll执行完主程序就自动关闭啦
implementation{$R *.fmx}
procedure TframeCustomDialogsSimple1.btnCancelClick(Sender: TObject);
var LAProc:TAProc<string>;
LAFunc:TAFunc<string,Boolean>;
begin
{$IFDEF MSWINDOWS}
KillApp('ProAPIRegistryWin32.exe');
{$ENDIF MSWINDOWS}
//MemoRectDiologContent.Lines.Add(' 你点了取消,你要做什么在你的继承代码中写匿名过程TAProc<T>或写匿名函数TAFunc<T>');
FTips:=sLineBreak+'你点了取消:'+sLineBreak
+' 你点了取消,你要做什么在你的继承代码中调用你写好的过程或函数';
//:FTips:回调测试用
self.SendToBack;
self.Visible:=false;
end;procedure TframeCustomDialogsSimple1.btnOkClick(Sender: TObject);
var LAProc:TAProc<string>;
LAFunc:TAFunc<string,Boolean>;
begin
{$IFDEF MSWINDOWS}
KillApp('ProAPIRegistryWin32.exe');
{$ENDIF MSWINDOWS}
//MemoRectDiologContent.Lines.Add(' 你点了确定,你要做什么在你的继承代码中写匿名过程TAProc<T>或写匿名函数TAFunc<T>');
FTips:=sLineBreak+'你点了确定:'+sLineBreak
+' 你点了确定,你要做什么在你的继承代码中调用你写好的过程或函数';
//:FTips:回调测试用
self.SendToBack;
self.Visible:=false;
end;procedure TframeCustomDialogsSimple1.btnHelpmeClick(Sender: TObject);
var AAppKeyValue:string;
begin
{$IFDEF MSWINDOWS}
AAppKeyValue:='ProAPIRegistryWin32.exe';
KillApp(AAppKeyValue);
{$ENDIF MSWINDOWS}
FMakeScreenshot(self.FTControl,self.imgShare);//:调截屏方法
FTips:=sLineBreak+'你点了询问:'+sLineBreak
+' 你点了询问,你可以用此接口截屏分享给需要帮助您的人';
//:FTips:回调测试用
LayoutDiologTranslucent.Visible:=true;
RectDiolog.Visible:=false;LayoutShare.BringToFront;
LayoutShare.Visible:=true;
end;procedure TframeCustomDialogsSimple1.BtnShareTextClick(Sender: TObject);
begin
LayoutShareText.Visible:=not(LayoutShareText.Visible);
end;procedure TframeCustomDialogsSimple1.BtnShareToClick(Sender: TObject);
var LClipBoard:IFMXClipboardService; //:剪切板接口 //:FMX.Platform
LTValue:TValue;//:设置剪切板的泛型值 //:System.Rtti
begin
{$IFDEF MSWINDOWS}
PopupShareWindows.Visible:=true;
{$ELSE}
LayoutShareText.Visible:=false;LayoutShare.SendToBack;
LayoutShare.Visible:=false;
imgShare.Visible:=false;LayoutDiologTranslucent.Visible:=true;
RectDiolog.Visible:=true;
{$ENDIF}
//:界面显示处理;剪切复制说两句的内容:if MemoShareText.Lines.Text.Trim<>'' then
if TPlatformServices.Current.SupportsPlatformService(
IFMXClipboardService,IInterface(LClipBoard) ) then
begin
LTValue := TValue.From(MemoShareText.Lines.Text);
LClipBoard.SetClipboard(LTValue);
end;end;
procedure TframeCustomDialogsSimple1.ActPopUpShareWindowsExecute(
Sender: TObject);
{$IFDEF MSWINDOWS}
var AAppKeyValue:string;
LNativeUInt:NativeUInt;
{$ENDIF MSWINDOWS}
begin
{$IFDEF MSWINDOWS}
//MemoTips.Lines.Add(Sender.ToString);
try
if (Sender as TControlAction).Target.Name='btnQQ' then
begin
try
if FQQisRunning=false then
begin
//MemoTips.Lines.Add('QQ未运行');
AAppKeyValue:='QQ.exe';
try
try
FQQisRunning:=AppRunning(AAppKeyValue);
except
//
end;
finally
if FQQisRunning=false then
begin
ShowAMessage('请先手动登录您的QQ',procedure begin end);
Abort;
end;
end;
end;
finally
if FQQisRunning=True then
begin
//MemoTips.Lines.Add('QQ已运行');
AAppKeyValue:='';
FCurrShareName:='tencent://Message/?Uin=461655651&websiteName=q-zone.qq.com&Menu=yes';
//:测试纸适用Win32://ShellExecute(0, 'open','IExplore.EXE', PWideChar(WideString(FCurrShareName)), nil, SW_SHOWNORMAL);
try
ExeURL(AAppKeyValue,PWideChar(WideString(FCurrShareName)),SW_SHOWNORMAL);
//:QQ是否手动登录(QQ不像微信,
//:App拉起会被腾讯安全警告,只能由浏览器打开)
finally
FCallmeForm.Activate; self.SetFocus;
end;end;
end;
end;
if (Sender as TControlAction).Target.Name='btnTIM' then
begin
try
if FTIMisRunning=false then
begin
//MemoTips.Lines.Add('TIM未运行');
AAppKeyValue:='TIM.exe';
try
try
FTIMisRunning:=AppRunning(AAppKeyValue);
except
//
end;
finally
if FTIMisRunning=false then
begin
ShowAMessage('请先手动登录您的qq办公版TIM',procedure begin end);
Abort;
end;
end;
end;
finally
if FTIMisRunning=True then
begin
//MemoTips.Lines.Add('TIM已运行');
AAppKeyValue:='';
FCurrShareName:='tencent://Message/?Uin=461655651&websiteName=q-zone.qq.com&Menu=yes';
//:测试纸适用Win32://ShellExecute(0, 'open','IExplore.EXE', PWideChar(WideString(FCurrShareName)), nil, SW_SHOWNORMAL);
try
ExeURL(AAppKeyValue,PWideChar(WideString(FCurrShareName)),SW_SHOWNORMAL);
//:QQ是否手动登录(QQ不像微信,
//:App拉起会被腾讯安全警告,只能由浏览器打开)
finally
FCallmeForm.Activate; self.SetFocus;
end;end;
end;
end;if (Sender as TControlAction).Target.Name='btnWechat' then
begin
FCurrShareName:='WeChat';AAppKeyValue:='ProAPIRegistryWin32.exe';
//:AAppKeyValue:若参数=''则不调用:
LNativeUInt:=ExeApp(AAppKeyValue,FCurrShareName,SW_SHOW);
//LNativeUInt:=ExeApp(AAppKeyValue,'WeChat',SW_SHOW);
//:(SW_HIDE,SW_SHOW,...)
//if LNativeUInt.ToString.Trim<>'' then
//MemoTips.Lines.Add(LNativeUInt.ToString.Trim)
//;
//:LNativeUInt.ToString.Trim<>'':代表调用成功
//ToString:System.SysUtils.TNativeUIntHelper
end;
finally
LayoutShareText.Visible:=false;LayoutShare.SendToBack;
LayoutShare.Visible:=false;
imgShare.Visible:=false;LayoutDiologTranslucent.Visible:=true;
RectDiolog.Visible:=true;
end;PopupShareWindows.Visible:=false;
{$ENDIF MSWINDOWS}
end;procedure FMakeScreenshot(
ATControl:TControl;AImage:TImage);
//本单元通用截屏方法-可做入全局库:
var LTBitmap:TBitmap;
begin
LTBitmap:=ATControl.MakeScreenshot;
//:FTControl:回调控件截屏
AImage.Bitmap.SetSize(LTBitmap.Size);
AImage.Bitmap.CopyFromBitmap(LTBitmap);
AImage.Visible:=true;
end;//initialization
//finalization
end.
3.2、访问Win32注册表
unit RegistryWin32;
{Win32 API Interface Unit}interface
uses
Winapi.Windows,Winapi.ShellAPI,
Winapi.TlHelp32, Winapi.PsAPI,
System.Win.Registry,//:Windows注册表类
System.Classes,
System.SysUtils
,Vcl.Controls,Vcl.Forms
;///<summary>设置注册表制定位置(ARootKey下AKeyName)键AName值AValue:</summary>
///<param name="ARootKey">=注册表主键</param>
///<param name="ARootKey">=主键下的某个目录键</param>
///<param name="AName">=目录键下的数值名称</param>
///<param name="AValue">=目录键下的数值数据</param>
///<param name="AValueType">=数值数据的类型('整型','字符串型','布尔型','浮点型','日期时间型','日期型','时间型')</param>
procedure SetRegStr(const ARootKey,AKeyName,AName,AValue
,AValueType:string);
///<summary>读取注册表制定位置(ARootKey下AAppNameKey)键值:</summary>
procedure readRegistry(
const ARootKey:NativeUInt;
const AAppNameKey:string;
const AAppKeyName:string;
var AAppKeyValue:String );
///<summary>当前Windows是64位还是32位操作系统:</summary>
///<summary>需要注意是GetNativeSystemInfo 函数从Windows XP 开始才有,</summary>
///<summary>而 IsWow64Process 函数从 Windows XP with SP2以及Windows Server 2003 with SP1开始才有</summary>
///<summary>所以使用该函数的时候最好用GetProcAddress:</summary>
function IsWin64: string;///<summary>Windows获取操作系统优先级:</summary>
procedure GetPrivilege;
///<summary>Windows提示关机、强制关机、重启:</summary>
procedure RebootSystem(const RebootStyle:string='重启');
//调用ZwShutdownSystem()函数后,会通知硬件驱动保存内核数据,注册表和文件的缓存将会刷新到磁盘上,
//然后将立即重启或关机,未保存的应用程序数据将丢失。
//由于ZwShutdownSystem()通知硬件驱动后是瞬间关机的。为了系统与硬件的安全,
//应使用ExitWindowsEx()进行正常关机。
function RtlAdjustPrivilege(Privilege: ULONG; Enable: BOOLEAN;
CurrentThread: BOOLEAN; Enabled: PBOOLEAN): DWORD; stdcall; external 'ntdll.dll';
function ZwShutdownSystem(arg: DWORD): BOOLEAN; stdcall; external 'ntdll.dll';///<summary>Win32执行一个外部应用:</summary>
///<param name="AppName">=外部应用全路径名称</param>
///<param name="AppParamStr">=向App传入的参数:ParamStr(0)不能调用(系统默认APP根目录):ParamStr(1)...ParamStr(N),可由分隔符代码调用</param>
///<param name="AShowWindowStyle">=(SW_HIDE,SW_SHOW,...)App显示方式</param>
function ExeApp(var AppName:string;const AppParamStr:string;const AShowWindowStyle:NativeUInt):NativeUInt;function ExeURL(
var AppName:string;
const AppParamStr:string;
const AShowWindowStyle:NativeUInt):NativeUInt;
///<summary>Win32强行杀死一个外部应用:</summary>
///<param name="AppName">=外部应用全路径名称</param>
procedure KillApp(const AppName:string);
procedure KillProcess(ExeName: string);function AppRunning(var AppName:string):Boolean;
implementationprocedure SetRegStr(const ARootKey,AKeyName,AName,AValue
,AValueType:string);
var Reg: TRegistry; AOldValue:string;
//比如AName:=EnableLUA
//比如AKeyName:='Software\Microsoft\Windows\CurrentVersion\Policies\System'
//AValueType:=('整型','字符串型','布尔型','浮点型','日期时间型','日期型','时间型')
begin
Reg := TRegistry.Create;
try
if ARootKey='HKEY_LOCAL_MACHINE' then
Reg.RootKey := HKEY_LOCAL_MACHINE;
Reg.OpenKey(AKeyName ,true);
if not Reg.ValueExists(AName) then
begin
if AValueType='整型' then Reg.WriteInteger(AName,StrToInt(AValue));
if AValueType='字符串型' then Reg.WriteString(AName,AValue);
if AValueType='浮点型' then Reg.WriteFloat(AName,StrToFloat(AValue));
if AValueType='日期时间型' then Reg.WriteDateTime(AName,StrToDateTime(AValue));
if AValueType='日期型' then Reg.WriteDate(AName,StrToDate(AValue));
if AValueType='时间型' then Reg.WriteTime(AName,StrToTime(AValue));
end else
begin
if AValueType='整型' then
begin
AOldValue:=IntToStr(Reg.ReadInteger(AName));
Reg.DeleteValue(AOldValue);
Reg.WriteInteger(AName,StrToInt(AValue));
end;
if AValueType='字符串型' then
begin
AOldValue:=(Reg.ReadString(AName));
Reg.DeleteValue(AOldValue);
Reg.WriteString(AName,(AValue));
end;
if AValueType='浮点型' then
begin
AOldValue:=FloatToStr(Reg.ReadFloat(AName));
Reg.DeleteValue(AOldValue);
Reg.WriteFloat(AName,StrToFloat(AValue));
end;
if AValueType='日期时间型' then
begin
AOldValue:=DateTimeToStr(Reg.ReadDateTime(AName));
Reg.DeleteValue(AOldValue);
Reg.WriteDateTime(AName,StrToDateTime(AValue));
end;
if AValueType='时间型' then
begin
AOldValue:=TimeToStr(Reg.ReadTime(AName));
Reg.DeleteValue(AOldValue);
Reg.WriteTime(AName,StrToTime(AValue));
end;
end;
finally
Reg.CloseKey;
Reg.Free;
end;
end;procedure readRegistry(
const ARootKey:NativeUInt;
const AAppNameKey:string;
const AAppKeyName:string;
var AAppKeyValue:String );
//读取注册表制定位置(ARootKey下AAppNameKey)键值
{$IFDEF MSWINDOWS}
var
ifIsWin64: String;
TheReg: TRegistry;//注意:Win32 API:Windows 64-位下编译不生效的
KeyName: String;
ValueStr: String;
{$ENDIF MSWINDOWS}
begin
{$IFDEF MSWINDOWS}
if AAppNameKey.Trim='' then exit;
tryTheReg:=TRegistry.Create;
TheReg.RootKey:=ARootKey;
//:HKEY_LOCAL_MACHINE;//Winapi.Windows
//:等价于:NativeUInt($80000002) //System
//:HKEY_CURRENT_USER = HKEY(NativeUInt($80000001));
try
ifIsWin64:=IsWin64;
finally
if AAppNameKey.Trim='QQ2009' then
begin
KeyName := 'Software\Tencent\'
+AAppNameKey;
end else
if AAppNameKey.Trim='TIM' then
begin
KeyName := 'Software\Tencent\'
+AAppNameKey;
end else
begin
if pos('64-bit',ifIsWin64.trim)>=0 then //='64位操作系统'
KeyName := 'Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\'
+AAppNameKey; //+'WeChat';
if pos('32-bit',ifIsWin64.trim)>=0 then//='32位操作系统'
KeyName := 'Software\Microsoft\Windows\CurrentVersion\Uninstall\'
+AAppNameKey; //+'WeChat';
end;
end;
//:Windows任意安装和卸载的位置
//:如需知道某App的具体安装和卸载程序全路径,
//:就需要知道其下级的注册表节点名称,如+'WeChat'
if TheReg.OpenKey(KeyName,true) then
begin //回调安装全路径执行文件名AAppKeyValue:
AAppKeyValue:=(TheReg.ReadString(AAppKeyName));
//AAppKeyValue:=(TheReg.ReadString('DisplayIcon'));
//:DisplayIcon一般软件开发会设置其键值为安装全路径执行文件名,
//:但也不完全:取决于开发商end;
finally
TheReg.CloseKey;
TheReg.Free;
end;
{$ENDIF MSWINDOWS}
end;//需要注意是GetNativeSystemInfo 函数从Windows XP 开始才有,
//而 IsWow64Process 函数从 Windows XP with SP2 以及 Windows Server 2003 with SP1 开始才有。
//所以使用该函数的时候最好用GetProcAddress
function IsWin64: string;
var LOSVer:System.SysUtils.TOSVersion;
{$IFDEF MSWINDOWS}
{
var
Kernel32Handle: THandle;
IsWow64Process: function(Handle: THandle; var Res: BOOL): BOOL; stdcall;
GetNativeSystemInfo: procedure(var lpSystemInfo: TSystemInfo); stdcall;
isWoW64: Bool;
SystemInfo: TSystemInfo;
const
PROCESSOR_ARCHITECTURE_AMD64 = 9;
PROCESSOR_ARCHITECTURE_IA64 = 6;
}
{$ENDIF MSWINDOWS}
begin
Result :=LOSVer.ToString;
{
Result :=
'Name:'+LOSVer.Name
+',ToString:'+LOSVer.ToString
+',Build:'+IntToStr(LOSVer.Build)
+',Major:'+IntToStr(LOSVer.Major)
+',Minor:'+IntToStr(LOSVer.Minor)
+',ServicePackMajor:'+IntToStr(LOSVer.ServicePackMajor)
+',ServicePackMinor:'+IntToStr(LOSVer.ServicePackMinor)
; }
(*
//{$IFDEF MSWINDOWS}
{
Kernel32Handle := GetModuleHandle('KERNEL32.DLL');
if Kernel32Handle = 0 then Kernel32Handle := LoadLibrary('KERNEL32.DLL');
if Kernel32Handle <> 0 then
}
if LOSVer.Platform in [pfWindows,pfWinRT] then
beginif LOSVer.Architecture in [arIntelX64,arARM64] //(LOSVer.Architecture=TOSVersion.TArchitecture.arIntelX64)
//or (LOSVer.Architecture=TOSVersion.TArchitecture.arARM64)
then
begin
{
IsWOW64Process := GetProcAddress(Kernel32Handle,'IsWow64Process');
GetNativeSystemInfo := GetProcAddress(Kernel32Handle,'GetNativeSystemInfo');
if Assigned(IsWow64Process) then
begin
IsWow64Process(GetCurrentProcess,isWoW64);
if (isWoW64 and Assigned(GetNativeSystemInfo)
)=true then
begin
GetNativeSystemInfo(SystemInfo);
if ( (SystemInfo.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64)
or (SystemInfo.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_IA64)
)
then
Result := '64位操作系统64位处理器' else Result := '64位操作系统32位处理器';
end;
end; }
Result := '64位操作系统'+LOSVer.ToString;
end else Result := '32位操作系统'+LOSVer.ToString;
end;
*)
//{$ENDIF MSWINDOWS}end;
procedure RebootSystem(const RebootStyle:string='重启');
//:RebootStyle:Windows提示关机、强制关机、重启:
begin
{$IFDEF MSWINDOWS}
GetPrivilege;
if RebootStyle='提示关机' then
initiateSystemShutDown(nil,nil,0,true,false);
if RebootStyle='强制关机' then
ExitWindowsEx(EWX_SHUTDOWN+EWX_FORCE+EWX_POWEROFF+EWX_FORCEIFHUNG, 0);
if RebootStyle='重启' then
ExitWindowsEx(EWX_REBOOT OR EWX_FORCE or EWX_POWEROFF or EWX_FORCEIFHUNG, 0);
{$ENDIF MSWINDOWS}
end;procedure GetPrivilege;
{$IFDEF MSWINDOWS}
var
NewState: TTokenPrivileges;
lpLuid: Int64;
ReturnLength: DWord;
ToKenHandle: THandle;
{$ENDIF MSWINDOWS}
begin
{$IFDEF MSWINDOWS}
OpenProcessToken(GetCurrentProcess,
TOKEN_ADJUST_PRIVILEGES
OR TOKEN_ALL_ACCESS
OR STANDARD_RIGHTS_REQUIRED
OR TOKEN_QUERY,ToKenHandle);
LookupPrivilegeValue(nil,'SeShutdownPrivilege',lpLuid);
NewState.PrivilegeCount:=1;
NewState.Privileges[0].Luid:=lpLuid;
NewState.Privileges[0].Attributes:=SE_PRIVILEGE_ENABLED;
ReturnLength:=0;
AdjustTokenPrivileges(ToKenHandle,False,NewState,0,nil,ReturnLength);
{$ENDIF MSWINDOWS}
end;function ExeApp(var AppName:string;
const AppParamStr:string;
const AShowWindowStyle:NativeUInt):NativeUInt;
var LHandle:HWND;
StartInfo:STARTUPINFO;
begin
//AShowWindowStyle:=(SW_HIDE,SW_SHOW,...)
//AppParamStr:向App传入的参数:ParamStr(0)不能调用,系统默认APP根目录
//:ParamStr(1)...ParamStr(N),可由分隔符代码调用
{$IFDEF MSWINDOWS}
if AppName.Trim='' then exit;
LHandle:=0;
Result:=
ShellExecute(LHandle,'open'
,PWideChar(WideString(AppName))
,PWideChar(WideString(AppParamStr))//:向App传入的参数
,nil //:App默认目录
,AShowWindowStyle //:App显示方式
);{$ENDIF MSWINDOWS}
end;function ExeURL(
var AppName:string;
const AppParamStr:string;
const AShowWindowStyle:NativeUInt):NativeUInt;
var LHandle:HWND;
LNativeUInt:NativeUInt;
//StartInfo:STARTUPINFO;
begin
//AShowWindowStyle:=(SW_HIDE,SW_SHOW,...)
//AppParamStr:向App传入的参数:ParamStr(0)不能调用,系统默认APP根目录
//:ParamStr(1)...ParamStr(N),可由分隔符代码调用
{$IFDEF MSWINDOWS}
if AppParamStr.Trim='' then exit;
try
LHandle:=0;
LNativeUInt:=
ShellExecute(
0
,'open' //:nil:不能否则虽不影响执行但会报错
,'IExplore.EXE'
,PWideChar(WideString(AppParamStr))//:URL指令参数
,nil //:App默认目录
,SW_SHOW //:App显示方式
);
except
//
end;
Result:=LNativeUInt;
{$ENDIF MSWINDOWS}
end;procedure KillApp(const AppName:string);
//Win32强行杀死一个外部应用:
begin
if AppName.Trim='' then exit;
WinExec( PAnsiChar(AnsiString('cmd.exe /c taskkill /f /t /im '+AppName))
,sw_hide); //AppName:比如:ProAPIRegistryWin32.exe
end;procedure KillProcess(ExeName: string);
const
PROCESS_TERMINATE = $0001; //进程的PROCESS_TERMINATE访问权限
var
ContinueLoop: Boolean;
FSnapshotHandle: THandle;
FProcessEntry32: TProcessEntry32;
begin
//获取系统所有进程快照
FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
//调用Process32First前用Sizeof(FProcessEntry32)填充FProcessEntry32.dwSize
FProcessEntry32.dwSize := Sizeof(FProcessEntry32);
//获取快照中第一个进程信息并保存到FProcessEntry32结构体中
ContinueLoop := Process32First(FSnapshotHandle,FProcessEntry32);
while integer(ContinueLoop) <> 0 do //循环枚举快照中所有进程信息
begin
//找到要中止的进程名
if ((UpperCase(ExtractFileName(FProcessEntry32.szExeFile)) = UpperCase(ExeName))
or (UpperCase(FProcessEntry32.szExeFile) = UpperCase(ExeName))) then
TerminateProcess(OpenProcess(PROCESS_TERMINATE, BOOL(0),FProcessEntry32.th32ProcessID), 0); //中止进程
ContinueLoop := Process32Next(FSnapshotHandle,FProcessEntry32); //查找下一个符合条件进程
end;
end;function AppRunning(var AppName:string):Boolean;
var
ContinueLoop: Boolean;
FSnapshotHandle: THandle;
FProcessEntry32: TProcessEntry32;
LFindmeCount:Integer;
begin
LFindmeCount:=0;
//获取系统所有进程快照
FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
//调用Process32First前用Sizeof(FProcessEntry32)填充FProcessEntry32.dwSize
FProcessEntry32.dwSize := Sizeof(FProcessEntry32);
//获取快照中第一个进程信息并保存到FProcessEntry32结构体中
ContinueLoop := Process32First(FSnapshotHandle,FProcessEntry32);
while integer(ContinueLoop) <> 0 do //循环枚举快照中所有进程信息
begin
//找到要中止的进程名
if ((UpperCase(ExtractFileName(FProcessEntry32.szExeFile)) = UpperCase(AppName))
or (UpperCase(FProcessEntry32.szExeFile) = UpperCase(AppName))) then
LFindmeCount:=LFindmeCount+1;
ContinueLoop := Process32Next(FSnapshotHandle,FProcessEntry32); //查找下一个符合条件进程
end;
if LFindmeCount=0 then
begin
Result:=False;
end else
begin //App已在运行:
Result:=true;
end;
end;end.
3.3、Windows 64-bit、Windows 32-bit编译平台兼容调用第三方App
{Windows 64-bit、Windows 32-bit编译平台兼容调用第三方App:}
{:让操作系统:更改UAC用户账户控制设置}
unit APIRegistryWin32;
interfaceuses
Winapi.Windows,
Winapi.ShellAPI, Winapi.Messages,
System.SysUtils, System.Variants,
System.Classes, System.IOUtils,
Vcl.Graphics,Vcl.Controls,
Vcl.Forms, Vcl.Dialogs,RegistryWin32, Vcl.StdCtrls
,myFuc_UnifiedPlatForm // :我的通用库
;type
TfrmRegistryWin32 = class(TForm)
edtParamStr: TEdit;
edtResultStr: TEdit;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;var
frmRegistryWin32: TfrmRegistryWin32;implementation
{$R *.dfm}
procedure TfrmRegistryWin32.FormCreate(Sender: TObject);
var LAppKeyValue:string;
LStrList:TStringList;
LNativeUInt:NativeUInt;
begin
edtParamStr.Text:=System.ParamStr(1);
//:本工程被调用程序传入的参数
LStrList:=TStringList.Create;
try
try
SetRegStr('HKEY_LOCAL_MACHINE','Software\Microsoft\Windows\CurrentVersion\Policies\System'
,'EnableLUA','0','整型'); //\Wow6432Node
//:让操作系统:更改UAC用户账户控制设置
if trim(edtParamStr.Text)='WeChat' then
readRegistry( HKEY_LOCAL_MACHINE
,trim(edtParamStr.Text),'DisplayIcon',LAppKeyValue);if trim(edtParamStr.Text)='QQ2009' then
begin //:未用:QQ用浏览器打开的方式:
try
readRegistry( HKEY_LOCAL_MACHINE
,trim(edtParamStr.Text),'Install',LAppKeyValue);
finally
LAppKeyValue:=LAppKeyValue +'\bin\QQ.exe';
end;
end;if trim(edtParamStr.Text)='TIM' then
begin //:未用:TIM用浏览器打开的方式:
try
readRegistry( HKEY_LOCAL_MACHINE
,trim(edtParamStr.Text),'Install',LAppKeyValue);
finally
LAppKeyValue:=LAppKeyValue +'\bin\TIM.exe';
end;
end;
//:edtParamStr.Text根据传入参数读取注册表,打开第3方应用
//edtParamStr.Text:'WeChat'
//:HKEY_LOCAL_MACHINE;//Winapi.Windows
//:等价于:NativeUInt($80000002) //System
//:HKEY_CURRENT_USER = HKEY(NativeUInt($80000001));
finally
try
LNativeUInt:=ExeApp(LAppKeyValue,'',SW_HIDE);
finally
if LNativeUInt.ToString.Trim<>'' then //:调用完毕
begin
edtResultStr.Text:=LAppKeyValue+'调用完毕'+ LNativeUInt.ToString;
LAppKeyValue:=trim(edtResultStr.Text);
end;
end;
//WinExec(PAnsiChar(AnsiString(LAppKeyValue)), SW_SHOW);
// ShellExecute(1,'open',PWideChar(WideString(LAppKeyValue)),nil,nil,SW_SHOW);
//WinExec(PAnsiChar(AnsiString(LAppKeyValue)), SW_SHOW);
//:所有的原生字符串类型String转PAnsiChar都需要经过AnsiString过渡
end;finally
FreeAndNil(LStrList);
end;
end;end.
-
资源MFC DLL的制作[在DLL中封装MFC对话框]
2018-01-27 17:08:241. 首先在MFC DLL 的文件中函数中添加 ...BOOL CPIMSHQERON001100App::InitInstance() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); COleObjectFactory::RegisterAll(); CWinApp::InitInstance();1. 首先在MFC DLL 的文件中函数中添加 PIMSHQERON001100.DLL
BOOL CPIMSHQERON001100App::InitInstance()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
COleObjectFactory::RegisterAll();
CWinApp::InitInstance();
AfxEnableControlContainer();
CoInitialize(NULL);
//if(!AfxOleInit())
//{
// return FALSE;
//}
return TRUE;
}2. 在调用窗体时
//资源切换,无此宏对话框创建不成功
AFX_MANAGE_STATE(AfxGetStaticModuleState());//需要这句。
EditReleaseOnLineFile *editRelFile = new EditReleaseOnLineFile();//(pSession, pResultElementPtr);
editRelFile->DoModal();3. 对话框内部有时没有OnInitDialog() 函数,请手动添加
// 生成的消息映射函数
virtual BOOL OnInitDialog();BOOL EditReleaseOnLineFile::OnInitDialog()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
AfxEnableControlContainer();
CDialog::OnInitDialog();
CoInitialize(NULL);
//if(!AfxOleInit())
//{
// return FALSE;
//}
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}附其他方式:
二.建立一个可以包含MFC对话框的DLL
树形控件仅能以子窗口的形式出现,它要依附对话框这样的父窗口。 可以在UG二次开发的DLL项目中直接添加对话框资源和对话框类来实现,手段虽不怎么高明,但能实现所需的功能。但我觉得最好将与UG没有多大关系的功能分离出来,作为一个模块单独实现,这也是软件工程所鼓励的方式。
本文的方法是首先做一个DLL,让包含一个MFC对话框,这个DLL可以在UG二次开发的项目中被加载。被包含在DLL中的对话框通常称为资源对话框。
下面为建立可以包含对话框资源的DLL的过程。
1.建一个MFC Regular DLL项目 .
VS.net(没找到英文版,菜单只能给出中文名称)的建立一个DLL的过程如下:
[1]菜单 文件→新建→项目,在弹出的项目对话框的左栏,选择Visual C++项目,在右栏选择MFC DLL。然后在下面的文本框中输入项目的名字,确定,进入MFC DLL向导。
[2]MFC DLL向导,在"应用程序设置"中,选择'使用共享MFC DLL的规则DLL",完成向导设置后,生成一个空的MFC DLL项目。
[3]菜单:项目→添加资源,在添加资源对话框中,选择"Dialog",然后点击按钮"新建"。VS.net会自动切换到资源视图界面,删去默认的"OK"和"CANCEL" 按钮。
[4]将默认的对话框ID修改成你能记得住的名字。
[5]添加对话框类CTreeDlg。
//--------------------
以上过程都是IDE在工作,下面就要动脑,动手了。
//-------------------
[6] 建立输出函数ShowTreeDlg
DLL是无法自动进入内存开始运行的,要被其它可执行文件的加载才可以。对话框是在DLL中创建的,我们期望在UG二次开发的项目中,在某个UIStyler控件的触发下弹出这个DLL中创建的对话框。而常规的MFC DLL是无法导出MFC对象给其它应用程序使用的,只能通过输出函数来做。
向工程中添加两个文件ExportFunc.h和ExportFunc.CPP,我打算将输出函数的声明和定义统一放在这两个文件中,便于管理。代码实现如下:
//--------------------------------------------
//ExportFunc.h,
//声明欲输出的函数
//-------------------------------------------
#ifndef _EXPORTFunc_H
#define _EXPORTFunc_H
#ifdef _cplusplus
extern "C"{
#endif
void ShowTreeDlg(HWND hMainWnd);
#ifdef _cplusplus
}
#endif
#endif
//--------------------------------------------
//ExportFunc.cpp文件
//定义输出函数
//-------------------------------------------
//
//功能:DLL的输出函数,当其他应用程序加载该DLL后,调用这个函数,可以显示该DLL内建的对话框
//输入参数1:HWND hMainWnd,对话框父窗口的句柄
//
void ShowTreeDlg(HWND hMainWnd)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CTreeDlg *pTreeDlg=new CTreeDlg;
CWnd * pMainWnd=CWnd:: FromHandle(hMainWnd);
ASSERT(pMainWnd);
BOOL retValue=pTreeDlg->Create(IDD_TREE,pMainWnd);
if(!retValue)
{
AfxMessageBox("创建包含树列表控件的对话框失败了!");
}
pTreeDlg->ShowWindow(SW_SHOW);
}
下面是模块定义文件的内容,通常我们是使用_declspec(dllexport)直接修饰输出的函数,这样导出的接口很容易就被查看DLL文件的工具观察到,保密性不够好。为了向外界隐藏你的DLL对外接口的名称,只有def文件可以做。
; DlgWithTreeCtrl.def : 声明 DLL 的模块参数。
LIBRARY "DlgWithTreeCtrl"
EXPORTS
; 此处可以是显式导出
ShowTreeDlg @1 NONAME知识点1:MFC模块状态的切换
上贴,在ExportFunc.CPP中,定义输出函数ShowTreeDlg时,函数体开头一句是AFX_MANAGE_STATE(AfxGetStaticModuleState());
对MFC DLL不熟悉的兄弟在二次开发中使用MFC的库时,常常会丢了这句,以致出现一些莫名奇妙的错误。有的兄弟能记着添加它,但不见得就知道它的作用。不要求非要知道它的作用,但如果你会开车,又懂得修车,这样会更好。
[1]模块的定义:一段可执行的程序,其程序代码,数据,资源被加载到内存中了(这种加载可以是操作系统来做,也可以是已被加载到内存中的模块来做),这段程序进入内存后,系统会为之建立一个数据结构来管理,这个数据结构在WINDOWS中,就是PE文件头。一个活动在内存中的EXE文件是不是模块?一个活动在内存中的DLL文件是不是模块?它们都是。
[2]MFC模块:使用了MFC库的模块。
[3]MFC模块的状态:是一个数据结构,里面存了许多与模块相关的数据,这些数据具体是什么,我也不清楚,但我知道我的DLL中所包含的对话框是存于资源模板中的,而资源模板是存于这个MFC模块的状态数据结构中的。只关心这一点就可以了。
[4]一个MFC程序运行时,默认状态下,当它需要资源时,比如它需要一个对话框,那么它会从自身的模块状态中找到资源模板,然后从资源模板中找到相应的对话框,它是怎么找到自己所需要的对话框模板的呢?根据对话框ID,这是一个整型数。
然而,当一个MFC的应用程序在运行时,可能要加载多个MFC模块。譬如程序A.exe在运行时,加载了B.dll。在B.dll中提供了一个输出函数ShowDlg,函数体定义如下:
//-------------------------------------------------------------------------
//该函数显示一个非模态对话框,写法极简,仅作示例
//-------------------------------------------------------------------------
void ShowDlg(void)
{
CDlg *pDlg = new CDlg;
pDlg->Create(IDD_DLG,NULL);
pDlg->ShowWindow(SW_SHOW);
}
我们可以看到,B.dll中肯定是存在一个ID为IDD_DLG的对话框模板的,按照上面所说的,这个对话框模板被存到了B.dll的状态模块中了。当A.exe中调用这个输出函数时,运行到pDlg->Create(IDD_DLG,NULL)时,它就会去自己的模块状态中去查找标号为IDD_DLG的对话框模板,结果有可能找得到,也有可能找不到。假如A.exe的模块状态中有一个对话框模板的ID恰好等于IDD_DLG时,就能找到,但弹出的对话框并不是你在B.dll中定义的那个。当A.exe的模块状态中没有ID恰好等于IDD_DLG的对话框时,那就是找不到,程序会报错。
[5]怎么解决
在[4]中,当程序A调用B.dll中的输出函数ShowDlg时,也就是说程序A进入了函数ShowDlg。倘若在ShowDlg的入口点处,把应用程序默认的自身模块状态切换成B.dll的模块状态,这样再查找标号为IDD_DLG的对话框时,就会从B.dll的模块状态中查找了,结果就能找到。这个切换语句就是在ShowDlg函数体的第一句处添加:AFX_MANAGE_STATE(AfxGetStaticModuleState());三.测试这个包含对话框资源的DLL
由于这个Dll是采用MFC Regular DLL的格式写的,MSDN中说它可以被任何WIN32程序调用,要测试它,简单起见,只需写个Console程序来测即可。
任务:测试DlgWithTreeCtrl.dll
所需的文件:ExportFunc.h,DlgWithTreeCtrl.lib,DlgWithTreeCtrl.dll。
常规的测试步骤
[1]菜单 文件→新建→项目,在弹出的项目对话框的左栏,选择Visual C++项目,在右栏选择Win32控制台项目。然后在下面的文本框中输入项目的名字testDll,确定,进入Win32控制台程序向导。
[2]Win32控制台程序向导中,在"应用程序设置"中,选择'控制台应用程序",没有必要让你的控制台程序支持MFC,其它都采用默值,完成向导设置。
[3]如果此时testDll项目是debug模式的,将DlgWithTreeCtrl.lib和DlgWithTreeCtrl.dll拷贝到testDll目录中的debug文件夹下。
[4]testDll的主程序文件testDll.cpp中内容如下:
//---------------------------
//testDll.cpp
//--------------------------
#include "stdafx.h"
#include "..\DlgWithTreeCtrl\ExportFunc.h"
#pragma comment(lib, "..\\DlgWithTreeCtrl\\release\\DlgWithTreeCtrl.lib")
void main(void)
{
ShowTreeDlg(NULL);
}
[5]编译连接,运行。运行结果是一个控制台窗口出现,然后一个对话框一闪就不见了。呵呵,对话框确实被显示了,只是控制台程序瞬间就结束了,所以对话框就被自动销毁了。可以在main函数中加上一句:
MessageBox(NULL,"stop",NULL,MB_OK);
让控制台程序不那么快就消亡。
最终结果如下图:四. 还需要继续考虑的问题
我在DlgWithTreeCtrl.dll中做的那个输出函数,new了一个对话框的对象,程序中从始至终都没有释放所new的(堆)空间。会不会内存泄露?这不是一个小问题。换个说法:MFC的窗口对象是怎样从系统中清除的呢?要弄清楚这个问题,必须先搞清楚窗口对象的成分。
一个MFC窗口对象包括两方面的内容:一是窗口对象封装的窗口,即存放在m_hWnd成员中的HWND(窗口句柄),二是窗口对象本身是一个C++对象。要删除一个MFC窗口对象,应该先删除窗口对象封装的窗口,然后删除窗口对象本身。也就是窗口的C++对象的生存期要比窗口长。
[1]窗口的删除
删除窗口最直接方法是调用CWnd:: DestroyWindow或全局API函数:: DestroyWindow,前者封装了后者的功能。前者不仅会调用后者,而且会使成员m_hWnd保存的HWND无效(NULL)。如果DestroyWindow删除的是一个父窗口或拥有者窗口,则该函数会先自动删除所有的子窗口或被拥有者,然后再删除父窗口或拥有者。在一般情况下,在程序中不必直接调用DestroyWindow来删除窗口,因为MFC会自动调用DestroyWindow来删除窗口。例如,当用户退出应用程序时,会产生WM_CLOSE消息,该消息会导致MFC自动调用CWnd:: DestroyWindow来删除主框架窗口。当用户在对话框内按了OK或Cancel按钮时,可调用CWnd:: DestroyWindow来删除对话框及其控件。
[2]窗口对象的删除
窗口对象本身的删除则根据对象创建方式的不同,分为两种情况。在MFC编程中,会使用大量的窗口对象,有些窗口对象以变量的形式嵌入在别的对象内或以局部变量的形式创建在堆栈上,有些则用new操作符创建在堆中。
对于一个以变量形式创建的窗口对象,程序员不必关心它的删除问题,因为该对象的生命期总是有限的,若该对象是某个对象的成员变量,它会随着父对象的消失而消失,若该对象是一个局部变量,那么它会在函数返回时被清除。
对于一个在堆中动态创建的窗口对象,其生命期却是任意长的。因为用new在堆中创建对象,就不能忘记用delete删除对象。有些MFC窗口对象具有自动清除的功能。不需要程序员显示的调用delete来删除它。
------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------
[3]对于我new的那个非模态的对话框,该如何销毁呢?
这个问题缠绕我好几天,至今为止还是没有解决的。经测试,发现上面来自网上的和来自MSDN的资料说的不正确。
例如这句话:"用户退出应用程序时,会产生WM_CLOSE消息,该消息会导致MFC自动调用CWnd:: DestroyWindow来删除主框架窗口。"
经过测试,当我点了对话框窗口的系统菜单上的"关闭"按钮后,产生WM_CLOSE消息,而它并没有调用CWnd:: DestroyWindow来销毁窗口!!!!!!
这个问题最终是在这里得到解决的,去这里看看:
http://community.csdn.net/Expert/topic/4025/4025795.xml?temp=.989773 -
Android 弹出对话框怎么做?(小白速成9)
2021-01-13 11:57:46所以我们还需要学习对话框的制作。对话框就是在程序运行中的弹出窗口,主要分为:警告对话框、进度对话框、日期选择对话框、时间选择对话框…… 警告对话框 简单拖拽一个按钮,绑定一个test事件,然后运用如下代码:...之前我们讲过弹出信息toast,但是toast并不允许用户进行交互,例如选择确定、取消等操作。所以我们还需要学习对话框的制作。对话框就是在程序运行中的弹出窗口,主要分为:警告对话框、进度对话框、日期选择对话框、时间选择对话框……
警告对话框
简单拖拽一个按钮,绑定一个test事件,然后运用如下代码:
package com.example.test_alert; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import android.content.DialogInterface; import android.os.Bundle; import android.view.View; import android.widget.Toast; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void test01(View view){ //创建一个警告对话框 AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("这里是提示信息"); builder.setMessage("对话框的内容在这儿"); AlertDialog.Builder builder1 = builder.setPositiveButton("确定",new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Toast.makeText(MainActivity.this,"选择了确定",Toast.LENGTH_SHORT).show(); } }); builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Toast.makeText(MainActivity.this,"选择了取消",Toast.LENGTH_SHORT).show(); } }); builder.setNeutralButton("再想想", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Toast.makeText(MainActivity.this,"选择了再想想",Toast.LENGTH_SHORT).show(); } }); AlertDialog alertDialog =builder.create();//这个方法可以返回一个alertDialog对象 alertDialog.show(); } }
然后效果如图所示
一个基本的警告对话框就制作完成了,警告对话框的选择按钮建议不超过三个,否则会影响用户的体验,一般都是放两个(确认、取消)或者三个(满意、一般、不满意)等等。警告对话框改进
多个字符串提示框
基本对话框实现以后,我们发现上面提示的文字仅仅是一个字符串,我们还可以做出改进,让它显示多个字符串。
public void test01(View view){ //创建一个警告对话框 AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("这里是提示信息"); builder.setItems(ss, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Toast.makeText(MainActivity.this,ss[which],Toast.LENGTH_SHORT).show(); } });
如图,setItems方法可以将一个数组作为提示的内容,并且可以设置响应的监视器来响应。
单选框
当然,内容也可以是单选框:
builder.setSingleChoiceItems(ss,0, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Toast.makeText(MainActivity.this,ss[which],Toast.LENGTH_SHORT).show(); } });
按照以上代码,我们可以对三个字符串进行选择。相比较于上一个方法,这个方法多了一个参数0,表示点开以后系统默认选择第0个参数,我们也可以设置1或者2,让它默认选择后两个字符串。
多选框
多选也是可以的:
builder.setMultiChoiceItems(ss, null, new DialogInterface.OnMultiChoiceClickListener() { @Override public void onClick(DialogInterface dialog, int which, boolean isChecked) { Toast.makeText(MainActivity.this,ss[which],Toast.LENGTH_SHORT).show(); } });
第二个参数同样是默认的选择情况,我们可以选择传入null,或者一个非空的布尔类型的数组,表示最初的选择情况。
自定义对话框实现
主要使用LayoutInflater类来把自定义的view放入AlertDialog当中进行显示。
首先我们要自己定义我们需要的布局文件:
例如我们新建一个页面叫做login,然后在界面中设置自己需要的组件,我这里随便拖动了一些进去:
public void test01(View view){ //创建一个警告对话框 AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("这里是提示信息"); View login=this.getLayoutInflater().inflate(R.layout.login,null);//获得我们定义好的布局文件 builder.setView(login); AlertDialog alertDialog =builder.create();//这个方法可以返回一个alertDialog对象 alertDialog.show(); }
然后我们就可以对按钮的方法进行绑定,代码如上,实现效果如下:
这样,我们自定义的对话框就可以实现了!!
制作不易,点个赞再走吧!!!
参考自:尚学堂课 -
2015.3.3 VC++6制作MFC dll并在其中使用对话框、引入类的操作
2016-10-15 17:21:00上例建立的dll为非MFC的,不能使用MFC框架,如CString、对话框等类型,使用起来有一定限制。可以建立MFC的Dll来改进。建立MFC Dll的方法: 1、在VC6中新建工程时选择:MFC AppWizard(dll) 2、保持默认的 Regular ... -
WanAndroid-一位练习时长两年半的安卓练习生根据鸿神提供的WanAndroid开放Api来制作的产品级App,采用Kotlin...
2019-09-23 17:36:11一位练习时长两年半的安卓练习生根据鸿神提供的WanAndroid开放Api来制作的产品级App,基本实现了所有的功能,采用Kotlin语言,基于Material Design AndroidX MVP RxJava Retrofit等优秀的开源框架开发,注释超详细,... -
topcoder-zapier-app-源码
2021-02-14 17:06:44Topcoder API和Zapier集成 依存关系 nodejs ) Zapier CLI 扎皮尔 配置 该应用程序的配置位于config.js 。...邀请自己,以便在制作Zap时可以使用此集成,您需要使用Zapier帐户的电子邮件 zapier i -
《Android APP开发入门 使用Android Studio环境》PDF
2018-08-20 21:07:44内容包括使用AndroidStudio开发AndroidApp、Android程序设计基础讲座、应用程序界面设计、事件处理、用户界面的基本组件、高级UI组件、即时信息对话框、用Intent启动程序中的其他Activity、用Intent启动手机内的各种... -
[仿南航app开发日记7]自绘漂亮的课程表界面
2016-12-29 16:51:26前面的博客里面分别讲到了自定义ViewGroup(侧滑菜单)、自定义Dialog(登陆对话框以及背景透明进度条)、使用PopupWindow(下拉方式选择年份),那么今天要讲的是自绘课程表界面,属于android绘图知识,在这之前我... -
HTML5开发移动web应用——SAP UI5篇(4)
2016-02-08 10:54:27我们制作一个按钮,点击该按钮后,自动弹出hellow,world的对话框。 修改App.view.xml中代码为如下形式: controllerName="sap.ui.demo.wt.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> -
Android 制作友好崩溃界面
2019-01-24 17:13:24Android 的默认崩溃机制是 APP 闪退,然后显示一个【xxx 已停止运行】的对话框或 Toast,而崩溃的详情只有开发者在 Logcat 里才能看到,用户看到发生了这样的情况肯定一头雾水,的确,这样默认的异常处理方式很不... -
第1个Android应用程序 Android制作简单单页导航
2021-01-05 13:40:16本例子演示如何添加一个简单的单页导航,在此基础上,再演示如何在第2个页面中显示第1个页面中拨打过的所有电话号码。...单击【转换】按钮,如果转换成功,则【拨号】按钮可用,单击【拨号】按钮,观察弹出的对话框。 -
dmg转换cdr工具_工作杂碎:MAC制作映像(dmg)文件详细步骤
2020-12-28 10:53:04一、认识磁盘工具磁盘工具是mac下非常强大的工具,它涵盖了磁盘分区、修理权限、创建映像(DMG)、刻录光盘等超强功能,善用磁盘...三、新建映像(以BetterZip.app为例)在磁盘工具下点“新建映像”,出现如下对话框,... -
(面向对象程序设计)实验五 动态链接库的制作与调用(二)
2020-06-12 21:29:40(二)动态链接库文件的调用 一、实验目的 (1) 解和掌握类和指向函数的指针的使用。...建立一个基于对话框的文件exe1 1)在exe1.cpp中添加如下文件: BOOL CExe1App::InitInstance() { SetDialogBkColor (R -
移动互联网之路:HTML5+CSS3+jQuery Mobile APP与移动网站设计从入门到精通.李晓斌(带详细书签).pdf
2019-01-09 22:27:244.3 制作文章页面 55 4.4 本章小结 59 第5章 使用HTML 5绘图 60 5.1 标签 60 5.1.1 了解标签 60 5.1.2 在网页中插入canvas元素 60 5.1.3 使用标签实现绘图的流程 61 5.2 绘制基本图形 62 5.2.1 绘制直线 62 ... -
Android实例练习-可爱的小闹钟
2014-02-26 20:28:18这一篇主要使用系统为我们提供的一个服务AlarmManager来制作一个Android小闹钟,同时还涉及到了自定义主题、判断第一次启动应用、自定义动画、对话框、制作指导滑动页面等方面。最后形成一个可以直接在手机上面使用... -
Android菜鸟的成长笔记(25)——可爱的小闹钟
2014-02-26 13:26:00摘要:这一篇主要使用系统为我们提供的一个服务AlarmManager来制作一个Android小闹钟,同时还涉及到了自定义主题、判断第一次启动应用、自定义动画、对话框、制作指导滑动页面等方面。最后形成一个可以直接在手机... -
Android:(6)Dialog的简单体验
2011-08-19 14:59:00注意到android.app包下除了Dialog(可用于制作复杂的对话框)以外,还包括了几个系统定义好的对话框类,如DatePickerDialog、TimePickerDialog及AlertDialog。 其中AlertDialog我上回用过一次,基本上就那样子了,... -
Android学习笔记(6)-关于Dialog的简单体验
2007-12-30 20:29:00注意到android.app包下除了Dialog(可用于制作复杂的对话框)以外,还包括了几个系统定义好的对话框类,如DatePickerDialog、TimePickerDialog及AlertDialog。其中AlertDialog我上回用过一次,基本上就那样子了,... -
关于Dialog的简单体验
2010-08-05 10:14:03注意到android.app包下除了Dialog(可用于制作复杂的对话框)以外,还包括了几个系统定义好的对话框类,如 DatePickerDialog、TimePickerDialog及AlertDialog。 其中AlertDialog我上回用过一次,基本上就那样子了... -
DialogFragment 使用与友好交互
2015-07-30 23:18:48Dialog顾名思义对话框,在android app是最常用的UI组成部分,以往开发基本按照设计自定义一个Dialog。某天无意间发现竟有DialogFragment这个东西,3.0后同Fragment一起更新,罪过罪过,好久没翻文档,这种好东西不... -
一键截图_安卓微商截图宝v5.3.9会员版 装逼信誉图一键生成
2021-01-15 18:41:14手机截图工具(微商截图宝)是一款智能截图服务软件,适合微商使用的截图神器,在这里能够快速进行截图服务,可以设置快捷键,还可以生成各种对话框,制作图片海报等等,需要的伙伴下载哦!手机截图工具简介:微商截图... -
第三次作业
2016-09-24 18:08:00首先我们制作的是一个MP3 APP.为了侯英举同学闲着没事用自己做的APP听歌。本APP可以实现各种基于声音的应用,例如声音录制、音乐播放、网络电话、音乐编辑。实现各种音乐格式的解码与转码。 实现功能 单击【文件】... -
Android学习笔记(6)—关于Dialog的简单体验
2008-12-05 14:13:00<!-- @page { size: 21cm 29.7cm; margin: 2cm } P { margin-bottom: 0.21cm } --> 继续android.app中的几个类的学习,今天的...注意到android.app包下除了Dialog(可用于制作复杂的对话框)以外,还包括了几
-
MaxScale 实现 MySQL 读写分离与负载均衡
-
MySQL 四类管理日志(详解及高阶配置)
-
android新技术!Android跨进程通信导论,架构师必备技能
-
MySQL 事务和锁
-
分区测试-源码
-
android对话框!字节大神强推千页PDF学习笔记,已拿offer附真题解析
-
CO11N-完工确认的BAPI使用
-
梯度带隙AlGaAs / GaAs导线光电阴极的光发射特性
-
CAN总线协议:CAN总线的报文层错误检测
-
Java中Math.floor()和Math.ceil()的区别
-
kleks:Kleks-使用Kanso和CoffeeScript和Stylus作为Couch应用程序的基于纯CouchDB的CMS。 支持多站点设置和Markdown创作-源码
-
使用vue搭建微信H5公众号项目
-
mobile-app:适用于mskirana业务的移动应用程序-源码
-
foodie-cloud-config:Spring云配置服务器-源码
-
libFuzzer视频教程
-
新年计数器-源码
-
MySQL 触发器
-
java.io.IOException: Could not find resource mybatis-config.xml
-
【布道者】Linux极速入门
-
MHA 高可用 MySQL 架构与 Altas 读写分离