⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fancontrol.cpp

📁 这是老外开发的IBM、LENOVE风扇控制程序
💻 CPP
字号:

// --------------------------------------------------------------
//
//  Thinkpad Fan Control
//
// --------------------------------------------------------------
//
//	This program and source code is in the public domain.
//
//	The author claims no copyright, copyleft, license or
//	whatsoever for the program itself (with exception of
//	WinIO driver).  You may use, reuse or distribute it's 
//	binaries or source code in any desired way or form,  
//	Useage of binaries or source shall be entirely and 
//	without exception at your own risk. 
// 
// --------------------------------------------------------------

#include "fancontrol.h"







//-------------------------------------------------------------------------
//  constructor
//-------------------------------------------------------------------------
FANCONTROL::FANCONTROL(HINSTANCE hinstapp)
	: hwndDialog(NULL),
		CurrentMode(-1),
		PreviousMode(-1),
		Cycle(5),
		CurrentIcon(-1),
		hThread(NULL),
		FanBeepFreq(440),
		FanBeepDura(50),
		ReadErrorCount(0),
		MaxReadErrors(10),
		pTaskbarIcon(NULL),
		MinimizeToSysTray(FALSE),
		StartMinimized(FALSE),
		MinimizeOnClose(FALSE),
		ActiveMode(false),
		FinalSeen(false)
{
	int i= 0;
	char buf[256]= "";

	// clear title strings
	setzero(this->Title, sizeof(this->Title));
	setzero(this->Title2, sizeof(this->Title2));
	setzero(this->LastTitle, sizeof(this->LastTitle));
	setzero(this->CurrentStatus, sizeof(this->CurrentStatus));
	setzero(this->IgnoreSensors, sizeof(this->IgnoreSensors));

	this->IconLevels[0]= 50;	// yellow icon level
	this->IconLevels[1]= 55;	// orange icon level
	this->IconLevels[2]= 60;	// red icon level


	// initial default "smart" table
	setzero(this->SmartLevels, sizeof(this->SmartLevels));
	this->SmartLevels[i].temp= 50;  this->SmartLevels[i].fan= 0; i++;
	this->SmartLevels[i].temp= 55;  this->SmartLevels[i].fan= 3; i++;
	this->SmartLevels[i].temp= 60;  this->SmartLevels[i].fan= 5; i++;
	this->SmartLevels[i].temp= 65;  this->SmartLevels[i].fan= 7; i++;
	this->SmartLevels[i].temp= 70;  this->SmartLevels[i].fan= 128; i++;
	this->SmartLevels[i].temp= -1;  this->SmartLevels[i].fan= 0; i++;


	this->hwndDialog= ::CreateDialogParam(hinstapp, 
										MAKEINTRESOURCE(9000), 
										HWND_DESKTOP, 
										(DLGPROC)BaseDlgProc, 
										(LPARAM)this);

	if (this->hwndDialog) {
		::GetWindowText(this->hwndDialog, this->Title, sizeof(this->Title));
		strcat(this->Title, " V" FANCONTROLVERSION);
		::SetWindowText(this->hwndDialog, this->Title);

		::SetWindowLong(this->hwndDialog, GWL_USERDATA, (ULONG)this);
		::SendDlgItemMessage(this->hwndDialog, 8112, EM_LIMITTEXT, 256, 0);
		::SendDlgItemMessage(this->hwndDialog, 9200, EM_LIMITTEXT, 4096, 0);
		::SetDlgItemText(this->hwndDialog, 8310, "7");
	

		// config file
		this->ReadConfig("fancontrol.ini");



		// taskbaricon (keep code after reading config)
		if (this->MinimizeToSysTray) {
			this->pTaskbarIcon= new	TASKBARICON(this->hwndDialog, 10, "Thinkpad Fan Control");
		}


		// read current fan control status and set mode buttons accordingly 
		if (this->ActiveMode==2) {
			this->CurrentMode= 2;
		}
		else
		if (this->ReadEcStatus(&this->State)) {
			if (this->State.FanCtrl & 0x80) {
				this->CurrentMode= 1;
			}
			else {
				this->CurrentMode= 3;

				char buf[16]= "";
				sprintf(buf, "%d", this->State.FanCtrl & 0x3f);
				::SetDlgItemText(this->hwndDialog, 8310, buf);
			}
		}

		this->ModeToDialog(this->CurrentMode);
		this->PreviousMode= 1;


		// enable/disable mode radiobuttons
		::EnableWindow(::GetDlgItem(this->hwndDialog, 8300), this->ActiveMode);
		::EnableWindow(::GetDlgItem(this->hwndDialog, 8301), this->ActiveMode);
		::EnableWindow(::GetDlgItem(this->hwndDialog, 8302), this->ActiveMode);
		::EnableWindow(::GetDlgItem(this->hwndDialog, 8310), this->ActiveMode);

		// make it call HandleControl initially
		::PostMessage(this->hwndDialog, WM__GETDATA, 0, 0);


		::SetTimer(this->hwndDialog, 1, this->Cycle*1000, NULL);	// fan update
		::SetTimer(this->hwndDialog, 2, 500, NULL);					// title update

		if (!this->MinimizeToSysTray)
			::ShowWindow(this->hwndDialog, TRUE);

		if (this->StartMinimized)
			::ShowWindow(this->hwndDialog, SW_MINIMIZE);
	}
}



//-------------------------------------------------------------------------
//  destructor
//-------------------------------------------------------------------------
FANCONTROL::~FANCONTROL()
{
	if (this->hThread) {
		::WaitForSingleObject(this->hThread, 2000);
		this->hThread= NULL;
	}

	if (this->pTaskbarIcon) {
		delete this->pTaskbarIcon;
		this->pTaskbarIcon= NULL;
	}


	if (this->hwndDialog)
		::DestroyWindow(this->hwndDialog);
}


//-------------------------------------------------------------------------
//  mode integer from mode radio buttons
//-------------------------------------------------------------------------
int
FANCONTROL::CurrentModeFromDialog()
{
	BOOL modetpauto= ::SendDlgItemMessage(this->hwndDialog, 8300, BM_GETCHECK, 0L, 0L),
		 modefcauto= ::SendDlgItemMessage(this->hwndDialog, 8301, BM_GETCHECK, 0L, 0L),
		 modemanual= ::SendDlgItemMessage(this->hwndDialog, 8302, BM_GETCHECK, 0L, 0L);

	if (modetpauto) 
		this->CurrentMode= 1;
	else
	if (modefcauto) 
		this->CurrentMode= 2;
	else
	if (modemanual)
		this->CurrentMode= 3;
	else
		this->CurrentMode= -1;


	return this->CurrentMode;
}


void
FANCONTROL::ModeToDialog(int mode)
{
   ::SendDlgItemMessage(this->hwndDialog, 8300, BM_SETCHECK, mode==1, 0L);
   ::SendDlgItemMessage(this->hwndDialog, 8301, BM_SETCHECK, mode==2, 0L);
   ::SendDlgItemMessage(this->hwndDialog, 8302, BM_SETCHECK, mode==3, 0L);
}



//-------------------------------------------------------------------------
//  process main dialog
//-------------------------------------------------------------------------
int FANCONTROL::ProcessDialog()
{

	MSG qmsg, qmsg2;
	int dlgrc= -1;

	if (this->hwndDialog) {
		for (;;) {
			BOOL nodlgmsg= FALSE;

			::GetMessage(&qmsg, NULL, 0L, 0L);

			// control movements
			if (qmsg.message!=WM__DISMISSDLG && IsDialogMessage(this->hwndDialog, &qmsg)) {
				continue;
			}

			qmsg2= qmsg;
			TranslateMessage(&qmsg);
			DispatchMessage(&qmsg);

			if (qmsg2.message==WM__DISMISSDLG && qmsg2.hwnd==this->hwndDialog) {
				dlgrc= qmsg2.wParam;
				break;
			}
		}
	}

	return dlgrc;
}



//-------------------------------------------------------------------------
//  dialog window procedure (map to class method)
//-------------------------------------------------------------------------
ULONG CALLBACK
FANCONTROL::BaseDlgProc(HWND hwnd, ULONG msg, WPARAM mp1, LPARAM mp2)
{
	ULONG rc= FALSE;

	FANCONTROL *This= (FANCONTROL*)GetWindowLong(hwnd, GWL_USERDATA);

	if (This) 
		rc= This->DlgProc(hwnd, msg, mp1, mp2);

	return rc;
}



//-------------------------------------------------------------------------
//  dialog window procedure as class method
//-------------------------------------------------------------------------
ULONG 
FANCONTROL::DlgProc(HWND hwnd, ULONG msg, WPARAM mp1, LPARAM mp2)
{
	ULONG rc= 0, ok, res;


	switch (msg) {

		case WM_INITDIALOG:
				// placing code here will NOT work!
				// (put it into BaseDlgProc instead)
				break;


		case WM_TIMER:
				switch (mp1) {

					case 1:		// update fan state	
						::PostMessage(this->hwndDialog, WM__GETDATA, 0, 0);
						break;


					case 2:		// update window title
						res= this->IsMinimized();
						if (res && strcmp(this->LastTitle, this->Title2)!=0) {
							::SetWindowText(this->hwndDialog, this->Title2);
							strcpy(this->LastTitle, this->Title2);
						}
						else 
						if (!res && strcmp(this->LastTitle, this->Title)!=0) {
							::SetWindowText(this->hwndDialog, this->Title);
							strcpy(this->LastTitle, this->Title);
						}

						if (this->pTaskbarIcon) {
							this->pTaskbarIcon->SetTooltip(this->Title2);

							int icon= -1;

							if (this->CurrentModeFromDialog()==1) {
								icon= 10;	// gray
							}
							else {
								icon= 11;	// blue
								for (int i= 0; i<ARRAYMAX(this->IconLevels); i++) {
									if (this->MaxTemp>=this->IconLevels[i]) {
										icon= 12+i;	// yellow, orange, red
									}
								}
							}

							if (icon!=this->CurrentIcon && icon!=-1) {
								this->pTaskbarIcon->SetIcon(icon);
								this->CurrentIcon= icon;
							}
						}
						break;
						

					default:
						break;
				}
				break;


		case WM_COMMAND:
				if (HIWORD(mp1)==BN_CLICKED || HIWORD(mp1)==EN_CHANGE) {
					int cmd= LOWORD(mp1);

					if (cmd>=8300 && cmd<=8302 || cmd==8310) {  // radio button or manual speed entry
						::PostMessage(hwnd, WM__GETDATA, 0, 0);
					}
					else 
					switch (cmd) {
						case 5001: // bios
						case 5002: // smart
									this->ModeToDialog(cmd-5000);
								   break;


						case 5010: // show window
								   ::ShowWindow(this->hwndDialog, TRUE);
								   ::SetForegroundWindow(this->hwndDialog);
								   break;

						case 5020: // end program

									// don't close if we can't set the fan back to bios controlled
									if (!this->ActiveMode || this->SetFan("On close", 0x80, true)) {
										::PostMessage(hwnd, WM__DISMISSDLG, IDCANCEL, 0); // exit from ProcessDialog() 
									}
								    break;

					}
				}
				break;
			

		case WM_CLOSE:
				if (this->MinimizeOnClose && this->MinimizeToSysTray) 
					::ShowWindow(this->hwndDialog, SW_MINIMIZE);
				else
					::PostMessage(this->hwndDialog, WM_COMMAND, 5020, 0); // End Program

				rc= TRUE;
				break;


		case WM_MOVE:
		case WM_SIZE:
				if (mp1==SIZE_MINIMIZED && this->MinimizeToSysTray) {
				    ::ShowWindow(this->hwndDialog, FALSE);
				}
				rc= TRUE;
				break;


		case WM_DESTROY:
				break;




		//
		// USER messages
		//

		case WM__GETDATA:
				if (!this->hThread) 
					this->hThread= this->CreateThread(FANCONTROL_Thread, (ULONG)this);
				break;


		case WM__NEWDATA:
				if (this->hThread) {
					::CloseHandle(this->hThread);
					this->hThread= 0;
				}

				ok= mp1;  // equivalent of "ok= this->ReadEcStatus(&this->State);" via thread
				
				if (ok) {
					this->ReadErrorCount= 0;
					this->HandleData();
				}
				else {
					this->Trace("Warning: Can't read Status (possible conflict with other software)");
					this->ReadErrorCount++;

					// after so many consecutive read errors, try to switch back to bios mode
					if (this->ReadErrorCount>this->MaxReadErrors) {
						this->ModeToDialog(1);
						ok= this->SetFan("Max. Errors", 0x80);
						if (ok) {
							::SendMessage(this->hwndDialog, WM_CLOSE, 0, 0);
						}
					}
				}
				break;


		case WM__TASKBAR:

				switch (mp2) {
				    case WM_LBUTTONDOWN:
								break;


				    case WM_LBUTTONUP:
								{
									BOOL 
									  isshift= ::GetAsyncKeyState(VK_SHIFT) & 0x8000,
									  isctrl= ::GetAsyncKeyState(VK_CONTROL) & 0x8000;

									int action= -1;

									// some fancy key dependent stuff could be done here.

								}
								break;


				    case WM_LBUTTONDBLCLK:
								::ShowWindow(this->hwndDialog, TRUE);
								::SetForegroundWindow(this->hwndDialog);
				                break;


				    case WM_RBUTTONDOWN:
								{
									MENU m(5000);
									int mode= this->CurrentModeFromDialog();
									if (mode==1) 
										m.CheckMenuItem(5001);
									else
									if (mode==2)
										m.CheckMenuItem(5002);

									m.Popup(this->hwndDialog);  
								}
								break;
				}
				rc= TRUE;
				break;


		default:
				break;

	}

	return rc;
}



//-------------------------------------------------------------------------
//  reading the EC status may take a while, hence do it in a thread
//-------------------------------------------------------------------------
int 
FANCONTROL::WorkThread()
{
	int ok= this->ReadEcStatus(&this->State);

	::PostMessage(this->hwndDialog, WM__NEWDATA, ok, 0);

	return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -