Merge from dev-FireflyShell branch

This commit is contained in:
Ron Pedde 2006-05-29 09:14:04 +00:00
parent 0a14704fd9
commit 7f08580a24
37 changed files with 3698 additions and 0 deletions

View File

@ -11,6 +11,9 @@ void plugin_handler(int, int, void *, int);
#define PIPE_BUFFER_SIZE 4096
#define USE_UDP 0
#define USE_MAILSLOT 1
/* Globals */
PLUGIN_EVENT_FN _pefn = { plugin_handler };
PLUGIN_INPUT_FN *_ppi;
@ -40,6 +43,7 @@ PLUGIN_INFO *plugin_info(PLUGIN_INPUT_FN *ppi) {
return &_pi;
}
#if USE_UDP
/** NO LOG IN HERE! We'll go into an endless loop. :) */
void plugin_handler(int event_id, int intval, void *vp, int len) {
int total_len = 3 * sizeof(int) + len + 1;
@ -76,3 +80,44 @@ void plugin_handler(int event_id, int intval, void *vp, int len) {
free(pmsg);
return;
}
#endif /* USE_UDP */
#if USE_MAILSLOT
#define MAILSLOT_NAME "\\\\.\\mailslot\\FireflyMediaServer--67A72768-4154-417e-BFA0-FA9B50C342DE"
/** NO LOG IN HERE! We'll go into an endless loop. :) */
void plugin_handler(int event_id, int intval, void *vp, int len) {
HANDLE h = CreateFile(MAILSLOT_NAME, GENERIC_WRITE,
FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if (h != INVALID_HANDLE_VALUE)
{
DWORD bytes_written;
const int packet_size = 12 + len;
unsigned char *buffer = (unsigned char *)malloc(packet_size);
if(!buffer)
return;
memset(buffer, 0, packet_size);
buffer[0] = packet_size & 0xff;
buffer[1] = (packet_size >> 8) & 0xff;
buffer[2] = (packet_size >> 16) & 0xff;
buffer[3] = (packet_size >> 24) & 0xff;
buffer[4] = event_id & 0xff;
buffer[5] = (event_id >> 8) & 0xff;
buffer[6] = (event_id >> 16) & 0xff;
buffer[7] = (event_id >> 24) & 0xff;
buffer[8] = intval & 0xff;
buffer[9] = (intval >> 8) & 0xff;
buffer[10] = (intval >> 16) & 0xff;
buffer[11] = (intval >> 24) & 0xff;
memcpy(buffer + 12, vp, len);
/* If this fails then there's nothing we can do about it anyway. */
WriteFile(h, buffer, packet_size, &bytes_written, NULL);
CloseHandle(h);
}
}
#endif /* USE_MAILSLOT */

View File

@ -0,0 +1,133 @@
/*
*(C) 2006 Roku LLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the GNU General
* Public License for more details.
*
* Please read README.txt in the same directory as this source file for
* further license information.
*/
#include "stdafx.h"
#include "AboutPage.h"
#include "FireflyShell.h"
#include "VersionInfo.h"
#include "DosPath.h"
LRESULT CAboutPage::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
// Do this before we try and use the controls.
DoDataExchange(false);
FillVersionList();
return 0;
}
void CAboutPage::FillVersionList()
{
m_versions.Empty();
// Initialise the list control
CString str;
str.LoadString(IDS_VERSIONINFO_DESCRIPTION);
m_list.AddColumn(str, SUBITEM_DESCRIPTION);
str.LoadString(IDS_VERSIONINFO_VERSION);
m_list.AddColumn(str, SUBITEM_VERSION, 1);
str.LoadString(IDS_VERSIONINFO_PATH);
m_list.AddColumn(str, SUBITEM_PATH, 2);
m_list.SetColumnWidth(SUBITEM_DESCRIPTION, 40);
m_list.SetColumnWidth(SUBITEM_VERSION, 40);
CDosPath server_path(GetApplication()->GetServiceBinaryPath());
AddEntry(server_path.GetPath(), _T("Firefly server"));
AddEntry(CDosPath::AppPath().GetPath(), _T("FireflyShell"));
CString plugins_path = server_path.GetPathOnly() + _T("plugins\\");
CString plugins_pattern = plugins_path + _T("*.dll");
WIN32_FIND_DATA find;
HANDLE hFind = FindFirstFile(plugins_pattern, &find);
if (hFind != INVALID_HANDLE_VALUE)
{
do
{
AddEntry(plugins_path + find.cFileName, CString(find.cFileName) + _T(" plugin"));
} while (FindNextFile(hFind, &find));
FindClose(hFind);
}
for(int i = 0; i < SUBITEM_COUNT; ++i)
{
m_list.SetColumnWidth(i, m_column_widths[i] + 16);
}
}
void CAboutPage::AddEntry(const TCHAR *path, const TCHAR *fallback_description)
{
VersionInfo vi;
CString description = fallback_description;
CString version;
if (vi.Open(path))
{
description = vi.GetFileDescription();
version = vi.GetFileVersion();
}
int item = m_list.GetItemCount();
AddItem(item, SUBITEM_DESCRIPTION, description);
AddItem(item, SUBITEM_VERSION, version);
AddItem(item, SUBITEM_PATH, path);
CString line;
line.Format(_T("%s\t%s\t%s\r\n"), description, version, path);
m_versions += line;
}
void CAboutPage::AddItem(int item, int subitem, const TCHAR *text)
{
m_list.AddItem(item, subitem, text);
const int width = m_list.GetStringWidth(text);
if (width > m_column_widths[subitem])
m_column_widths[subitem] = width;
}
LRESULT CAboutPage::OnWebsite(WORD, WORD, HWND, BOOL &)
{
const TCHAR *url = _T("http://www.fireflymediaserver.org/");
::ShellExecute(m_hWnd, _T("open"), url, NULL, NULL, SW_SHOWNORMAL);
return 0;
}
LRESULT CAboutPage::OnCopy(WORD, WORD, HWND, BOOL &)
{
if (OpenClipboard())
{
const size_t len = m_versions.GetLength() * sizeof(TCHAR);
HGLOBAL h = ::GlobalAlloc(GMEM_MOVEABLE, len);
if (h)
{
void *buffer = ::GlobalLock(h);
memcpy(buffer, static_cast<const TCHAR *>(m_versions), len);
::GlobalUnlock(h);
EmptyClipboard();
#if defined(UNICODE)
SetClipboardData(CF_UNICODETEXT, h);
#else
SetClipboardData(CF_TEXT, h);
#endif
}
CloseClipboard();
}
return 0;
}

View File

@ -0,0 +1,72 @@
/*
*(C) 2006 Roku LLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the GNU General
* Public License for more details.
*
* Please read README.txt in the same directory as this source file for
* further license information.
*/
#ifndef ABOUTPAGE_H
#define ABOUTPAGE_H 1
#include "resource.h"
class CAboutPage :
public CPropertyPageImpl<CAboutPage>,
public CWinDataExchange<CAboutPage>
{
typedef CPropertyPageImpl<CAboutPage> base;
CListViewCtrl m_list;
enum
{
SUBITEM_DESCRIPTION = 0,
SUBITEM_VERSION = 1,
SUBITEM_PATH = 2,
SUBITEM_COUNT = 3
};
int m_column_widths[SUBITEM_COUNT];
// String version of information ready to write to the clipboard
CString m_versions;
public:
CAboutPage()
{
::ZeroMemory(m_column_widths, sizeof(m_column_widths));
}
enum { IDD = IDD_PAGE_ABOUT };
private:
// Message Handlers
BEGIN_MSG_MAP(CAboutPage)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
COMMAND_ID_HANDLER(IDC_WEBSITE, OnWebsite)
COMMAND_ID_HANDLER(IDC_COPY, OnCopy)
CHAIN_MSG_MAP(base)
END_MSG_MAP()
BEGIN_DDX_MAP(CAboutPage)
DDX_CONTROL_HANDLE(IDC_VERSIONLIST, m_list)
END_DDX_MAP()
LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnWebsite(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
LRESULT OnCopy(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
void FillVersionList();
void AddEntry(const TCHAR *path, const TCHAR *fallback_description);
void AddItem(int item, int subitem, const TCHAR *text);
};
#endif // ABOUTPAGE_H

View File

@ -0,0 +1,167 @@
/*
*(C) 2006 Roku LLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the GNU General
* Public License for more details.
*
* Please read README.txt in the same directory as this source file for
* further license information.
*/
#include "stdafx.h"
#include "AdvancedPage.h"
#include "IniFile.h"
#include "FireflyShell.h"
LRESULT CAdvancedPage::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
IniFile ini(GetApplication()->GetConfigPath());
m_server_port = ini.GetInteger(_T("general"), _T("port"), 9999);
DoDataExchange(false);
m_port_spin.SetRange32(1, 65535);
switch (GetApplication()->IsAutoStartEnabled())
{
case 0:
m_autostart_check.SetCheck(BST_UNCHECKED);
break;
case 1:
m_autostart_check.SetCheck(BST_CHECKED);
break;
case 2:
// Be sneaky here. Make it capable of showing indeterminate but
// don't make it automatically change on click. We'll revert
// to a normal checkbox when the click happens.
m_autostart_check.SetButtonStyle(BS_3STATE);
m_autostart_check.SetCheck(BST_INDETERMINATE);
break;
}
UpdateControls();
GetApplication()->ServiceStatusSubscribe(this);
return 0;
}
void CAdvancedPage::OnDestroy()
{
GetApplication()->ServiceStatusUnsubscribe(this);
}
void CAdvancedPage::UpdateControls()
{
Service::Status status = GetApplication()->GetServiceStatus();
UpdateControls(status);
}
void CAdvancedPage::UpdateControls(Service::Status status)
{
UINT state_id;
if (status.IsPending())
{
state_id = IDS_SERVER_PENDING;
GetDlgItem(IDC_STARTSERVICE).ShowWindow(SW_HIDE);
GetDlgItem(IDC_STOPSERVICE).ShowWindow(SW_HIDE);
}
else if (status.IsRunning())
{
state_id = IDS_SERVER_RUNNING;
GetDlgItem(IDC_STARTSERVICE).ShowWindow(SW_HIDE);
GetDlgItem(IDC_STOPSERVICE).ShowWindow(SW_SHOW);
}
else
{
state_id = IDS_SERVER_STOPPED;
GetDlgItem(IDC_STARTSERVICE).ShowWindow(SW_SHOW);
GetDlgItem(IDC_STOPSERVICE).ShowWindow(SW_HIDE);
}
const bool can_configure = GetApplication()->CanConfigure();
GetDlgItem(IDC_SERVERPORT).EnableWindow(can_configure);
GetDlgItem(IDC_PORTSPIN).EnableWindow(can_configure);
// If we can't control the service then don't give the user
// the impression that we can.
const bool can_control = GetApplication()->CanControlService();
GetDlgItem(IDC_STARTSERVICE).EnableWindow(can_control);
GetDlgItem(IDC_STOPSERVICE).EnableWindow(can_control);
GetDlgItem(IDC_AUTOSTART).EnableWindow(can_control);
CString state;
state.LoadString(state_id);
if (!can_control)
{
CString s;
s.LoadString(IDS_NOT_ADMIN);
state += " ";
state += s;
}
GetDlgItem(IDC_SERVERSTATE).SetWindowText(state);
}
int CAdvancedPage::OnApply()
{
ATLTRACE("CAdvancedPage::OnApply\n");
if (!DoDataExchange(true))
return false;
IniFile ini(GetApplication()->GetConfigPath());
ini.SetInteger(_T("general"), _T("port"), m_server_port);
switch (m_autostart_check.GetCheck())
{
case BST_CHECKED:
GetApplication()->EnableAutoStart(m_hWnd, true);
break;
case BST_UNCHECKED:
GetApplication()->EnableAutoStart(m_hWnd, false);
break;
case BST_INDETERMINATE:
// Ignore
break;
}
// Incorrectly documented in WTL
return true;
}
LRESULT CAdvancedPage::OnStartService(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
GetApplication()->StartService(m_hWnd);
UpdateControls();
return 0;
}
LRESULT CAdvancedPage::OnStopService(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
GetApplication()->StopService(m_hWnd);
UpdateControls();
return 0;
}
LRESULT CAdvancedPage::OnWebAdmin(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
// Go to the config file because we might not have committed a change yet.
IniFile ini(GetApplication()->GetConfigPath());
unsigned int port = ini.GetInteger(_T("general"), _T("port"), 9999);
CString url;
url.Format(_T("http://localhost:%u/"), port);
::ShellExecute(m_hWnd, _T("open"), url, NULL, NULL, SW_SHOWNORMAL);
return 0;
}
void CAdvancedPage::OnServiceStatus(Service::Status old_status, Service::Status new_status)
{
UpdateControls(new_status);
}

View File

@ -0,0 +1,98 @@
/*
*(C) 2006 Roku LLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the GNU General
* Public License for more details.
*
* Please read README.txt in the same directory as this source file for
* further license information.
*/
#ifndef ADVANCEDPAGE_H
#define ADVANCEDPAGE_H 1
#include "resource.h"
#include "ServiceControl.h"
/// @todo Users shouldn't be able to paste non-numbers into the port number.
class CAdvancedPage :
public CPropertyPageImpl<CAdvancedPage>,
public CWinDataExchange<CAdvancedPage>,
public ServiceStatusObserver
{
public:
enum { IDD = IDD_PAGE_ADVANCED };
private:
typedef CPropertyPageImpl<CAdvancedPage> base;
enum ServiceState
{
Pending = 0,
Running = 1,
Stopped = 2
};
enum { TIMER_ID = 42 };
unsigned int m_server_port;
CUpDownCtrl m_port_spin;
CButton m_autostart_check;
void UpdateControls(Service::Status status);
void UpdateControls();
// ServiceStatusObserver
void OnServiceStatus(Service::Status old_status, Service::Status new_status);
BEGIN_MSG_MAP(CAdvancedPage)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
COMMAND_HANDLER_EX(IDC_SERVERPORT, EN_CHANGE, OnChange)
COMMAND_HANDLER_EX(IDC_AUTOSTART, BN_CLICKED, OnClickAutostart)
COMMAND_ID_HANDLER(IDC_STARTSERVICE, OnStartService)
COMMAND_ID_HANDLER(IDC_STOPSERVICE, OnStopService)
COMMAND_ID_HANDLER(IDC_WEBADMIN, OnWebAdmin)
MSG_WM_DESTROY(OnDestroy)
CHAIN_MSG_MAP(base)
END_MSG_MAP()
BEGIN_DDX_MAP(CAdvancedPage)
DDX_UINT(IDC_SERVERPORT, m_server_port);
DDX_CONTROL_HANDLE(IDC_PORTSPIN, m_port_spin);
DDX_CONTROL_HANDLE(IDC_AUTOSTART, m_autostart_check);
END_DDX_MAP()
// MessageHandlers;
LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnStartService(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
LRESULT OnStopService(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
LRESULT OnWebAdmin(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
void OnDestroy();
void OnTimer(UINT id, TIMERPROC proc);
int OnApply();
void OnChange(UINT uCode, int nCtrlID, HWND hwndCtrl)
{
// Lots of things could have changed.
SetModified();
}
void OnClickAutostart(UINT uCode, int nCtrlID, HWND hwndCtrl)
{
// When clicked revert to being a normal checkbox in case
// we were intermediate.
if (m_autostart_check.GetButtonStyle() != BS_AUTOCHECKBOX)
{
m_autostart_check.SetButtonStyle(BS_AUTOCHECKBOX);
m_autostart_check.SetCheck(TRUE);
}
OnChange(uCode, nCtrlID, hwndCtrl);
}
};
#endif // ADVANCEDPAGE_H

View File

@ -0,0 +1,90 @@
/*
*(C) 2006 Roku LLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the GNU General
* Public License for more details.
*
* Please read README.txt in the same directory as this source file for
* further license information.
*/
#include "stdafx.h"
#include "ConfigPage.h"
#include "FireflyShell.h"
#include "IniFile.h"
LRESULT CConfigPage::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
IniFile ini(GetApplication()->GetConfigPath());
m_server_name = ini.GetString(_T("general"), _T("servername"), _T("Firefly media server"));
m_media_path = ini.GetString(_T("general"), _T("mp3_dir"), _T("C:\\Music"));
m_password = ini.GetString(_T("general"), _T("password"), _T(""));
// Do this before we try and use the controls.
DoDataExchange(false);
const bool enable_password = !m_password.IsEmpty();
m_protect_checkbox.SetCheck(enable_password);
EnableControls();
return 0;
}
void CConfigPage::EnableControls()
{
const bool enable = GetApplication()->CanConfigure();
GetDlgItem(IDC_SERVERNAME).EnableWindow(enable);
GetDlgItem(IDC_PATH).EnableWindow(enable);
GetDlgItem(IDC_PROTECT).EnableWindow(enable);
GetDlgItem(IDC_BROWSE).EnableWindow(enable);
const bool enable_password = (m_protect_checkbox.GetCheck() != 0) && enable;
GetDlgItem(IDC_PASSWORD).EnableWindow(enable_password);
GetDlgItem(IDC_PASSWORD_PROMPT).EnableWindow(enable_password);
}
int CConfigPage::OnApply()
{
ATLTRACE("CConfigPage::OnApply\n");
if (!DoDataExchange(true))
return false;
IniFile ini(GetApplication()->GetConfigPath());
ini.SetString(_T("general"), _T("servername"), m_server_name);
ini.SetString(_T("general"), _T("mp3_dir"), m_media_path);
ini.SetString(_T("general"), _T("password"), m_password);
// Incorrectly documented in WTL
return true;
}
LRESULT CConfigPage::OnBrowse(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
CFolderDialog folder;
// Who cares if it fails.
DoDataExchange(true);
folder.SetInitialFolder(m_media_path);
if (folder.DoModal() == IDOK)
{
m_media_path = folder.GetFolderPath();
DoDataExchange(false);
}
return 0;
}
void CConfigPage::OnClickProtect(UINT uCode, int nCtrlID, HWND hwndCtrl)
{
EnableControls();
SetModified();
}

View File

@ -0,0 +1,70 @@
/*
*(C) 2006 Roku LLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the GNU General
* Public License for more details.
*
* Please read README.txt in the same directory as this source file for
* further license information.
*/
#ifndef CONFIGPAGE_H
#define CONFIGPAGE_H 1
#include "resource.h"
class CMainDlg;
class CConfigPage :
public CPropertyPageImpl<CConfigPage>,
public CWinDataExchange<CConfigPage>
{
typedef CPropertyPageImpl<CConfigPage> base;
public:
enum { IDD = IDD_PAGE_BASIC };
private:
CString m_media_path;
CString m_server_name;
CString m_password;
CButton m_protect_checkbox;
void EnableControls();
BEGIN_MSG_MAP(thisClass)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
COMMAND_ID_HANDLER(IDC_BROWSE, OnBrowse)
COMMAND_HANDLER_EX(IDC_PROTECT, BN_CLICKED, OnClickProtect)
COMMAND_HANDLER_EX(IDC_PASSWORD, EN_CHANGE, OnChange)
COMMAND_HANDLER_EX(IDC_SERVERNAME, EN_CHANGE, OnChange)
COMMAND_HANDLER_EX(IDC_PATH, EN_CHANGE, OnChange)
CHAIN_MSG_MAP(base)
END_MSG_MAP()
BEGIN_DDX_MAP(CConfigPage)
DDX_TEXT(IDC_PATH, m_media_path);
DDX_TEXT(IDC_SERVERNAME, m_server_name);
DDX_TEXT(IDC_PASSWORD, m_password);
DDX_CONTROL_HANDLE(IDC_PROTECT, m_protect_checkbox);
END_DDX_MAP()
// Message handlers
LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnBrowse(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
void OnClickProtect(UINT uCode, int nCtrlID, HWND hwndCtrl);
int OnApply();
void OnChange(UINT uCode, int nCtrlID, HWND hwndCtrl)
{
// Lots of things could have changed.
SetModified();
}
};
#endif // CONFIGPAGE_H

View File

@ -0,0 +1,173 @@
/*
* (C) 1997, 2006 Mike Crowe
*
* License: Do what you like with it except claim that you wrote it.
*/
#include "stdafx.h"
#include "dospath.h"
#include <stdlib.h>
#include <direct.h>
CDosPath::CDosPath(const TCHAR *pszPath, int nFlags)
{
SetPath(pszPath, nFlags);
}
CDosPath::CDosPath(const CDosPath &old)
{
m_drive = old.m_drive;
m_dir = old.m_dir;
m_file = old.m_file;
m_ext = old.m_ext;
}
CDosPath &CDosPath::operator=(const CDosPath &old)
{
m_drive = old.m_drive;
m_dir = old.m_dir;
m_file = old.m_file;
m_ext = old.m_ext;
return *this;
}
CDosPath::~CDosPath()
{
}
void CDosPath::SplitPath(const TCHAR *path)
{
#if USE_SECURE
_tsplitpath_s(path, m_drive.GetBufferSetLength(_MAX_DRIVE), _MAX_DRIVE,
m_dir.GetBufferSetLength(_MAX_DIR), _MAX_DIR,
m_file.GetBufferSetLength(_MAX_FNAME), _MAX_FNAME,
m_ext.GetBufferSetLength(_MAX_EXT), _MAX_EXT);
#else
_tsplitpath(path, m_drive.GetBufferSetLength(_MAX_DRIVE),
m_dir.GetBufferSetLength(_MAX_DIR),
m_file.GetBufferSetLength(_MAX_FNAME),
m_ext.GetBufferSetLength(_MAX_EXT));
#endif
m_ext.ReleaseBuffer();
m_file.ReleaseBuffer();
m_dir.ReleaseBuffer();
m_drive.ReleaseBuffer();
}
void CDosPath::SetPath(const TCHAR *pszPath, int nFlags)
{
if (nFlags & PATH_ONLY)
{
CString temp(pszPath);
temp += '\\';
SplitPath(temp);
}
else
SplitPath(pszPath);
}
CDosPath &CDosPath::operator|=(CDosPath &fullpath)
{
if (m_drive.IsEmpty())
{
// TRACE1("Inserting drive %s\n", fullpath.m_szDrive);
m_drive = fullpath.m_drive;
}
if (m_dir.IsEmpty())
{
// TRACE1("Inserting directory %s\n", fullpath.m_szDir);
m_dir = fullpath.m_dir;
}
if (m_file.IsEmpty())
{
// TRACE1("Inserting file %s\n", fullpath.m_szFile);
m_file = fullpath.m_file;
}
if (m_ext.IsEmpty())
{
// TRACE1("Inserting extension %s\n", fullpath.m_szExt);
m_ext = fullpath.m_ext;
}
return *this;
}
CDosPath CDosPath::operator|(CDosPath &fullpath)
{
CDosPath temp(GetPath());
temp |= fullpath;
return temp;
}
CString CDosPath::GetPath() const
{
CString temp;
#if USE_SECURE
_tmakepath_s(temp.GetBufferSetLength(_MAX_PATH), _MAX_PATH, m_drive, m_dir, m_file, m_ext);
#else
_tmakepath(temp.GetBufferSetLength(_MAX_PATH), m_drive, m_dir, m_file, m_ext);
#endif
temp.ReleaseBuffer();
return temp;
}
CString CDosPath::GetPathOnly() const
{
CString temp;
#if USE_SECURE
_tmakepath_s(temp.GetBufferSetLength(_MAX_PATH), _MAX_PATH, m_drive, m_dir, NULL, NULL);
#else
_tmakepath(temp.GetBufferSetLength(_MAX_PATH), m_drive, m_dir, NULL, NULL);
#endif
temp.ReleaseBuffer();
return temp;
}
CDosPath CDosPath::CurrentPath()
{
TCHAR szBuffer[_MAX_PATH];
_tgetcwd(szBuffer, _MAX_PATH);
return CDosPath(szBuffer, PATH_ONLY);
}
CDosPath CDosPath::AppPath()
{
TCHAR szBuffer[_MAX_PATH];
#ifdef _MFC
GetModuleFileName(AfxGetApp()->m_hInstance, szBuffer, _MAX_PATH);
#else
GetModuleFileName(GetModuleHandle(NULL), szBuffer, _MAX_PATH);
#endif
return CDosPath(szBuffer);
}
CDosPath CDosPath::WindowsPath()
{
TCHAR szBuffer[_MAX_PATH];
GetWindowsDirectory(szBuffer, _MAX_PATH);
return CDosPath(szBuffer, PATH_ONLY);
}
#ifdef MAKE_EXE
#include <stdio.h>
void main(int ac, char *av[])
{
if (ac != 3)
{
printf("Usage: dospath incomplete complete\n");
return;
}
CDosPath a = av[1];
CDosPath b = av[2];
a |= b;
printf("%s |= %s = %s\n", av[1], av[2], (const char *) a.GetPath());
printf("\n\n\n\n");
a = CDosPath::CurrentPath();
printf("Current = %s\n", (const char *)a.GetPath());
a = CDosPath::AppPath();
printf("App = %s\n", (const char *)a.GetPath());
a = CDosPath::TempPath();
printf("Temp = %s\n", (const char *)a.GetPath());
}
#endif

View File

@ -0,0 +1,51 @@
/*
* (C) 1997, 2006 Mike Crowe
*
* License: Do what you like with it except claim that you wrote it.
*/
#ifndef DOSPATH_H
#define DOSPATH_H
class CDosPath
{
CString m_drive;
CString m_dir;
CString m_file;
CString m_ext;
void SplitPath(const TCHAR *buffer);
public:
enum { PATH_ONLY = 1 };
CDosPath(const TCHAR *pszPath, int nFlags = 0);
CDosPath(const CDosPath &old);
~CDosPath();
CDosPath &operator|=(CDosPath &fullpath);
CDosPath operator|(CDosPath &fullpath);
CDosPath &operator=(const CDosPath &old);
CString GetPath() const;
CString GetPathOnly() const;
void SetPath(const TCHAR *pszBuffer, int nFlags = 0);
static CDosPath CurrentPath();
static CDosPath AppPath();
static CDosPath TempPath();
#ifdef _WINDOWS
static CDosPath WindowsPath();
#endif
CString GetFile()
{
return m_file;
}
CString GetExt()
{
return m_ext;
}
};
#endif // DOSPATH_H

View File

@ -0,0 +1,373 @@
/*
*(C) 2006 Roku LLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the GNU General
* Public License for more details.
*
* Please read README.txt in the same directory as this source file for
* further license information.
*/
#include "stdafx.h"
#include "resource.h"
#include "FireflyShell.h"
#include "DosPath.h"
#include "ServiceControl.h"
#include "MainDlg.h"
#include "ServerEvents.h"
#include "IniFile.h"
CAppModule _Module;
#define RUN_KEY _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run")
#define RUN_VALUE _T("FireflyShell")
Application::Application()
: m_dlg(NULL), m_server_events(&m_icon)
{
CDosPath path = CDosPath::AppPath();
CDosPath filename(_T("mt-daapd.conf"));
filename |= path;
m_config_path = filename.GetPath();
ATLTRACE("Config path: %s\n", (const TCHAR *)m_config_path);
// We don't care if this fails. We can deal with that later.
m_service.Open(_T("Firefly Media Server"));
CheckCanConfigure();
m_unique_name = GenerateUniqueName();
m_registered_activation_message = ::RegisterWindowMessage(m_unique_name);
}
Application::~Application()
{
ATLASSERT(m_dlg == NULL);
}
void Application::CheckCanConfigure()
{
IniFile ini(m_config_path);
m_configurable = ini.IsWritable();
}
int Application::Run(LPCTSTR lpstrCmdLine, int nCmdShow)
{
if (ActivatePreviousInstance(lpstrCmdLine, nCmdShow))
{
ATLTRACE(_T("Already running\n"));
return 0;
}
CMessageLoop theLoop;
_Module.AddMessageLoop(&theLoop);
if (!m_icon.Create())
{
ATLTRACE(_T("Icon creation failed!\n"));
return 0;
}
EnableServerEvents(true);
if (ShowDialogAtStart(lpstrCmdLine, nCmdShow))
Configure();
int nRet = theLoop.Run();
EnableServerEvents(false);
m_icon.Destroy();
_Module.RemoveMessageLoop();
return nRet;
}
void Application::Exit()
{
if (m_dlg)
{
m_dlg->DestroyWindow();
delete m_dlg;
m_dlg = NULL;
}
::PostQuitMessage(0);
}
void Application::Configure()
{
if (m_dlg)
{
m_dlg->ShowWindow(SW_RESTORE);
SetForegroundWindow(m_dlg->m_hWnd);
}
else
{
CheckCanConfigure();
// Other people may need to talk to the dialog while it exists.
CMainDlg dlg;
m_dlg = &dlg;
dlg.DoModal();
m_dlg = NULL;
}
}
void Application::StartService(HWND hwndParent)
{
CWaitCursor wc;
ATLASSERT(m_service.CanControl());
if (!m_service.CanControl())
return;
if (!m_service.StartAndWait())
{
MessageBox(hwndParent, IDS_SERVERSTARTFAIL, MB_OK);
}
}
void Application::StopService(HWND hwndParent)
{
CWaitCursor wc;
ATLASSERT(m_service.CanControl());
if (!m_service.CanControl())
return;
if (!m_service.StopAndWait())
{
MessageBox(hwndParent, IDS_SERVERSTOPFAIL, MB_OK);
}
}
void Application::RestartService(HWND hwndParent)
{
CWaitCursor wc;
StopService(hwndParent);
StartService(hwndParent);
}
bool Application::ShowDialogAtStart(LPCTSTR cmdline, int nCmdShow)
{
if ((cmdline[0] == '-') && (cmdline[1] == 'q'))
return false;
switch (nCmdShow)
{
case SW_RESTORE:
case SW_SHOW:
case SW_SHOWMAXIMIZED:
case SW_SHOWNORMAL:
case SW_SHOWDEFAULT:
case SW_MAX:
return true;
default:
return false;
}
}
BOOL CALLBACK Application::StaticWindowSearcher(HWND hwnd, LPARAM lparam)
{
DWORD result;
LRESULT ok = ::SendMessageTimeout(hwnd,
lparam,
0, 0,
SMTO_BLOCK |
SMTO_ABORTIFHUNG,
200,
&result);
if (ok == 0)
return TRUE; // ignore this and continue
// If we get the magic response then we must have found our Window
// so we can give up.
if (result == lparam)
return FALSE;
else
return TRUE;
}
bool Application::ActivatePreviousInstance(LPCTSTR lpstrCmdLine, int nCmdShow)
{
HANDLE h = ::CreateMutex(NULL, TRUE, m_unique_name);
const bool running = (GetLastError() == ERROR_ALREADY_EXISTS);
if (h != NULL)
{
::ReleaseMutex(h);
}
// It seems that getting the other window to activate itself does
// actually work even though Windows anti-focus-stealing stuff
// could try and stop it.
if (running && ShowDialogAtStart(lpstrCmdLine, nCmdShow))
{
EnumWindows(StaticWindowSearcher, m_registered_activation_message);
return true;
}
return running;
}
CString Application::GenerateUniqueName()
{
// We need to allow one instance to run per desktop. See
// http://www.codeproject.com/cpp/avoidmultinstance.asp
// First start with some application unique
CString s(_T("Firefly-67A72768-4154-417e-BFA0-FA9B50C342DE"));
// Now append something desktop unique
DWORD len;
HDESK desktop = GetThreadDesktop(GetCurrentThreadId());
BOOL result = GetUserObjectInformation(desktop, UOI_NAME, NULL, 0, &len);
DWORD err = ::GetLastError();
if(!result && err == ERROR_INSUFFICIENT_BUFFER)
{ /* NT/2000/XP */
LPBYTE data = new BYTE[len];
result = GetUserObjectInformation(desktop, UOI_NAME, data, len, &len);
s += _T("-");
s += (LPCTSTR)data;
delete [ ] data;
} /* NT/2000/XP */
else
{ /* Win9x */
s += _T("-Win9x");
} /* Win9x */
return s;
}
void Application::EnableServerEvents(bool b)
{
if (b)
m_server_events.Start();
else
m_server_events.Stop();
}
CString Application::MakeRunKeyValue()
{
CString required_path("\"");
required_path += CDosPath::AppPath().GetPath();
required_path += "\" -q";
return required_path;
}
void Application::EnableAutoStart(HWND hwnd, bool enable)
{
// First let's control the service.
int required_startup = enable ? SERVICE_AUTO_START : SERVICE_DISABLED;
if (m_service.GetStartup() != required_startup)
{
if (!m_service.ConfigureStartup(required_startup))
{
MessageBox(hwnd, IDS_FAILED_CONFIGURE_SERVICE, MB_OK);
}
}
// Now let's set up the Run key.
HKEY hkey;
LONG result = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, RUN_KEY, 0, KEY_SET_VALUE | STANDARD_RIGHTS_WRITE, &hkey);
if (result == ERROR_SUCCESS)
{
if (enable)
{
// We need to quote it because the path may contain spaces.
CString str = MakeRunKeyValue();
result = RegSetValueEx(hkey, RUN_VALUE, 0UL, REG_SZ, reinterpret_cast<LPCBYTE>(static_cast<LPCTSTR>(str)), (str.GetLength() + 1) * sizeof(TCHAR));
}
else
{
result = RegDeleteValue(hkey, RUN_VALUE);
if (result == ERROR_FILE_NOT_FOUND)
result = 0;
}
if (result != ERROR_SUCCESS)
{
ATLTRACE("Error:%u\n", result);
MessageBox(hwnd, IDS_FAILED_CONFIGURE_STARTUP, MB_OK);
}
}
}
int Application::IsAutoStartEnabled() const
{
// Look at the service
int service_result = 2;
switch (m_service.GetStartup())
{
case SERVICE_AUTO_START:
service_result = true;
break;
case SERVICE_DISABLED:
service_result = false;
break;
}
// Look at the Run key
int run_result = 2;
HKEY hkey;
if (::RegOpenKeyEx(HKEY_LOCAL_MACHINE, RUN_KEY, 0, KEY_QUERY_VALUE | STANDARD_RIGHTS_READ, &hkey) == ERROR_SUCCESS)
{
DWORD dwType, cbData;
TCHAR buffer[_MAX_PATH + 1];
cbData = (_MAX_PATH + 1) * sizeof(TCHAR);
if (::RegQueryValueEx(hkey, RUN_VALUE, NULL, &dwType, reinterpret_cast<LPBYTE>(buffer), &cbData) == ERROR_SUCCESS)
{
CString path(buffer, cbData - sizeof(TCHAR));
ATLTRACE("Registry run key path: %s\n", (const TCHAR *)path);
if (path == MakeRunKeyValue())
run_result = true;
else
{
// It's there - but it isn't us that it will start.
run_result = 2;
}
}
else
{
// The key doesn't exist.
run_result = false;
}
}
else
{
run_result = false;
}
// If the answers agree then return them. Otherwise we're indeterminate.
if (run_result == service_result)
return run_result;
else
return 2;
}
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)
{
// this resolves ATL window thunking problem when Microsoft Layer for Unicode (MSLU) is used
::DefWindowProc(NULL, 0, 0, 0L);
AtlInitCommonControls(ICC_BAR_CLASSES); // add flags to support other controls
HRESULT hRes = _Module.Init(NULL, hInstance);
ATLASSERT(SUCCEEDED(hRes));
int nRet;
{
// Application object is destroyed prior to undoing everything above.
Application app;
nRet = app.Run(lpstrCmdLine, nCmdShow);
}
_Module.Term();
return nRet;
}

View File

@ -0,0 +1,154 @@
/*
*(C) 2006 Roku LLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the GNU General
* Public License for more details.
*
* Please read README.txt in the same directory as this source file for
* further license information.
*/
#ifndef FIREFLYSHELL_H
#define FIREFLYSHELL_H 1
#include "singleton.h"
#include "NotifyIcon.h"
#include "ServiceControl.h"
#include <vector>
#include <algorithm>
#include "ServerEvents.h"
class CMainDlg;
/// The main application. Not a window.
class Application : public Singleton<Application>
{
CNotifyIcon m_icon;
CMainDlg *m_dlg;
CString m_config_path;
Service m_service;
ServiceStatusMonitor m_service_monitor;
ServerEvents m_server_events;
CString m_unique_name;
UINT m_registered_activation_message;
bool m_configurable;
/// Returns true if a previous instance was found. Only
/// actually activates a previous instance if nCmdShow
/// indicates so.
bool ActivatePreviousInstance(LPCTSTR cmdline, int nCmdShow);
/// Helper for ActivatePreviousInstance.
static BOOL CALLBACK Application::StaticWindowSearcher(HWND hwnd, LPARAM lparam);
/// Generate a unique name that can be used to detect multiple instances.
static CString GenerateUniqueName();
// Depending on how the application was launched we display the dialog or not.
static bool ShowDialogAtStart(LPCTSTR cmdline, int nCmdShow);
static CString MakeRunKeyValue();
public:
Application();
~Application();
/// Gets the application going
int Run(LPCTSTR lpstrCmdLine, int nCmdShow);
/// mt-daapd.conf path
CString GetConfigPath()
{
return m_config_path;
}
/// Registered message used to activate other instances
UINT GetRegisteredActivationMessage() const
{
return m_registered_activation_message;
}
// User actions
void Configure();
void Exit();
// Service control
void StartService(HWND hwndParent);
void StopService(HWND hwndParent);
void RestartService(HWND hwndParent);
Service::Status GetServiceStatus()
{
Service::Status status;
if (m_service.IsOpen())
{
m_service.GetStatus(&status);
}
return status;
}
// Expensive - only do it just before displaying the dialog box.
void CheckCanConfigure();
// Cheap.
bool CanConfigure() const
{
// We need to both rewrite the config file and
// control the service if we're going to be
// useful.
return m_configurable && m_service.CanControl();
}
bool CanControlService() const
{
return m_service.CanControl();
}
void CheckServiceStatus()
{
m_service_monitor.Poll(&m_service);
}
void ServiceStatusSubscribe(ServiceStatusObserver *obs)
{
m_service_monitor.Subscribe(obs);
}
void ServiceStatusUnsubscribe(ServiceStatusObserver *obs)
{
m_service_monitor.Unsubscribe(obs);
}
CString GetServiceBinaryPath() const
{
return m_service.GetBinaryPath();
}
/// Used to disable listening for events from the server when this user is
/// not active.
void EnableServerEvents(bool);
/// Enable/disable automatic startup of service and FireflyShell.
void EnableAutoStart(HWND, bool);
/// Reports 0 for disabled, 1 for enabled, 2 for indeterminate
int IsAutoStartEnabled() const;
int MessageBox(HWND hwnd, UINT id, UINT flags)
{
CString title, text;
ATLVERIFY(title.LoadString(IDR_MAINFRAME));
ATLVERIFY(text.LoadString(id));
return ::MessageBox(hwnd, text, title, flags);
}
};
inline Application *GetApplication() { return Application::GetInstance(); }
#endif // FIREFLYSHELL_H

View File

@ -0,0 +1,301 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "atlres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""atlres.h""\r\n"
END
3 TEXTINCLUDE
BEGIN
"#ifndef APSTUDIO_INVOKED\r\n"
"#include ""version.rc""\r\n"
"#endif // !APSTUDIO_INVOKED\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDR_MAINFRAME ICON "res\\FireflyShell.ico"
IDI_SHELL_RUNNING ICON "res\\shellrunning.ico"
IDI_SHELL_STOPPED ICON "res\\shellstopped.ico"
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_PAGE_ABOUT DIALOGEX 0, 0, 221, 223
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "About"
FONT 8, "MS Sans Serif", 0, 0, 0x0
BEGIN
ICON IDR_MAINFRAME,IDC_STATIC,93,18,20,20
CTEXT "Firefly Media Server",IDC_STATIC,7,41,207,11
LTEXT "For help, tips and troubleshooting advice visit the Firefly Media Server website.",IDC_STATIC,12,79,119,23
PUSHBUTTON "Visit &Website...",IDC_WEBSITE,139,82,70,14
GROUPBOX "Version information",IDC_STATIC,7,114,207,102
CONTROL "",IDC_VERSIONLIST,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,12,126,197,63
PUSHBUTTON "&Copy to Clipboard",IDC_COPY,139,194,70,14
END
IDD_PAGE_BASIC DIALOGEX 0, 0, 222, 230
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Library"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Library &Name",IDC_STATIC,7,24,72,8
EDITTEXT IDC_SERVERNAME,61,21,152,14,ES_AUTOHSCROLL
LTEXT "Media &Location",IDC_STATIC,7,60,48,8
EDITTEXT IDC_PATH,61,57,152,14,ES_AUTOHSCROLL
PUSHBUTTON "&Browse...",IDC_BROWSE,163,76,50,14
GROUPBOX "Security",IDC_STATIC,7,113,206,113
CONTROL "&Protect Firefly media library with a password",IDC_PROTECT,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,18,128,187,10
LTEXT "Password:",IDC_PASSWORD_PROMPT,18,157,34,8
EDITTEXT IDC_PASSWORD,61,156,148,14,ES_PASSWORD | ES_AUTOHSCROLL
LTEXT "Explanatory text about passwords go here. Why you'd want a password and what are the implications 'n' stuff.",IDC_STATIC,18,180,188,39,SS_NOPREFIX
END
IDD_PAGE_LOG DIALOGEX 0, 0, 222, 220
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Log"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
EDITTEXT IDC_LOG,4,4,214,212,ES_AUTOHSCROLL | ES_READONLY
END
IDD_PAGE_ADVANCED DIALOGEX 0, 0, 222, 220
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Server"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
GROUPBOX "Server Status",IDC_STATIC,6,7,210,82
LTEXT "Current state of the server goes here",IDC_SERVERSTATE,12,24,200,25
PUSHBUTTON "&Stop Server",IDC_STOPSERVICE,160,49,50,14
PUSHBUTTON "&Start Server",IDC_STARTSERVICE,160,49,50,14
CONTROL "&Start Firefly when Windows starts",IDC_AUTOSTART,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,73,196,10
GROUPBOX "Advanced",IDC_STATIC,6,93,210,61
LTEXT "Server port number",IDC_STATIC,12,108,122,11
EDITTEXT IDC_SERVERPORT,155,106,42,14,ES_AUTOHSCROLL | ES_NUMBER
CONTROL "",IDC_PORTSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK,197,106,11,14
LTEXT "You may need to change this if another program is already using this port.",IDC_STATIC,12,129,196,23
GROUPBOX "Web administration",IDC_STATIC,6,159,210,54
LTEXT "Firefly Media Server also provides a web administration interface.",IDC_STATIC,12,177,140,20
PUSHBUTTON "&Open",IDC_WEBADMIN,160,194,50,14
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_PAGE_ABOUT, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 214
VERTGUIDE, 12
VERTGUIDE, 131
VERTGUIDE, 139
VERTGUIDE, 209
TOPMARGIN, 7
BOTTOMMARGIN, 216
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Accelerator
//
IDR_MAINFRAME ACCELERATORS
BEGIN
"N", ID_FILE_NEW, VIRTKEY, CONTROL
"O", ID_FILE_OPEN, VIRTKEY, CONTROL
"S", ID_FILE_SAVE, VIRTKEY, CONTROL
"P", ID_FILE_PRINT, VIRTKEY, CONTROL
"Z", ID_EDIT_UNDO, VIRTKEY, CONTROL
"X", ID_EDIT_CUT, VIRTKEY, CONTROL
"C", ID_EDIT_COPY, VIRTKEY, CONTROL
"V", ID_EDIT_PASTE, VIRTKEY, CONTROL
VK_BACK, ID_EDIT_UNDO, VIRTKEY, ALT
VK_DELETE, ID_EDIT_CUT, VIRTKEY, SHIFT
VK_INSERT, ID_EDIT_COPY, VIRTKEY, CONTROL
VK_INSERT, ID_EDIT_PASTE, VIRTKEY, SHIFT
VK_F6, ID_NEXT_PANE, VIRTKEY
VK_F6, ID_PREV_PANE, VIRTKEY, SHIFT
END
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
IDM_CONTEXT MENU
BEGIN
POPUP ""
BEGIN
MENUITEM "&Configure Firefly Media Server...", ID_CONFIGURE
MENUITEM "E&xit", ID_EXIT
END
END
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE
BEGIN
IDR_MAINFRAME "Firefly Media Server"
IDS_SERVER_RUNNING "The Firefly media server is currently running."
IDS_SERVER_STOPPED "The Firefly media server is not currently running."
IDS_SERVERSTARTFAIL "Failed to start Firefly Media Server."
IDS_SERVERSTOPFAIL "Failed to stop Firefly Media Server."
IDS_SERVER_PENDING "The Firefly media server is currently busy."
IDS_SERVER_START "&Start"
IDS_SERVER_STOP "&Stop"
IDS_SCAN_START "Scanning for media is in progress\n\nThis may take some time."
IDS_SCAN_STOP "Scanning for media is complete."
IDS_NOT_ADMIN "You must be logged in as a local administrator to start and stop the server."
IDS_QUERYSERVERRESTART "Changing the configuration will require a restart of the Firefly Media Server. Are you sure you want to do this?"
IDS_VERSIONINFO_DESCRIPTION "Description"
IDS_VERSIONINFO_VERSION "Version"
IDS_VERSIONINFO_PATH "Path"
IDS_FAILED_CONFIGURE_SERVICE "Failed to reconfigure service."
END
STRINGTABLE
BEGIN
ID_FILE_NEW "Create a new document\nNew"
ID_FILE_OPEN "Open an existing document\nOpen"
ID_FILE_CLOSE "Close the active document\nClose"
ID_FILE_SAVE "Save the active document\nSave"
ID_FILE_SAVE_AS "Save the active document with a new name\nSave As"
ID_FILE_PAGE_SETUP "Change the printing options\nPage Setup"
ID_FILE_PRINT_SETUP "Change the printer and printing options\nPrint Setup"
ID_FILE_PRINT "Print the active document\nPrint"
ID_FILE_PRINT_PREVIEW "Display full pages\nPrint Preview"
END
STRINGTABLE
BEGIN
ID_APP_ABOUT "Display program information, version number and copyright\nAbout"
ID_APP_EXIT "Quit the application; prompts to save documents\nExit"
END
STRINGTABLE
BEGIN
ID_NEXT_PANE "Switch to the next window pane\nNext Pane"
ID_PREV_PANE "Switch back to the previous window pane\nPrevious Pane"
END
STRINGTABLE
BEGIN
ID_WINDOW_NEW "Open another window for the active document\nNew Window"
ID_WINDOW_ARRANGE "Arrange icons at the bottom of the window\nArrange Icons"
ID_WINDOW_CASCADE "Arrange windows so they overlap\nCascade Windows"
ID_WINDOW_TILE_HORZ "Arrange windows as non-overlapping tiles\nTile Windows"
ID_WINDOW_TILE_VERT "Arrange windows as non-overlapping tiles\nTile Windows"
ID_WINDOW_SPLIT "Split the active window into panes\nSplit"
END
STRINGTABLE
BEGIN
ID_EDIT_CLEAR "Erase the selection\nErase"
ID_EDIT_CLEAR_ALL "Erase everything\nErase All"
ID_EDIT_COPY "Copy the selection and put it on the Clipboard\nCopy"
ID_EDIT_CUT "Cut the selection and put it on the Clipboard\nCut"
ID_EDIT_FIND "Find the specified text\nFind"
ID_EDIT_PASTE "Insert Clipboard contents\nPaste"
ID_EDIT_REPEAT "Repeat the last action\nRepeat"
ID_EDIT_REPLACE "Replace specific text with different text\nReplace"
ID_EDIT_SELECT_ALL "Select the entire document\nSelect All"
ID_EDIT_UNDO "Undo the last action\nUndo"
ID_EDIT_REDO "Redo the previously undone action\nRedo"
END
STRINGTABLE
BEGIN
ATL_IDS_SCSIZE "Change the window size"
ATL_IDS_SCMOVE "Change the window position"
ATL_IDS_SCMINIMIZE "Reduce the window to an icon"
ATL_IDS_SCMAXIMIZE "Enlarge the window to full size"
ATL_IDS_SCNEXTWINDOW "Switch to the next document window"
ATL_IDS_SCPREVWINDOW "Switch to the previous document window"
ATL_IDS_SCCLOSE "Close the active window and prompts to save the documents"
END
STRINGTABLE
BEGIN
ATL_IDS_SCRESTORE "Restore the window to normal size"
ATL_IDS_SCTASKLIST "Activate Task List"
ATL_IDS_MDICHILD "Activate this window"
END
STRINGTABLE
BEGIN
ATL_IDS_IDLEMESSAGE "Ready"
END
STRINGTABLE
BEGIN
ATL_IDS_MRU_FILE "Open this document"
END
STRINGTABLE
BEGIN
IDS_FAILED_CONFIGURE_STARTUP "Failed to reconfigure startup application."
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,370 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="FireflyShell"
ProjectGUID="{FC91423E-33F6-4037-95AC-A8BAD7DF599F}"
RootNamespace="FireflyShell"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="../Debug"
IntermediateDirectory="Debug"
ConfigurationType="1"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
CommandLine="..\versionize.bat"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="_DEBUG"
MkTypLibCompatible="false"
TargetEnvironment="1"
GenerateStublessProxies="true"
TypeLibraryName="$(IntDir)/FireflyShell.tlb"
HeaderFileName="FireflyShell.h"
DLLDataFileName=""
InterfaceIdentifierFileName="FireflyShell_i.c"
ProxyFileName="FireflyShell_p.c"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_WINDOWS;STRICT;_DEBUG"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="2"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="1033"
AdditionalIncludeDirectories="$(IntDir)"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="version.lib"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="../Release"
IntermediateDirectory="Release"
ConfigurationType="1"
UseOfATL="1"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
CommandLine="..\versionize.bat"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="NDEBUG"
MkTypLibCompatible="false"
TargetEnvironment="1"
GenerateStublessProxies="true"
TypeLibraryName="$(IntDir)/FireflyShell.tlb"
HeaderFileName="FireflyShell.h"
DLLDataFileName=""
InterfaceIdentifierFileName="FireflyShell_i.c"
ProxyFileName="FireflyShell_p.c"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;_WINDOWS;STRICT;NDEBUG"
ExceptionHandling="1"
RuntimeLibrary="0"
UsePrecompiledHeader="2"
WarningLevel="3"
DebugInformationFormat="0"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="1033"
AdditionalIncludeDirectories="$(IntDir)"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="version.lib"
LinkIncremental="1"
SubSystem="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm"
>
<File
RelativePath=".\AboutPage.cpp"
>
</File>
<File
RelativePath=".\AdvancedPage.cpp"
>
</File>
<File
RelativePath=".\ConfigPage.cpp"
>
</File>
<File
RelativePath=".\DosPath.cpp"
>
</File>
<File
RelativePath=".\FireflyShell.cpp"
>
</File>
<File
RelativePath=".\LogPage.cpp"
>
</File>
<File
RelativePath=".\MainDlg.cpp"
>
</File>
<File
RelativePath=".\NotifyIcon.cpp"
>
</File>
<File
RelativePath=".\ServerEvents.cpp"
>
</File>
<File
RelativePath=".\ServiceControl.cpp"
>
</File>
<File
RelativePath=".\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\VersionInfo.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc"
>
<File
RelativePath=".\AboutPage.h"
>
</File>
<File
RelativePath=".\AdvancedPage.h"
>
</File>
<File
RelativePath=".\ConfigPage.h"
>
</File>
<File
RelativePath=".\DosPath.h"
>
</File>
<File
RelativePath=".\FireflyShell.h"
>
</File>
<File
RelativePath=".\IniFile.h"
>
</File>
<File
RelativePath=".\LogPage.h"
>
</File>
<File
RelativePath=".\MainDlg.h"
>
</File>
<File
RelativePath=".\NotifyIcon.h"
>
</File>
<File
RelativePath=".\resource.h"
>
</File>
<File
RelativePath=".\ServerEvents.h"
>
</File>
<File
RelativePath=".\ServiceControl.h"
>
</File>
<File
RelativePath=".\singleton.h"
>
</File>
<File
RelativePath=".\stdafx.h"
>
</File>
<File
RelativePath=".\VersionInfo.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest"
>
<File
RelativePath=".\res\FireflyShell.ico"
>
</File>
<File
RelativePath=".\FireflyShell.rc"
>
</File>
<File
RelativePath=".\res\shellrunning.ico"
>
</File>
<File
RelativePath=".\res\shellstopped.ico"
>
</File>
<File
RelativePath=".\version.rc"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCResourceCompilerTool"
/>
</FileConfiguration>
</File>
</Filter>
<File
RelativePath=".\README.txt"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -0,0 +1,68 @@
/*
*(C) 2006 Roku LLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the GNU General
* Public License for more details.
*
* Please read README.txt in the same directory as this source file for
* further license information.
*/
#ifndef INIFILE_H
#define INIFILE_H
#include "DosPath.h"
class IniFile
{
CString m_path;
public:
explicit IniFile(const CString &path)
: m_path(path)
{
}
CString GetString(const TCHAR *section, const TCHAR *key, const TCHAR *defstring)
{
CString str;
::GetPrivateProfileString(section, key, defstring, str.GetBuffer(512), 512, m_path);
str.ReleaseBuffer();
return str;
}
bool SetString(const TCHAR *section, const TCHAR *key, const TCHAR *value)
{
return ::WritePrivateProfileString(section, key, value, m_path) != 0;
}
int GetInteger(const TCHAR *section, const TCHAR *key, int defvalue)
{
return ::GetPrivateProfileInt(section, key, defvalue, m_path);
}
bool SetInteger(const TCHAR *section, const TCHAR *key, int value)
{
CString str;
str.Format(_T("%d"), value);
return ::WritePrivateProfileString(section, key, str, m_path) != 0;
}
bool IsWritable() const
{
if (::WritePrivateProfileString(_T("Writability Test"), _T("Writability Test"), _T("Test"), m_path))
{
// Remove it then.
::WritePrivateProfileString(_T("Writability Test"), NULL, NULL, m_path);
return true;
}
else
return false;
}
};
#endif // INIFILE_H

View File

@ -0,0 +1,23 @@
/*
*(C) 2006 Roku LLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the GNU General
* Public License for more details.
*
* Please read README.txt in the same directory as this source file for
* further license information.
*/
#include "stdafx.h"
#include "LogPage.h"
LRESULT CLogPage::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
return 0;
}

View File

@ -0,0 +1,41 @@
/*
*(C) 2006 Roku LLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the GNU General
* Public License for more details.
*
* Please read README.txt in the same directory as this source file for
* further license information.
*/
#ifndef LOGPAGE_H
#define LOGPAGE_H 1
#include "resource.h"
class CLogPage :
public CPropertyPageImpl<CLogPage>
{
typedef CPropertyPageImpl<CLogPage> base;
public:
enum { IDD = IDD_PAGE_LOG };
private:
// Message Handlers
BEGIN_MSG_MAP(CLogPage)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
CHAIN_MSG_MAP(base)
END_MSG_MAP()
LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
};
#endif // LOGPAGE_H

View File

@ -0,0 +1,59 @@
/*
*(C) 2006 Roku LLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the GNU General
* Public License for more details.
*
* Please read README.txt in the same directory as this source file for
* further license information.
*/
#include "stdafx.h"
#include "resource.h"
#include "MainDlg.h"
#include "FireflyShell.h"
CMainDlg::CMainDlg()
{
this->AddPage(m_pageConfig);
this->AddPage(m_pageAdvanced);
//this->AddPage(m_pageLog);
this->AddPage(m_pageAbout);
ATLVERIFY(m_strTitle.LoadString(IDR_MAINFRAME));
this->SetTitle(m_strTitle);
}
LRESULT CMainDlg::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
bool restart_service = false;
if (HIWORD(wParam) == BN_CLICKED)
{
const UINT id = LOWORD(wParam);
if ((id == IDOK || id == ID_APPLY_NOW)
&& GetDlgItem(ID_APPLY_NOW).IsWindowEnabled()
&& GetApplication()->GetServiceStatus().IsRunning())
{
CString title, text;
title.LoadString(IDR_MAINFRAME);
text.LoadString(IDS_QUERYSERVERRESTART);
if (MessageBox(text, title, MB_YESNO) != IDYES)
return 0;
restart_service = true;
}
}
LRESULT result = base::OnCommand(uMsg, wParam, lParam, bHandled);
if (restart_service)
GetApplication()->RestartService(m_hWnd);
return result;
}

View File

@ -0,0 +1,47 @@
/*
*(C) 2006 Roku LLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the GNU General
* Public License for more details.
*
* Please read README.txt in the same directory as this source file for
* further license information.
*/
#ifndef MAINDLG_H
#define MAINDLG_H 1
#include "ConfigPage.h"
#include "AdvancedPage.h"
#include "LogPage.h"
#include "AboutPage.h"
class CMainDlg : public CPropertySheetImpl<CMainDlg>
{
typedef CPropertySheetImpl<CMainDlg> base;
CString m_strTitle;
CConfigPage m_pageConfig;
CAdvancedPage m_pageAdvanced;
CLogPage m_pageLog;
CAboutPage m_pageAbout;
BEGIN_MSG_MAP(CMainDlg)
MESSAGE_HANDLER(WM_COMMAND, OnCommand)
CHAIN_MSG_MAP(base)
END_MSG_MAP()
LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
public:
CMainDlg();
};
#endif // MAINDLG_H

View File

@ -0,0 +1,270 @@
/*
*(C) 2006 Roku LLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the GNU General
* Public License for more details.
*
* Please read README.txt in the same directory as this source file for
* further license information.
*/
#include "stdafx.h"
#include "resource.h"
#include "NotifyIcon.h"
#include "FireflyShell.h"
CNotifyIcon::CNotifyIcon()
{
ZeroMemory(&m_nid, sizeof(NOTIFYICONDATA));
m_nid.cbSize = sizeof(NOTIFYICONDATA);
m_nid.uID = ID_SHELLNOTIFY;
m_running_icon = AtlLoadIcon(IDI_SHELL_RUNNING);
m_stopped_icon = AtlLoadIcon(IDI_SHELL_STOPPED);
}
BOOL CNotifyIcon::Create()
{
m_registered_activation_message = GetApplication()->GetRegisteredActivationMessage();
RECT rect = {0, 0, 0, 0};
// Hidden window.
if (base::Create(NULL, rect, _T("FireflyShellNotifyIconHidden"), WS_POPUP))
{
m_nid.uFlags = NIF_ICON|NIF_MESSAGE|NIF_TIP;
InflictIconState();
//wcsncpy(niData.szTip, TEXT("Foo?"), sizeof(niData.szTip));
m_nid.hWnd = m_hWnd;
m_nid.uCallbackMessage = PRIVATE_WM_NOTIFYICON;
Shell_NotifyIcon(NIM_ADD, &m_nid);
SetTimer(TIMER_ID, 5000, NULL);
GetApplication()->ServiceStatusSubscribe(this);
EnableUserSwitchNotifications();
return TRUE;
}
return FALSE;
}
void CNotifyIcon::Destroy()
{
GetApplication()->ServiceStatusUnsubscribe(this);
KillTimer(TIMER_ID);
Shell_NotifyIcon(NIM_DELETE, &m_nid);
DestroyIcon(m_nid.hIcon);
base::DestroyWindow();
}
void CNotifyIcon::PopupBalloon(UINT title_id, UINT text_id, DWORD flags)
{
CString title, text;
title.LoadString(title_id);
text.LoadString(text_id);
m_nid.uFlags |= NIF_INFO;
SafeStringCopy(m_nid.szInfoTitle, title, 64);
SafeStringCopy(m_nid.szInfo, text, 256);
m_nid.dwInfoFlags = flags;
m_nid.uTimeout = 10000;
Shell_NotifyIcon(NIM_MODIFY, &m_nid);
}
void CNotifyIcon::Update()
{
InflictIconState();
// I suspect we'll need this line too.
// m_nid.uFlags &= ~NIF_INFO;
Shell_NotifyIcon(NIM_MODIFY, &m_nid);
}
void CNotifyIcon::InflictIconState()
{
// Will the icons leak?
Service::Status status = GetApplication()->GetServiceStatus();
UINT state_id;
if (status.IsPending())
{
state_id = IDS_SERVER_PENDING;
m_nid.hIcon = m_stopped_icon; // As good as any?
}
else if (status.IsRunning())
{
state_id = IDS_SERVER_RUNNING;
m_nid.hIcon = m_running_icon;
}
else
{
state_id = IDS_SERVER_STOPPED;
m_nid.hIcon = m_stopped_icon;
}
CString tip;
tip.LoadString(state_id);
SafeStringCopy(m_nid.szTip, tip, 64);
}
void CNotifyIcon::OnServiceStatus(Service::Status old_status, Service::Status new_status)
{
Update();
}
void CNotifyIcon::OnTimer(UINT id, TIMERPROC proc)
{
if (id == TIMER_ID)
{
GetApplication()->CheckServiceStatus();
}
}
LRESULT CNotifyIcon::OnNotifyIconMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
switch (lParam)
{
case WM_LBUTTONDBLCLK:
GetApplication()->Configure();
bHandled = true;
return 0L;
case WM_RBUTTONDOWN:
case WM_CONTEXTMENU:
OnContextMenu();
bHandled = true;
return 0L;
}
return 0L;
}
void CNotifyIcon::OnContextMenu()
{
HMENU hMenu;
HINSTANCE hInstance = _Module.GetResourceInstance();
hMenu = ::LoadMenu(hInstance, MAKEINTRESOURCE(IDM_CONTEXT));
POINT pt;
GetCursorPos(&pt);
// See TrackPopupMenu in MSDN.
SetForegroundWindow(m_hWnd);
//::SetForegroundWindow(m_hWnd);
HMENU hPopup = GetSubMenu(hMenu, 0);
::SetMenuDefaultItem(hPopup, ID_CONFIGURE, FALSE);
TrackPopupMenu(hPopup, TPM_LEFTALIGN | TPM_BOTTOMALIGN, pt.x, pt.y, 0, m_hWnd, NULL);
::PostMessage(m_hWnd, WM_NULL, 0, 0);
::DestroyMenu(hMenu);
}
LRESULT CNotifyIcon::OnConfigure(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
GetApplication()->Configure();
return 0;
}
LRESULT CNotifyIcon::OnExit(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
/// @todo
Application::GetInstance()->Exit();
return 0;
}
LRESULT CNotifyIcon::OnRegisteredActivation(UINT, WPARAM, LPARAM, BOOL &bHandled)
{
ATLTRACE(_T("Activate\n"));
bHandled = true;
GetApplication()->Configure();
// We return a magic number so that the caller knows we've been found
// and can give up.
return m_registered_activation_message;
}
void CNotifyIcon::OnServerEvent(UINT32 id, UINT32 intval, const CString &strval)
{
// Note that we're running on a different thread here. We need to punt
// the event over to the main thread using SendMessage.
switch (id)
{
case 0:
break;
case 1:
case 2:
SendMessage(WM_SERVEREVENT, id);
break;
default:
ATLASSERT(false);
break;
}
}
LRESULT CNotifyIcon::OnServerEvent(UINT, WPARAM wparam, LPARAM, BOOL &bHandled)
{
bHandled = true;
switch (wparam)
{
case 1:
PopupBalloon(IDR_MAINFRAME, IDS_SCAN_START);
break;
case 2:
PopupBalloon(IDR_MAINFRAME, IDS_SCAN_STOP);
break;
}
return 0;
}
void CNotifyIcon::EnableUserSwitchNotifications()
{
HMODULE h = ::LoadLibrary(_T("WtsApi32.dll"));
if (h)
{
typedef BOOL (WINAPI *Proc)(HWND, DWORD);
Proc fn = reinterpret_cast<Proc>(GetProcAddress(h, "WTSRegisterSessionNotification"));
if (fn)
{
(*fn)(m_hWnd, NOTIFY_FOR_THIS_SESSION);
}
::FreeLibrary(h);
}
}
LRESULT CNotifyIcon::OnSessionChange(UINT, WPARAM wparam, LPARAM, BOOL &bHandled)
{
// Because only one process can get events through the mailslot we
// disconnect from it when the user uses XP fast user switching to
// switch to a different user.
switch (wparam)
{
case WTS_CONSOLE_CONNECT:
case WTS_REMOTE_CONNECT:
ATLTRACE("SESSION CONNECT\n");
GetApplication()->EnableServerEvents(true);
break;
case WTS_CONSOLE_DISCONNECT:
case WTS_REMOTE_DISCONNECT:
ATLTRACE("SESSION DISCONNECT\n");
GetApplication()->EnableServerEvents(false);
break;
}
bHandled = true;
return 0;
}

View File

@ -0,0 +1,81 @@
/*
*(C) 2006 Roku LLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the GNU General
* Public License for more details.
*
* Please read README.txt in the same directory as this source file for
* further license information.
*/
#ifndef NOTIFYICON_H
#define NOTIFYICON_H
#include "ServiceControl.h"
#include "ServerEvents.h"
class CNotifyIcon
: public CWindowImpl<CNotifyIcon>,
public ServiceStatusObserver,
public ServerEvents::Observer
{
typedef CWindowImpl<CNotifyIcon> base;
NOTIFYICONDATA m_nid;
HICON m_running_icon;
HICON m_stopped_icon;
UINT m_registered_activation_message;
enum { TIMER_ID = 43 };
enum { WM_SERVEREVENT = WM_APP + 42 };
enum { PRIVATE_WM_NOTIFYICON = WM_USER + 42 };
BEGIN_MSG_MAP(CNotifyIcon)
MESSAGE_HANDLER(PRIVATE_WM_NOTIFYICON, OnNotifyIconMessage)
COMMAND_ID_HANDLER(ID_CONFIGURE, OnConfigure)
COMMAND_ID_HANDLER(ID_EXIT, OnExit)
MESSAGE_HANDLER(m_registered_activation_message, OnRegisteredActivation)
MESSAGE_HANDLER(WM_SERVEREVENT, OnServerEvent)
MESSAGE_HANDLER(WM_WTSSESSION_CHANGE, OnSessionChange)
MSG_WM_TIMER(OnTimer)
END_MSG_MAP()
// Message handlers
void OnContextMenu();
LRESULT OnNotifyIconMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnConfigure(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
LRESULT OnExit(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
LRESULT OnRegisteredActivation(UINT, WPARAM, LPARAM, BOOL &bHandled);
LRESULT OnServerEvent(UINT, WPARAM, LPARAM, BOOL &bHandled);
LRESULT OnSessionChange(UINT, WPARAM, LPARAM, BOOL &bHandled);
void OnTimer(UINT id, TIMERPROC proc);
void PopupBalloon(UINT title_id, UINT text_id, DWORD flags = NIIF_INFO);
void InflictIconState();
void Update();
// Terminal services stuff on XP.
void EnableUserSwitchNotifications();
// ServiceStatusObserver
void OnServiceStatus(Service::Status old_status, Service::Status new_status);
// ServerEvents::Observer
void OnServerEvent(UINT32 id, UINT32 intval, const CString &str);
public:
CNotifyIcon();
BOOL Create();
void Destroy();
};
#endif // NOTIFYICON_H

View File

@ -0,0 +1,17 @@
The FireflyShell source code is distributed under the terms of the GNU
General Public License Version 2 as published by the Free Software
Foundation. You can find a copy of this license in the LICENSE.txt
file.
This program uses the Microsoft Windows Template Library which is released
under the Common Public License. The copyright holders of FireflyShell
explicitly grant the additional right to distribute binaries produced from
source code derived from FireflyShell that are linked with the Microsoft
Windows Template Library.
Note that you may not be able to incorporate third party GNU General Public
Licensed code into FireflyShell and then distribute binaries unless you have
a similar additional right from the copyright holder.
You can find the Windows Template Library at
http://sourceforge.net/projects/wtl/

View File

@ -0,0 +1,142 @@
/*
*(C) 2006 Roku LLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the GNU General
* Public License for more details.
*
* Please read README.txt in the same directory as this source file for
* further license information.
*/
#include "stdafx.h"
#include "ServerEvents.h"
ServerEvents::ServerEvents(Observer *obs) :
m_thread(INVALID_HANDLE_VALUE),
m_mailslot(INVALID_HANDLE_VALUE),
m_obs(obs)
{
}
ServerEvents::~ServerEvents()
{
ATLASSERT(m_mailslot == INVALID_HANDLE_VALUE);
ATLASSERT(m_thread == INVALID_HANDLE_VALUE);
}
bool ServerEvents::Start()
{
ATLASSERT(m_mailslot == INVALID_HANDLE_VALUE);
ATLASSERT(m_thread == INVALID_HANDLE_VALUE);
ATLASSERT(m_obs != NULL);
m_mailslot = ::CreateMailslot(_T("\\\\.\\mailslot\\FireflyMediaServer--67A72768-4154-417e-BFA0-FA9B50C342DE"), 0, MAILSLOT_WAIT_FOREVER, NULL);
if (m_mailslot != INVALID_HANDLE_VALUE)
{
//m_thread = ::CreateThread(NULL, 0, &StaticThreadProc, this, 0, &thread_id);
m_thread = (HANDLE)_beginthreadex(NULL, 0, &StaticThreadProc, this, 0, NULL);
if (m_thread == NULL)
{
// Failed
ATLTRACE("beginthreadex failed: %d\n", errno);
::CloseHandle(m_mailslot);
m_mailslot = INVALID_HANDLE_VALUE;
return false;
}
}
else
{
return false;
}
return true;
}
void ServerEvents::Stop()
{
ATLASSERT(m_mailslot != INVALID_HANDLE_VALUE);
ATLASSERT(m_thread != INVALID_HANDLE_VALUE);
// Force the thread to give up. This could be done with a separate event
// and overlapped IO but this is cheap.
CloseHandle(m_mailslot);
m_mailslot = INVALID_HANDLE_VALUE;
// Wait for it to finish.
WaitForSingleObject(m_thread, INFINITE);
CloseHandle(m_thread);
m_thread = INVALID_HANDLE_VALUE;
}
//DWORD ServerEvents::StaticThreadProc(LPVOID param)
unsigned ServerEvents::StaticThreadProc(void *param)
{
return reinterpret_cast<ServerEvents *>(param)->ThreadProc();
}
DWORD ServerEvents::ThreadProc()
{
const size_t BUFFER_SIZE = 65536;
void *buffer = operator new(BUFFER_SIZE);
bool finished = false;
while (!finished)
{
DWORD bytes_read;
if (ReadFile(m_mailslot, buffer, BUFFER_SIZE, &bytes_read, NULL))
{
TCHAR *b = (TCHAR *)buffer;
b[bytes_read/sizeof(TCHAR)] = 0;
ATLTRACE("%ls\n", b);
OnEvent(buffer, bytes_read);
}
else
{
ATLTRACE("Read failed: error %d\n", GetLastError());
finished = true;
}
}
return 0;
}
void ServerEvents::OnEvent(const void *buffer, size_t bytes_received)
{
const BYTE *received = reinterpret_cast<const BYTE *>(buffer);
if (bytes_received >= 12)
{
UINT32 packet_size = received[0] | (received[1] << 8) | (received[2] << 16) | (received[3] << 24);
UINT32 id = received[4] | (received[5] << 8) | (received[6] << 16) | (received[7] << 24);
UINT32 intval = received[8] | (received[9] << 8) | (received[10] << 16) | (received[11] << 24);
size_t string_length = bytes_received - 12;
if ((packet_size < bytes_received) && (packet_size >= 12))
string_length = packet_size - 12;
CString str;
if (string_length > 0)
{
#ifdef UNICODE
// It might be less that string_length long after conversion but it shouldn't be more unless
// our codepage is extremely weird.
str.ReleaseBuffer(MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, reinterpret_cast<const char *>(received + 12),
string_length, str.GetBufferSetLength(string_length), string_length));
#else
SafeStringCopy(str.GetBufferSetLength(string_length), received + 12, string_length);
#endif
str.ReleaseBuffer(string_length);
}
m_obs->OnServerEvent(id, intval, str);
}
}

View File

@ -0,0 +1,55 @@
/*
*(C) 2006 Roku LLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the GNU General
* Public License for more details.
*
* Please read README.txt in the same directory as this source file for
* further license information.
*/
#ifndef SERVEREVENTS_H
#define SERVEREVENTS_H
class ServerEvents
{
public:
/// Note that the observer is called on the wrong thread.
class Observer
{
public:
virtual void OnServerEvent(UINT32 id, UINT32 intval, const CString &str) = 0;
};
private:
HANDLE m_thread;
HANDLE m_mailslot;
Observer *m_obs;
static unsigned __stdcall StaticThreadProc(void *);
DWORD ThreadProc();
void OnEvent(const void *buffer, size_t length);
public:
ServerEvents(Observer *obs);
~ServerEvents();
void SetObserver(Observer *obs)
{
ATLASSERT(m_obs == NULL);
m_obs = obs;
}
bool Start();
void Stop();
};
#endif // SERVICE

View File

@ -0,0 +1,205 @@
/*
*(C) 2006 Roku LLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the GNU General
* Public License for more details.
*
* Please read README.txt in the same directory as this source file for
* further license information.
*/
#include "stdafx.h"
#include "ServiceControl.h"
bool Service::Open(const TCHAR *name)
{
Close();
const DWORD ADMIN_ACCESS = SC_MANAGER_ALL_ACCESS;
const DWORD USER_ACCESS = SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE | STANDARD_RIGHTS_READ;
DWORD dwDesiredAccess = ADMIN_ACCESS;
m_sc_manager = ::OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, dwDesiredAccess);
if (!m_sc_manager)
{
dwDesiredAccess = USER_ACCESS;
m_sc_manager = ::OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, dwDesiredAccess);
m_can_control = false;
}
else
{
m_can_control = true;
}
if (m_sc_manager)
{
m_sc_service = ::OpenService(m_sc_manager, name, dwDesiredAccess);
if (m_sc_service)
return true;
}
Close();
return false;
}
void Service::Close()
{
if (m_sc_service)
{
::CloseServiceHandle(m_sc_service);
m_sc_service = NULL;
}
if (m_sc_manager)
{
::CloseServiceHandle(m_sc_manager);
m_sc_manager = NULL;
}
}
bool Service::GetStatus(Status *status) const
{
if (::QueryServiceStatus(m_sc_service, status))
return true;
else
return false;
}
bool Service::Start()
{
if (::StartService(m_sc_service, 0, NULL))
return true;
else
return false;
}
bool Service::StartAndWait()
{
if (Start())
{
Status status;
return WaitPending(&status, SERVICE_START_PENDING);
}
else
return false;
}
bool Service::Stop()
{
Status status;
if (::ControlService(m_sc_service, SERVICE_CONTROL_STOP, &status))
return true;
else
return false;
}
bool Service::StopAndWait()
{
Status status;
if (::ControlService(m_sc_service, SERVICE_CONTROL_STOP, &status))
{
return WaitPending(&status, SERVICE_STOP_PENDING);
}
else
return false;
}
bool Service::WaitPending(Status *status, DWORD existing_state)
{
if (GetStatus(status))
{
DWORD dwStartTickCount = GetTickCount();
DWORD dwOldCheckPoint = status->dwCheckPoint;
while (status->dwCurrentState == existing_state)
{
ATLTRACE(_T("WaitPending\n"));
DWORD dwWaitTime = status->dwWaitHint / 10;
if (dwWaitTime < 1000)
dwWaitTime = 1000;
else if (dwWaitTime > 10000)
dwWaitTime = 10000;
::Sleep(dwWaitTime);
if (!GetStatus(status))
return false;
if (status->dwCheckPoint != dwOldCheckPoint)
{
// The service is making progress
dwStartTickCount = GetTickCount();
dwOldCheckPoint = status->dwCheckPoint;
}
else if (GetTickCount() - dwStartTickCount > status->dwWaitHint)
{
/// Hmm. No progress
return false;
}
}
}
return true;
}
CString Service::GetBinaryPath() const
{
CString path;
DWORD bytes_required;
::QueryServiceConfig(m_sc_service, NULL, 0, &bytes_required);
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
void *buffer = operator new(bytes_required);
LPQUERY_SERVICE_CONFIG config = reinterpret_cast<LPQUERY_SERVICE_CONFIG>(buffer);
if (::QueryServiceConfig(m_sc_service, config, bytes_required, &bytes_required))
{
path = config->lpBinaryPathName;
}
delete buffer;
}
return path;
}
DWORD Service::GetStartup() const
{
DWORD result = 0xffffffff;
const size_t BUFFER_SIZE = 8192;
void *buffer = operator new(BUFFER_SIZE);
LPQUERY_SERVICE_CONFIG config = reinterpret_cast<LPQUERY_SERVICE_CONFIG>(buffer);
DWORD bytes_required;
if (::QueryServiceConfig(m_sc_service, config, BUFFER_SIZE, &bytes_required))
result = config->dwStartType;
delete buffer;
return result;
}
bool Service::ConfigureStartup(DWORD startup)
{
if (::ChangeServiceConfig(m_sc_service, SERVICE_NO_CHANGE, startup, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
return true;
else
return false;
}
void ServiceStatusMonitor::Poll(Service *service)
{
Service::Status new_status;
if (service->GetStatus(&new_status))
{
if (!m_service_status.IsValid() || (m_service_status != new_status))
{
FireServiceStatus(m_service_status, new_status);
m_service_status = new_status;
}
}
}

View File

@ -0,0 +1,171 @@
/*
*(C) 2006 Roku LLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the GNU General
* Public License for more details.
*
* Please read README.txt in the same directory as this source file for
* further license information.
*/
#ifndef SERVICECONTROL_H
#define SERVICECONTROL_H
class Service
{
SC_HANDLE m_sc_manager;
SC_HANDLE m_sc_service;
bool m_can_control;
public:
class Status : public SERVICE_STATUS
{
bool WaitPending();
public:
Status()
{
SERVICE_STATUS *clearable_this = this;
ZeroMemory(clearable_this, sizeof(SERVICE_STATUS));
}
bool operator==(const Status &r) const
{
const SERVICE_STATUS *lhs = this;
const SERVICE_STATUS *rhs = &r;
return memcmp(lhs, rhs, sizeof(SERVICE_STATUS)) == 0;
}
bool operator!=(const Status &r) const
{
const SERVICE_STATUS *lhs = this;
const SERVICE_STATUS *rhs = &r;
return memcmp(lhs, rhs, sizeof(SERVICE_STATUS)) != 0;
}
void AssertValid() const
{
// If we've been written then this shouldn't be zero.
ATLASSERT(dwCurrentState != 0);
}
bool IsValid() const
{
return dwCurrentState != 0;
}
bool IsRunning() const
{
AssertValid();
return dwCurrentState == SERVICE_RUNNING;
}
bool IsStopped() const
{
AssertValid();
return dwCurrentState == SERVICE_STOPPED;
}
bool IsPaused() const
{
AssertValid();
return dwCurrentState == SERVICE_PAUSED;
}
bool IsPending() const
{
AssertValid();
switch (dwCurrentState)
{
case SERVICE_CONTINUE_PENDING:
case SERVICE_PAUSE_PENDING:
case SERVICE_START_PENDING:
case SERVICE_STOP_PENDING:
return true;
default:
return false;
}
}
};
Service() : m_sc_manager(NULL), m_sc_service(NULL), m_can_control(false) {}
~Service() { Close(); }
bool IsOpen() const
{
return m_sc_service != NULL;
}
bool Open(const TCHAR *name);
void Close();
bool GetStatus(Status *status) const;
bool Start();
bool StartAndWait();
bool Stop();
bool StopAndWait();
bool WaitPending(Status *status, DWORD existing_state);
bool PollPending(Status *status, DWORD existing_state);
bool CanControl() const
{
// For the time being - need to deal with running as a user that can't control.
return IsOpen() && m_can_control;
}
CString GetBinaryPath() const;
/// Pass SERVICE_AUTO_START, SERVICE_BOOT_START, SERVICE_DEMAND_START,
/// SERVICE_DISABLED or SERVICE_SYSTEM_START.
bool ConfigureStartup(DWORD dwStartup);
DWORD GetStartup() const;
};
class ServiceStatusObserver
{
public:
virtual void OnServiceStatus(Service::Status old_status, Service::Status new_status) = 0;
};
class ServiceStatusMonitor
{
Service::Status m_service_status;
std::vector<ServiceStatusObserver *> m_service_observers;
void FireServiceStatus(Service::Status old_status, Service::Status new_status)
{
std::vector<ServiceStatusObserver *>::iterator i = m_service_observers.begin();
while (i != m_service_observers.end())
{
(*i)->OnServiceStatus(old_status, new_status);
++i;
}
}
public:
void Poll(Service *service);
void Subscribe(ServiceStatusObserver *obs)
{
m_service_observers.push_back(obs);
}
void Unsubscribe(ServiceStatusObserver *obs)
{
std::vector<ServiceStatusObserver *>::iterator i = std::find(m_service_observers.begin(), m_service_observers.end(), obs);
ATLASSERT(i != m_service_observers.end());
if (i != m_service_observers.end())
{
m_service_observers.erase(i);
}
}
};
#endif // SERVICECONTROL_H

View File

@ -0,0 +1,111 @@
/*
*(C) 2006 Roku LLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the GNU General
* Public License for more details.
*
* Please read README.txt in the same directory as this source file for
* further license information.
*/
#include "stdafx.h"
#include "VersionInfo.h"
bool VersionInfo::Open(const TCHAR *filename)
{
Close();
DWORD useless;
m_size = GetFileVersionInfoSize(filename, &useless);
if (m_size)
{
m_buffer = operator new(m_size);
::ZeroMemory(m_buffer, m_size);
if (GetFileVersionInfo(filename, 0, m_size, m_buffer))
{
return IdentifySubBlock();
}
else
Close();
}
return false;
}
bool VersionInfo::IdentifySubBlock()
{
m_subblock.Empty();
WORD required_langid = LANGIDFROMLCID(GetUserDefaultLCID());
UINT cbTranslate;
struct LANGANDCODEPAGE
{
WORD wLanguage;
WORD wCodePage;
} *lpTranslate;
if (VerQueryValue(m_buffer, _T("\\VarFileInfo\\Translation"),
reinterpret_cast<LPVOID*>(&lpTranslate),
&cbTranslate))
{
// Try and find the user's language, but if we can't then just use the
// first one in the file.
int lang_index = -1;
for(unsigned i=0; i < (cbTranslate/sizeof(struct LANGANDCODEPAGE)); i++ )
{
// If we have an exact match then great.
if (lpTranslate[i].wLanguage == required_langid)
{
lang_index = i;
break;
}
// Otherwise settle for a primary language match and keep looking
else if ((PRIMARYLANGID(lpTranslate[i].wLanguage) == PRIMARYLANGID(required_langid)) && (lang_index < 0))
{
lang_index = i;
}
}
if (lang_index < 0)
{
ATLTRACE("Failed to find a matching language. Just using the first one.\n");
lang_index = 0;
}
m_subblock.Format(_T("\\StringFileInfo\\%04x%04x\\"), lpTranslate[lang_index].wLanguage, lpTranslate[lang_index].wCodePage);
return true;
}
return false;
}
void VersionInfo::Close()
{
if (m_buffer)
{
delete m_buffer;
m_buffer = NULL;
}
}
CString VersionInfo::GetString(const TCHAR *name) const
{
CString path = m_subblock + name;
LPVOID buffer;
UINT cb;
if (VerQueryValue(m_buffer, const_cast<LPTSTR>(static_cast<LPCTSTR>(path)), &buffer, &cb))
{
return CString(static_cast<LPCTSTR>(buffer), cb);
}
return CString();
}
//CString VersionInfo::GetStringFileVersion()
//{
// VerQueryValue(m_buffer,
//}

View File

@ -0,0 +1,46 @@
/*
*(C) 2006 Roku LLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the GNU General
* Public License for more details.
*
* Please read README.txt in the same directory as this source file for
* further license information.
*/
#ifndef VERSIONINFO_H
#define VERSIONINFO_H
class VersionInfo
{
size_t m_size;
void *m_buffer;
CString m_subblock;
bool IdentifySubBlock();
CString GetString(const TCHAR *name) const;
public:
VersionInfo() : m_size(0), m_buffer(NULL) {}
bool Open(const TCHAR *filename);
void Close();
CString GetFileDescription() const
{
return GetString(_T("FileDescription"));
}
CString GetFileVersion() const
{
return GetString(_T("FileVersion"));
}
};
#endif // VERSIONINFO_H

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,59 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by FireflyShell.rc
//
#define IDR_MAINFRAME 128
#define IDS_SERVER_RUNNING 129
#define IDS_SERVER_STOPPED 130
#define IDS_SERVERSTARTFAIL 131
#define IDS_SERVERSTOPFAIL 132
#define IDS_SERVER_PENDING 133
#define IDS_SERVER_START 134
#define IDS_SERVER_STOP 135
#define IDS_SCAN_START 136
#define IDS_SCAN_STOP 137
#define IDS_NOT_ADMIN 138
#define IDS_QUERYSERVERRESTART 139
#define IDS_VERSIONINFO_DESCRIPTION 140
#define IDS_VERSIONINFO_VERSION 141
#define IDS_VERSIONINFO_PATH 142
#define IDS_FAILED_CONFIGURE_SERVICE 143
#define IDS_FAILED_CONFIGURE_STARTUP 144
#define IDD_PAGE_BASIC 201
#define IDD_PAGE_ADVANCED 202
#define IDD_PAGE_LOG 203
#define IDD_PAGE_ABOUT 204
#define IDI_SHELL_STOPPED 207
#define IDC_SERVERNAME 1000
#define IDC_PATH 1001
#define IDC_BROWSE 1002
#define IDI_SHELL_RUNNING 1003
#define IDM_CONTEXT 1003
#define IDC_LOG 1003
#define ID_CONFIGURE 1004
#define IDC_PROTECT 1004
#define IDC_PASSWORD 1005
#define IDC_PASSWORD_PROMPT 1006
#define ID_EXIT 1007
#define IDC_PORTSPIN 1007
#define IDC_STARTSERVICE 1008
#define IDC_SERVERPORT 1009
#define IDC_STOPSERVICE 1010
#define IDC_SERVERSTATE 1011
#define IDC_AUTOSTART 1012
#define IDC_WEBADMIN 1013
#define IDC_WEBSITE 1014
#define IDC_VERSIONLIST 1015
#define IDC_COPY 1016
#define ID_SHELLNOTIFY 4242
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 208
#define _APS_NEXT_COMMAND_VALUE 32773
#define _APS_NEXT_CONTROL_VALUE 1017
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@ -0,0 +1,49 @@
/*
*(C) 2006 Roku LLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the GNU General
* Public License for more details.
*
* Please read README.txt in the same directory as this source file for
* further license information.
*/
#ifndef SINGLETON_H
#define SINGLETON_H
template <class T>
class Singleton
{
static T *sm_instance;
public:
Singleton()
{
T *instance = static_cast<T *>(this);
ATLASSERT(sm_instance == NULL);
sm_instance = instance;
}
virtual ~Singleton()
{
ATLASSERT(sm_instance != NULL);
sm_instance = NULL;
}
static T *GetInstance()
{
ATLASSERT(sm_instance != NULL);
return sm_instance;
}
};
template <class T>
T *Singleton<T>::sm_instance;
#endif // SINGLETON_H

View File

@ -0,0 +1,21 @@
/*
*(C) 2006 Roku LLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the GNU General
* Public License for more details.
*
* Please read README.txt in the same directory as this source file for
* further license information.
*/
#include "stdafx.h"
#if (_ATL_VER < 0x0700)
#include <atlimpl.cpp>
#endif //(_ATL_VER < 0x0700)

View File

@ -0,0 +1,77 @@
/*
*(C) 2006 Roku LLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the GNU General
* Public License for more details.
*
* Please read README.txt in the same directory as this source file for
* further license information.
*/
#pragma once
// Change these values to use different versions
#define WINVER 0x0400
#define _WIN32_WINNT 0x0501
#define _WIN32_IE 0x0500
#define _RICHEDIT_VER 0x0100
#define _UNICODE
#define UNICODE
#include <atlbase.h>
#include <atlapp.h>
extern CAppModule _Module;
#include <atlwin.h>
#include <atlframe.h>
#include <atlctrls.h>
#include <atldlgs.h>
#include <atlmisc.h>
#include <atlddx.h>
#include <atlcrack.h>
#include <atlctrlx.h>
#include <vector>
#include <algorithm>
// WtsApi32.h is only in the latest platform SDK. Don't rely
// on everyone having it.
#if !defined(NOTIFY_FOR_THIS_SESSION)
#define NOTIFY_FOR_THIS_SESSION 0
#endif
#if defined _M_IX86
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_IA64
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_X64
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#else
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif
// Visual C++ 2005's new secure string operations
#define USE_SECURE 0
#if defined(_MSC_VER)
#if _MSC_VER >= 1400
#undef USE_SECURE
#define USE_SECURE 1
#endif // _MSC_VER >= 1400
#endif // defined(_MSC_VER)
inline void SafeStringCopy(TCHAR *dest, const TCHAR *source, size_t len)
{
#if USE_SECURE
_tcsncpy_s(dest, len, source, len);
#else
_tcsncpy(dest, source, len);
dest[len - 1] = 0;
#endif
}

View File

@ -0,0 +1,13 @@
/* Version number of package */
#define VERSION_MAJOR 0
#define VERSION_MID 1
#define VERSION_MINOR 0
#define VERSION_BUILD $WCREV$
#define VERSION_LOCAL "$WCMODS? (LOCAL):$"
#define BUILD_DATE "$WCNOW$"
#define REPO_DATE "$WCDATE$"
#define VERSION_STRIZE2(x) #x
#define VERSION_STRIZE(x) VERSION_STRIZE2(x)
#define VERSION_STRING VERSION_STRIZE(VERSION_MAJOR) "." VERSION_STRIZE(VERSION_MID) "-svn" VERSION_STRIZE(VERSION_BUILD) VERSION_LOCAL

View File

@ -0,0 +1,44 @@
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
#include "version.h"
#include "winver.h"
#ifndef APSTUDIO_INVOKED
VS_VERSION_INFO VERSIONINFO
FILEVERSION VERSION_MAJOR, VERSION_MID, VERSION_MINOR, VERSION_BUILD
PRODUCTVERSION VERSION_MAJOR, VERSION_MID, VERSION_MINOR, VERSION_BUILD
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0x0L
#endif
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_APP
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Roku LLC"
VALUE "FileDescription", "FireflyShell"
VALUE "FileVersion", VERSION_STRING
VALUE "InternalName", "FireflyShell"
VALUE "LegalCopyright", "Copyright 2006 Roku LLC"
VALUE "OriginalFilename", "FireflyShell.exe"
VALUE "ProductName", "Firefly Media Server"
VALUE "ProductVersion", VERSION_STRING
VALUE "Comments", "Build date: " BUILD_DATE "\r\nRepository date: " REPO_DATE "\r\n"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif //APSTUDIO_INVOKED

View File

@ -8,6 +8,7 @@ echo Fixing version info...
%SUBWC% %0\..\.. %0\..\FireflyConfig\AssemblyInfo.cs.templ %0\..\FireflyConfig\AssemblyInfo.cs
%SUBWC% %0\..\.. %0\..\nsi\mt-daapd.nsi.templ %0\..\nsi\mt-daapd.nsi
%SUBWC% %0\..\.. %0\..\ssc-ffmpeg.rc.templ %0\..\ssc-ffmpeg.rc
%SUBWC% %0\..\.. %0\..\FireflyShell\version.h.templ %0\..\FireflyShell\version.h
goto END
:NOSUBWC
@ -15,4 +16,5 @@ copy %0\..\config.h.templ %0\..\config.h
copy %0\..\FireflyConfig\AssemblyInfo.cs.templ %0\..\FireflyConfig\AssemblyInfo.cs
copy %0\..\nsi\mt-daapd.nsi.templ %0\..\nsi\mt-daapd.nsi
copy %0\..\.. %0\..\ssc-ffmpeg.rc.templ %0\..\ssc-ffmpeg.rc
copy %0\..\FireflyShell\version.h.templ %0\..\version.h
:END