金山卫士开源软件之旅(十) KSafeMain工程的分析 1

2023-10-27

 上一次看金山开源到现在已有一两个月了。期间看到QQ群里大家对它很是热情。

最近有时间想看看金山的主界面工程KSafeMain,自己水平有限,总结的东西浅显。但还是愿意拿来与大家分享。希望对大家有帮助。

 

转载请标明是引用于 http://blog.csdn.net/chenyujing1234

欢迎大家提出问题讨论。

 1、超链接的加入

上图中红色标注的地方就是超链接的地方。

它的实现是在dlgfile_header.xml文件中。

    

 

eg:

求助这个按钮:

<link class="linktext5" pos="-238,6" href="http://www.ijinshan.com/safe/help.html?fr=client" crtext="FFFFFF">求助</link>

标红色的部分表此控制的类型为 linktext5,它是定义在def_style.xml文件中.

通过cursor节点的属性实现放上去有手的开关的功能。

 

 

那么是哪里调用了此文件中呢?

在bkwinres.rc2中有

即,我们把此文件定义为509了。

而在dlg_main.xml中对调用了ID为509的XML文件

 

 

2、修复漏洞的实现

 

2、1  界面创建方法

首先绑定dlg_main.xml里的 <tabctrl id="136"

在bkwinres.h中有

#define IDC_TAB_MAIN                            136

 

在beikesafemaindlg.h中有

    BK_NOTIFY_MAP(IDC_RICHVIEW_WIN)
        //BK_NOTIFY_ID_COMMAND(IDCANCEL, OnBkBtnClose)
        BK_NOTIFY_ID_COMMAND(IDC_BTN_SYS_CLOSE, OnBkBtnClose)
        BK_NOTIFY_ID_COMMAND(IDC_BTN_SYS_MAX, OnBkBtnMax)
        BK_NOTIFY_ID_COMMAND(IDC_BTN_SYS_MIN, OnBkBtnMin)
        BK_NOTIFY_TAB_SELCHANGE(IDC_TAB_MAIN, OnBkTabMainSelChange)
    BK_NOTIFY_MAP_END()

 

BOOL CBeikeSafeMainDlg::OnBkTabMainSelChange(int nTabItemIDOld, int nTabItemIDNew)
{

	DEBUG_TRACE(L"Tab Change %d, %d\r\n", nTabItemIDOld, nTabItemIDNew);

	BOOL bRet = FALSE;

	if (m_bFirstPageChange)
	{
		if (0 != nTabItemIDNew)
		{
			PostMessage(MSG_APP_DELAY_EXAM, FALSE);
		}

		m_bFirstPageChange = FALSE;
	}



	bRet = TRUE;
	switch (nTabItemIDNew)
	{
	case 0:
		if (m_bPage0NeverShowed)
		{
			PostMessage(MSG_APP_DELAY_NAVIGATE_IE);
			PostMessage(MSG_APP_DELAY_EXAM, TRUE);

			m_bPage0NeverShowed = FALSE;
		}

		break;

	case 1:
		break;

	case 2:		
		break;
	case 3:    // 修复漏洞
		m_viewVulfix.ShowWindow(SW_SHOW);
		if(!m_bVulfixInited || m_bVulfixRescanRequired)
		{
			BOOL toRescan = TRUE;
			if(m_bVulfixRescanRequired && theEngine && theEngine->m_isRepairing)
			{
				toRescan = FALSE;
			}			
			m_bVulfixInited = TRUE;
			m_bVulfixRescanRequired = FALSE;
			if(toRescan)
				m_viewVulfix.m_viewSoftVul.InitEnv();
		}
		break;
	case  4://系统优化
	case  5://清理
	case  6://网盾
	case  8:// 打开软件管理
	default:
		break;
	}

	return TRUE;
}







 可以得知近好修改漏洞后进入的case是:

 case 3:

处理的第一条是 m_viewVulfix.ShowWindow(SW_SHOW);

m_viewVulfix是CBeikeSafeMainDlg中的成员:

// 修复漏洞页面里的view
 CEmbeddedView m_viewVulfix; 

CEmbeddedView也CBeikeSafeMainDlg一样都是继承自CBkDialogViewImpl。

每个CBkDialogViewImpl的实例中都有三个成员,分别是m_bkHeader、m_bkBody和m_bkFooter,它们分别代表窗口的头部、中间和底部,

它们各自界面元素的加载是在 CBkDialogViewImpl::Load 。

 

 它的类定义很简单:

class CEmbeddedView 
	: public CBkDialogViewImpl<CEmbeddedView>
	, public CIconAnimate<CEmbeddedView>
{
public:
	//  做漏洞扫描动作的类
	CBeikeVulfixHandler m_viewSoftVul;


那么m_viewVulfix是在哪里创建的呢?

(1) CBeikeSafeMainDlg::OnInitDialog 的一开始就初始化了这个变量
BOOL CBeikeSafeMainDlg::OnInitDialog(CWindow /*wndFocus*/, LPARAM /*lInitParam*/)
{

	SetIcon(::LoadIcon((HMODULE)&__ImageBase, MAKEINTRESOURCE(IDI_BEIKESAFE)));
	SetIcon(::LoadIcon((HMODULE)&__ImageBase, MAKEINTRESOURCE(IDI_SMALL)), FALSE);

	_Module.SetActiveWindow(m_hWnd);
	// 创建修复漏洞页面的view
	InitVulFix();

 

它主要是加载界面元素,并创建list控件.

void CBeikeSafeMainDlg::InitVulFix()
{
	// 创建 m_viewVulfix 窗口
	m_viewVulfix.Create(GetViewHWND(), NULL, WS_CHILD|WS_CLIPCHILDREN, 0, 3000);
	// 从 dlg_vul_main.xml 文件中加载控件
	ATLVERIFY( m_viewVulfix.Load( IDR_BK_VULDLG_MAIN ) );
	// 设置修复漏洞处理逻辑类m_viewSoftVul的父窗口
	m_viewVulfix.m_viewSoftVul.SetMainDlg( this );
	// 创建列名为:严重程序、补丁名称、补丁描述、发面日期、状态的列表控件
	m_viewVulfix.Init(m_hWnd);
}

(2) dlg_vul_main.xml文件分析

主要分为两大部分:

扫描或修复状态扫描结果.

从XML文件中可以看到 扫描中与repairing是同一块,暂时把repairing隐藏起来。

 

repairing有五个部分:

 

2、2  按钮处理函数的实现

扫描结果显示的效果图是:

在 case 3:的处理中显示完界面后主要就是调用扫描漏洞的工作:

if(toRescan)
    m_viewVulfix.m_viewSoftVul.InitEnv();

它主要完成 :

初始化扫描引擎;

 加载ksafevul.dll中的API函数, 创建CVulEngine中的IVulEnvironment 接口;

解发开始扫描的消息。

void CBeikeVulfixHandler::InitEnv()
{
	if(!theEngine)
	{
		// 初始化扫描引擎
		theEngine = new CVulEngine;	
		// 加载ksafevul.dll中的API函数, 创建CVulEngine中的IVulEnvironment 接口
		theEngine->_InitFunctions();

		m_WinInfo.Init();
		//m_WinInfo64 = IsWin64();
	}
	// 解发开始扫描的消息
	PostMessage( WMH_SCAN_START, 0, 0);
}
(2、2、1)很多人反映ksafevul.dll 加载不到。此dll的得到金山是提供源码的。

大家可以用VS2005打开 beikesafevul.sln

(2、2、1、1)首先编译BeikeUtils工程。

会出现以下报错:

1>d:\自己的经验总结\自己的经验总结\金山开源\oss\pcmanager\src\publish\common/registrywow.h(18) : error C2146: 语法错误 : 缺少“;”(在标识符“OpenKeyEx”的前面)
1>d:\自己的经验总结\自己的经验总结\金山开源\oss\pcmanager\src\publish\common/registrywow.h(18) : error C4430: 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int
1>d:\自己的经验总结\自己的经验总结\金山开源\oss\pcmanager\src\publish\common/registrywow.h(19) : error C4430: 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int


解决方法请参考我的另一篇文章:(里面有同样的出错的处理)

金山卫士开源软件之旅(一) VS 2005环境下编译

(2、2、1、2) 其它的工程都顺利编译通过,只有两个工程ksafevul、VulfixLib出现报错:

envutils.h(428) : error C3861: “IsWin64”: 找不到标识符

    它是用来判断系统是不是64位用的。

既然源码没有提供此函数,那么我们自己来实现吧:

考虑到调用到此函数的cpp文件都包含了BeikeUtils.h文件,我决定在BeikeUtils 中添加此函数体

BeikeUtils.h中添加

// 判断是不是64位的系统
// 返回值: TRUE 是64位系统;FALSE 不是64位系统
BOOL IsWin64();


BeikeUtils.cpp里添加

BOOL IsWin64()
{
	#define IS_64BIT_OS (sizeof(void *) == 8)
	return IS_64BIT_OS;
}

ksafevul工程编译通过后就生成了ksafevul.dll.这样大家就可以调试扫描漏洞与修复漏洞的过程了。

(2、2、2) WMH_SCAN_START消息的回调函数如下:
void CBeikeVulfixHandler::OnBkBtnScan()
{
	if(m_firstInited)
	{
		// Clean downloaded files 
		BOOL bSave = BKSafeConfig::Get_Vulfix_SaveDownFile();
		if( !bSave )
			theEngine->m_fixLog.CleanFiles(FALSE, NULL);
		m_firstInited = FALSE;
		SetItemVisible(1015, !theEngine->IsSystemSupported());
	}
	// 把扫描结果列表清空
	ResetListCtrl(m_wndListCtrlVul);
	// 调用引擎起一线程开始扫描
	if( theEngine->ScanVul( m_RefWin.m_hWnd ) )
	{
		// 界面处理
		m_dwScanBeginTime = GetTickCount();
		m_bScanStarted = FALSE;

		m_nScanState = 0;
		m_nTotalItem = 0;
		m_nCurrentItem = 0;
		_SetDisplayState(SCANSTATE_SCANNING);
		_SetScanProgress( 0 );
		m_RefWin.SetTimer(0, 200, NULL);
		m_wndListCtrlVul.SetEmptyString(BkString::Get(IDS_VULFIX_5027));
		m_RefWin.StartIconAnimate( IDC_IMG_VULFIX_SCAN_ANIMATION, IDC_PROGRESS_VULFIX_SCANNING, 300);
		SetItemDWordAttribute(IDC_PROGRESS_VULFIX_SCANNING, "showpercent", 0);
	}
}


以上主要的工作是调用ScanVul创建一线程完成扫描

bool CVulEngine::ScanVul(HWND hWnd)
{
	if(m_hThreadVulScan)
		_SafeTerminateThread( m_hThreadVulScan, FALSE );

	m_bVulScanCanceled = FALSE;
	m_hThreadVulScan = CreateThread(NULL, 0, ThreadFunc_Scan, (void*)hWnd, 0, NULL);
	return m_hThreadVulScan!=NULL;
}


 

DWORD WINAPI CVulEngine::ThreadFunc_Scan( LPVOID lpParam )
{
	HWND hWnd = (HWND)lpParam;
	theEngine->_ScanVul(hWnd);	
	return 0;
}


 

void CVulEngine::_ScanVul(HWND hWnd)
{
	DWORD dwFlags = _GetScanFlags();
	CWindowVulfixObserver observer( hWnd);
	if(!m_pVulScan)
		// 创建扫描组件IVulfix
		m_pVulScan = CreateVulFix();
	
	HRESULT hr = E_POINTER;
	if(m_pVulScan)
	{
		// 设计扫描组件的观察者对象
		m_pVulScan->SetObserver(&observer);
		// 执行扫描(要持续一段时间)
		hr = m_pVulScan->Scan(dwFlags);
		DEBUG_TRACE(_T("CVulEngine::_ScanVul ScanVul %x(%x) \n"), hr, dwFlags);
		m_pVulScan->SetObserver(NULL);
	}
	// 通知扫描完成
	_RelayMessage(hWnd, WMH_SCAN_DONE, m_bVulScanCanceled, hr);
}


 

(2、2、3)  DLL也加载到了,为什么修复漏洞不是没有扫描的结果呢。

我也被这个问题困扰着,从KSafeMain工程中我们只能知道

hr = m_pVulScan->Scan(dwFlags);

返回了失败.所以没有扫描结果。

但原因是什么呢?我决定对此打破砂锅。

(2、2、3、1)Scan的实现在VulfixLIb工程中(在上面的(2、2、1)中讲到)

 

说是扫描,其实是 从数据库文件 office64.dat、office.dat、soft.dat、system64.dat、system.dat中读取漏洞列表

看到这里更坚定了我对对金山的开源的失望是对的。

//  从数据库文件 office64.dat、office.dat、soft.dat、system64.dat、system.dat中读取漏洞列表
HRESULT CImplVulfix::Scan(DWORD dwFlags)
{
	TIME_CHECK( _T("CImplVulfix::Scan ") );
	m_Canceled = FALSE;
	T_ComInit __init__com__;
	HRESULT hr ; 	
	do
	{
		// 把数据库和补丁列表清除
		Reset();
		GetLangID();
		
		CSysEnv& sysEnv = singleton<CSysEnv>::Instance();
		sysEnv.Init();
		if( FAILED( hr=sysEnv.IsSupported(FALSE) ) )
			break;
		
		Init();
		m_objIgnore.LoadIgnoreDB();

		CString filenameSystem, filenameOffice, filenameSoft;
		GetXmlDBFileName(VTYPE_WINDOWS, filenameSystem, IsWin64());
		GetXmlDBFileName(VTYPE_OFFICE, filenameOffice, FALSE);
		GetXmlDBFileName(VTYPE_SOFTLEAK, filenameSoft, FALSE);
		if( !PathFileExists(filenameSystem) && !PathFileExists(filenameOffice) && !PathFileExists(filenameSoft) )
		{
			hr = KERR_LOAD_FILE;
			break;
		}
		// 创建OS Filter
		m_pFilterOS = CreateOSFilter(sysEnv.m_WinVer, dwFlags);
		// 初始化OS Filter
		InitOSFilter( m_pFilterOS, sysEnv.m_WinVer, dwFlags);
		if( m_pFilterOS->WaitComplete() )
		{
			// 设计数据库对象的观察者
			m_dbOS.SetObserver( m_Observer );
			m_dbOffice.SetObserver( m_Observer );
			m_dbSoft.SetObserver( m_Observer );
			m_pFilterOS->SetIIgnore( &m_objIgnore );
			
			CString filename;
			try
			{
				FixLocale();

				//BOOL bWin64 = IsWin64();
				//PVOID OldValue = NULL;
				//if(bWin64)
				//	Wow64DisableWow64FsRedirection(&OldValue);
				
				// 从data文件夹里的文件载入数据库数据
				!m_Canceled && m_dbOffice.Load( filenameOffice, m_pFilterOS, dwFlags );
				!m_Canceled && sysEnv.IsLangSupported() && sysEnv.IsOsSupported() && m_dbOS.Load( filenameSystem, m_pFilterOS, dwFlags );
				!m_Canceled && m_dbSoft.Load( filenameSoft, NULL, dwFlags);

				//if(bWin64)
				//	Wow64RevertWow64FsRedirection(OldValue);
			}
			catch (...)
			{
				hr = KERR_LOAD_FILE;
			}
			
			CSimpleArray<LPTUpdateItem> arrLeaks;
			CSimpleArray<TReplacedUpdate*> arrReplaced;		
			// 从数据库中获得列表 
			m_dbOS.GetUnfixedLeakList( arrLeaks, m_arrFixedVuls, m_arrInvalid, arrReplaced );
			m_dbOffice.GetUnfixedLeakList( arrLeaks, m_arrFixedVuls, m_arrInvalid, arrReplaced );

			const CSimpleArray<int> &arrExpired = m_dbOS.GetExpiredIds();
			CSimpleArray<int> arrReplacedId;
			for(int i=0; i<arrReplaced.GetSize(); ++i)
			{
				arrReplacedId.Add( arrReplaced[i]->nKBID );
			}
			
			// select soft ignored vuls 
			CSimpleArray<LPTVulSoft> arrSoftLeaks;
			m_dbSoft.GetUnfixedLeakList( arrSoftLeaks );
			for(int i=0; i<arrSoftLeaks.GetSize(); ++i)
			{
				LPTVulSoft ps = arrSoftLeaks[i];
				ps->isIgnored = m_objIgnore.IsIgnored( ps->nID );
				if( ps->isIgnored )
				{
					LPTUpdateItem pu = new TUpdateItem;
					pu->m_nType = VTYPE_SOFTLEAK;
					pu->nID = ps->nID;
					pu->strName = ps->matchedItem.strName;
					pu->strDescription = ps->strDescription;
					pu->strWebpage = ps->matchedItem.strWebpage;
					pu->nWarnLevel = ps->nLevel;
					pu->strPubdate = ps->strPubdate;

					m_arrIgnoredVuls.Add( pu );
					m_arrIgnoredVulsFromSoft.Add( pu );
				}
				else
					m_arrSoftLeaks.Add( ps );
			}
			
			// select installable, ignored , expired 
			for(int i=0; i<arrLeaks.GetSize(); ++i )
			{
				LPTUpdateItem &pi = arrLeaks[i];
				pi->isExpired = arrExpired.Find( pi->nID )!=-1;

				if(pi->isExpired)
					m_arrInvalid.Add( pi );
				else if(pi->isIgnored)
					m_arrIgnoredVuls.Add( pi );
				else
				{
					bool bReplaced = arrReplacedId.Find( pi->nID )!=-1;
					if(!bReplaced)
						m_arrLeaks.Add( pi );
				}
			}
			
			// find correct replace relationship 
			for(int i=0; i<arrReplaced.GetSize(); ++i)
			{
				TReplacedUpdate* pu = arrReplaced[i];
				BOOL bInstalled = FindArrayIndex( m_arrFixedVuls, pu->nKBID )!=-1;
				if( !bInstalled )
				{
					if( FindArrayIndex(m_arrFixedVuls, pu->nKBID2)!=-1 
						|| FindArrayIndex(m_arrLeaks, pu->nKBID2)!=-1
						|| FindArrayIndex(m_arrIgnoredVuls, pu->nKBID2)!=-1 )
						m_arrReplacedUpdates.Add( pu );
				}
			}

			// - 保存最后无漏洞时间, 使得下次不再提示有风险 
			// -- 非快速扫描的结果才有效果 
			if( RequireUsingInterface() && !(dwFlags & VULSCAN_EXPRESS_SCAN) )
			{
				BOOL hasMustLeak = FALSE;
				const CSimpleArray<LPTUpdateItem> &arrLeaks = GetResults();
				for(int i=0; i<arrLeaks.GetSize(); ++i)
				{
					if(arrLeaks[i]->nWarnLevel>0)
					{
						hasMustLeak = TRUE;
						break;
					}
				}
				CString strVal;
				if(!hasMustLeak)
				{
					T_Date date;
					GetLatestPackgeDate(date.nYear, date.nMonth, date.nDay);
					strVal.Format(_T("%04d-%02d-%02d"), date.nYear, date.nMonth, date.nDay);
				}
				WriteVulConfig(_T("VulScan"), _T("LastSafePkgDate"), strVal);
			}			
		}
		
		hr = KERR_NONE;
	} while (FALSE);
	return hr;
}


 

(2、2、3、2) 只需要把数据库文件拷到KSafeMain工程目录下即可得到扫描结果。

图一中的整个文件夹data拷到图二中即可

图一:

 

图二:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

金山卫士开源软件之旅(十) KSafeMain工程的分析 1 的相关文章

  • PHP 构造函数返回 NULL

    我有这个代码 是否有可能User对象构造函数以某种方式失败 以便 this gt LoggedUser被分配了一个NULL构造函数返回后值和对象被释放吗 this gt LoggedUser NULL if SESSION verbiste
  • 使用 EntityFramework 使用空参数值调用存储过程

    我在 sqlserver 2008 上有一个存储过程 其中一个参数接受空值 我不知道如何使用参数上的空值来调用该 SP 为了获得更多上下文 我正在使用 EntityFramework 6xx 在下一个示例中 参数 status Compat
  • 如何在Ireport中给出多选参数空值的条件?

    我正在使用以下方法编写报告iReport http en wikipedia org wiki JasperReports Third party tools我想在其中添加空值条件 它使用单选选项 city P p city or P p
  • execlp 多个“程序”

    我想运行类似的东西 cat file tar base64 myprogram c base64 d tar zvt I use execlp运行该进程 当我尝试运行类似的东西时cat它有效 但如果我尝试运行base64 d tar zvt
  • Linux 上 的默认键绑定是什么? Mac 将此绑定到命令

    Vim 的一些示例设置 例如janus https github com carlhuda janus 将命令键绑定到某些命令 例如 Command Shift F for Ack map
  • Mockito - thenReturn 始终返回 null 对象

    我正在尝试实现 Mockito 来测试特定方法 但 thenReturn 似乎总是返回一个 null 对象 而不是我想要的 CUT public class TestClassFacade injected via Spring priva
  • Unix 命令列出包含字符串但*不*包含另一个字符串的文件

    如何递归查看包含一个字符串且不包含另一个字符串的文件列表 另外 我的意思是评估文件的文本 而不是文件名 结论 根据评论 我最终使用了 find name html exec grep lR base maps xargs grep L ba
  • mysqli bind_param 中的 NULL 是什么类型?

    我正在尝试将参数绑定到 INSERT INTO MySQLi 准备好的语句 如果该变量存在 否则插入 null 然后我知道 type variable i corresponding variable has type integer d
  • Microsoft SQL:CASE WHEN 与 ISNULL/NULLIF

    除了可读性之外 在防止 SQL 中的除以 0 错误时 使用 CASE WHEN 语句与 ISNULL NULLIF 相比还有什么显着的好处吗 CASE WHEN BeginningQuantity BAdjustedQuantity 0 T
  • C# 和 SQL Server:如果字符串值为空,如何在命令参数中插入 DBNull.Value?

    我已经搜索了几个小时 但找不到解决方案 我正在将一些字符串插入 SQL 但是有时 我用来执行此操作的方法可能包含空字符串 即 因此我想在 SQL Server 中插入一个空值 首先我测试我的方法以确保我能够插入DBNull Value通过使
  • 将 null 转换为对象?

    我今天遇到了这段代码 AsyncInvoke OnTimeMessageTimer object null ElapsedEventArgs null 有没有什么问题 有时 当方法重载时 您需要这样做 以告诉编译器您正在调用哪一个 null
  • KDB 排除具有空值的行

    我有一个表 其中有一些带有空值的单元格 分散在数据集中 有什么简单的方法可以排除任何列中包含空值的所有行吗 我只是想避免这种情况 select from T where not null col1 not null col2 not nul
  • 左右 mac“命令”键的配置不同吗?

    我想知道是否可以将右侧的 mac 命令 设置为像 ctrl 键一样 但保留左侧 命令 键的默认功能 谢谢 有一个非常棒的应用程序 称为 Ukelele 免费 不幸的是 它无法区分左右命令键 然而 我最近发现了一个更好的应用程序 名为 Con
  • 使用命令启动 Tmux 并指定配置文件

    我正在研究交互式的小脚本 我试图启动 tmux 既指定命令 以便当进程退出时 tmux 会话退出 并使用配置文件 但似乎这是不可能的 tmux new session d s myapp python myapp py f myapp tm
  • 按下按钮时有多个命令

    我想在单击按钮时运行多个功能 例如我希望我的按钮看起来像 self testButton Button self text test command func1 command func2 当我执行此语句时 我收到错误 因为我无法将某些内容
  • Ruby 在特定目录中运行 shell 命令

    我知道如何在 Ruby 中运行 shell 命令 例如 x cmd 但是 如何指定运行此命令的目录 有没有类似的脱壳方式 类似subprocess Popen在Python中 subprocess Popen r c mytool tool
  • 使用绑定和空值命中 Oracle 索引的最佳查询

    我有一个表 该表在多个列上有一个索引 其中许多列可以为空 CREATE UNIQUE INDEX UX MYTABLE A B C D E ON MYTABLE A B C D E 现在 我在 C 代码中尝试检查该表并精确命中索引 对于每个
  • 何时为 WPF/MVVM 使用事件和命令?

    我正在练习如何使用 MVVM 模式编写 WPF 应用程序 到目前为止 我还没有在我的代码中使用命令 在我的视图模型中我实现INotifyPropertyChanged并使用 事件PropertyChangedEventHandler Pro
  • 从视图模型调用方法的命令

    好吧 我倾向于避免使用命令 因为它们总是让我感到困惑 但我正在进行一个新项目 并且正在尝试正确构建它 并且在我看来没有任何代码隐藏 基本上我现在想做的就是连接一个按钮来触发一个命令 在我的视图模型上执行一些操作 但不知何故 如此简单的事情仍
  • 淹没在空无的海洋中

    我继承的一个应用程序跟踪对材料样品执行的实验室测试结果 数据存储在单个表 tblSampleData 中 其主键为 SampleID 并有 235 列代表潜在的测试结果 问题是每个样本仅执行少量测试 因此每行包含超过 200 个空值 实际上

随机推荐

  • @FeignClient 注解的使用与常见问题

    概述 Feign 是一个声明式的 Web 服务 通过定义一个添加相应注解的接口 即可完成一个 Web 服务的接口 SpringCloud 对 Feign 进行了封装以后 其开始能够支持 Spring MVC 标准注解 同时在 SpringC
  • 有序数组合并

    数组合并是归并排序中的一个步骤 今单独就两个有序数组的合并给出代码实现 归并排序的另一个步骤就是递归 递归就是一个方法在其方法体的某个地方调用自己 这样就会将同一个逻辑不断的压栈 到达递归条件后 又一层层地出栈 直到所有方法被压栈的部分都被
  • ARGB与RGB、RGBA的区别

    ARGB 是一种色彩模式 也就是RGB色彩模式附加上Alpha 透明度 通道 常见于32位位图的存储结构 RGB 色彩模式是工业界的一种颜色标准 是通过对红 R 绿 G 蓝 B 三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的
  • HikariPool-1 - Failed to validate connection com.mysql.cj.jdbc....Possibly consider using a shorter

    今天使用springboot遇到了这样的问题 springboot项目启动开始可以访问数据库 但是几分钟之后就会报错 idea报错信息 HikariPool 1 Failed to validate connection com mysql
  • 【技术分享】开启机器学习之旅的8个推荐Python库

    机器学习是当今的热门话题之一 Python 是众多用户中排名第一的编程语言 然而 Python 是一种通用编程语言 这意味着它被用于许多不同的领域 要使用 Python 进行机器学习 除了通用Python之外 您还需要学习一些额外的 Pyt
  • SSH和SSM对比总结

    Java开发之路 2016 10 18 11 19 当下流行的两种企业开发MVC开源框架 是我们Java程序猿必备知识能力 MVC 即模型 model 视图 view 控制器 controller 的缩写 一种软件设计典范 用一种业务逻辑
  • MVC三层架构的模式

    大家好 今天给大家分享一下MVC 三层架构的模式 首先你要知道 所谓的MVC就是一种面向于javaee企业级开发的设计模式 这里要强调一点 MVC 不是一种技术 不是一种像spring 那样的框架 它是一种思想 可以理解为一种解决问题的风格
  • 001学习亿级流量搭建-ubuntu-小白式环境搭建准备

    本人也是刚开始学习亿级流量搭建 包括虚拟机安装 java配置 系统配置 有什么不对 可以微信公众号一起交流 java微技术 环境搭建准备 本人用ubuntu16 04 下载地址http releases ubuntu com 16 04 u
  • java selenium 环境搭建

    eclipse运行selenium webdriver工程 1 需要三个文件selenium server standalone 3 141 0 jar selenium java 4 0 jar和selenium java 4 0 0 s
  • 一些算法岗的校招面经

    从今年3月份暑期实习到秋招一直投的算法岗 数据挖掘 机器学习 今年听说投算法的人特别多 竞争激烈 自己之前本来想去金融 后来觉得还是喜欢互联网 从去年11月才开始好好看书 又不是CS科班出身 所以面试毫无优势可言 基本上把大半个互联网公司都
  • 奇迹服务器放虚拟机,虚拟机双开奇迹教程

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 准备工作 1 VMware Workstation 5 5 4 2 XP安装盘 没有的人可以去买个或去下个系统 最好是最原始的系统没任何补丁的 安装系统的时候把虚拟系统里面的硬盘分2个区 一个盘
  • 互联网产品中的平台、社区、软件、网站、品牌等科普

    文章目录 GitHub GitLab xiaomi cn 微博 B站 MIUI Android Redmi ROM LineageOS SU ASUS Nokia Nubia NVIDIA OnePlus Razer Fairphone S
  • 游戏开发unity编辑器扩展知识系列:获取选中对象

    参考 UnityEditor的Selection类
  • amd raid for Linux,AMD平台RAID 0安装

    AMD平台RAID 0安装 2011 05 29 16 07 47 标签 电脑 it 分类 技术 AMD平台RAID 0安装 AMD平台的RAID 0安装要稍微复杂一些 这主要是因为安装系统的时候 Windows 7以及Windows Vi
  • 朴素贝叶斯分类算法

    版权声明 本文为CSDN博主 JensLee 的原创文章 遵循 CC 4 0 BY SA 版权协议 转载请附上原文出处链接及本声明 原文链接 https blog csdn net LEE18254290736 article detail
  • wangEditor富文本编辑的使用(上传视频上传图片)

    我认为比较重要的是上传图片跟上传视频比较重要
  • 【MySQL】第一篇

    首先需要调出MySQL 5 7 Command Line Client 界面 开始 程序 MySQL MySQL 5 7 Command Line Client 启动 MySQL 5 7 Command Line Client 然后MySQ
  • 自媒体必备素材库,免费、商用,赶紧马住~

    自媒体经常需要用到各类素材 本期就给大家安利6个自媒体必备的素材网站 免费 付费 商用都有 建议收藏起来 1 菜鸟图库 https www sucai999 com video html v NTYwNDUx 菜鸟图库可以找到设计 办公 图
  • jmeter 获取全部响应_jmeter 获取响应头数据(Respones headers)

    最近遇到一个请求重定向 想要判断url 是否和预期一致 找了下有两种方法 一 用正则表达式提取器 1 想要提取如下图响应数据 正则表达是提取设置如下 二 beanshell 断言 该组件可以直接获取ResponseHeaders 底部显示如
  • 金山卫士开源软件之旅(十) KSafeMain工程的分析 1

    上一次看金山开源到现在已有一两个月了 期间看到QQ群里大家对它很是热情 最近有时间想看看金山的主界面工程KSafeMain 自己水平有限 总结的东西浅显 但还是愿意拿来与大家分享 希望对大家有帮助 转载请标明是引用于 http blog c