mirror of
https://github.com/AppleWin/AppleWin.git
synced 2025-01-16 09:30:00 +00:00
Uthernet: fix usability and settings (PR #947)
* Make Uthernet settings behave like all other cards. Fix as well the fact that the Uthernet interface would not be reapplied after a restart. * Uthernet: use consistent types to reduce code complexity. Use std::string everywhere.
This commit is contained in:
parent
05b9668f72
commit
d631b23d24
@ -6,6 +6,7 @@
|
||||
#include "../DiskImage.h" // Disk_Status_e
|
||||
#include "../Harddisk.h" // HD_CardIsEnabled()
|
||||
#include "../Interface.h" // VideoRefreshRate_e, GetVideoRefreshRate()
|
||||
#include "../Tfe/tfe.h"
|
||||
|
||||
class CConfigNeedingRestart
|
||||
{
|
||||
@ -23,6 +24,9 @@ public:
|
||||
m_Slot[SLOT4] = GetCardMgr().QuerySlot(SLOT4);
|
||||
m_Slot[SLOT5] = GetCardMgr().QuerySlot(SLOT5);
|
||||
m_Slot[SLOT7] = GetCardMgr().QuerySlot(SLOT7);
|
||||
|
||||
m_tfeEnabled = get_tfe_enabled();
|
||||
m_tfeInterface = get_tfe_interface();
|
||||
}
|
||||
|
||||
const CConfigNeedingRestart& operator= (const CConfigNeedingRestart& other)
|
||||
@ -31,6 +35,8 @@ public:
|
||||
m_CpuType = other.m_CpuType;
|
||||
memcpy(m_Slot, other.m_Slot, sizeof(m_Slot));
|
||||
m_bEnableHDD = other.m_bEnableHDD;
|
||||
m_tfeEnabled = other.m_tfeEnabled;
|
||||
m_tfeInterface = other.m_tfeInterface;
|
||||
m_bEnableTheFreezesF8Rom = other.m_bEnableTheFreezesF8Rom;
|
||||
m_uSaveLoadStateMsg = other.m_uSaveLoadStateMsg;
|
||||
m_videoRefreshRate = other.m_videoRefreshRate;
|
||||
@ -43,6 +49,8 @@ public:
|
||||
m_CpuType == other.m_CpuType &&
|
||||
memcmp(m_Slot, other.m_Slot, sizeof(m_Slot)) == 0 &&
|
||||
m_bEnableHDD == other.m_bEnableHDD &&
|
||||
m_tfeEnabled == other.m_tfeEnabled &&
|
||||
m_tfeInterface == other.m_tfeInterface &&
|
||||
m_bEnableTheFreezesF8Rom == other.m_bEnableTheFreezesF8Rom &&
|
||||
m_uSaveLoadStateMsg == other.m_uSaveLoadStateMsg &&
|
||||
m_videoRefreshRate == other.m_videoRefreshRate;
|
||||
@ -58,6 +66,8 @@ public:
|
||||
SS_CARDTYPE m_Slot[NUM_SLOTS]; // 0..7
|
||||
SS_CARDTYPE m_SlotAux;
|
||||
bool m_bEnableHDD;
|
||||
int m_tfeEnabled;
|
||||
std::string m_tfeInterface;
|
||||
UINT m_bEnableTheFreezesF8Rom;
|
||||
UINT m_uSaveLoadStateMsg;
|
||||
VideoRefreshRate_e m_videoRefreshRate;
|
||||
|
@ -238,6 +238,11 @@ INT_PTR CPageConfig::DlgProcInternal(HWND hWnd, UINT message, WPARAM wparam, LPA
|
||||
EnableTrackbar(hWnd, bCustom);
|
||||
}
|
||||
|
||||
{
|
||||
m_PageConfigTfe.m_tfe_enabled = get_tfe_enabled();
|
||||
m_PageConfigTfe.m_tfe_interface_name = get_tfe_interface();
|
||||
}
|
||||
|
||||
InitOptions(hWnd);
|
||||
|
||||
break;
|
||||
@ -310,6 +315,9 @@ void CPageConfig::DlgOK(HWND hWnd)
|
||||
m_PropertySheetHelper.GetConfigNew().m_videoRefreshRate = isNewVideoRate50Hz ? VR_50HZ : VR_60HZ;
|
||||
}
|
||||
|
||||
m_PropertySheetHelper.GetConfigNew().m_tfeEnabled = m_PageConfigTfe.m_tfe_enabled;
|
||||
m_PropertySheetHelper.GetConfigNew().m_tfeInterface = m_PageConfigTfe.m_tfe_interface_name;
|
||||
|
||||
if (bVideoReinit)
|
||||
{
|
||||
win32Frame.FrameRefreshStatus(DRAW_TITLE);
|
||||
|
@ -196,29 +196,19 @@ void CPageConfigTfe::init_tfe_dialog(HWND hwnd)
|
||||
HWND temp_hwnd;
|
||||
int active_value;
|
||||
|
||||
int tfe_enable;
|
||||
int xsize, ysize;
|
||||
|
||||
char *interface_name = NULL;
|
||||
|
||||
uilib_get_group_extent(hwnd, ms_leftgroup, &xsize, &ysize);
|
||||
uilib_adjust_group_width(hwnd, ms_leftgroup);
|
||||
uilib_move_group(hwnd, ms_rightgroup, xsize + 30);
|
||||
|
||||
//resources_get_value("ETHERNET_ACTIVE", (void *)&tfe_enabled);
|
||||
get_tfe_enabled(&tfe_enable);
|
||||
|
||||
//resources_get_value("ETHERNET_AS_RR", (void *)&tfe_as_rr_net);
|
||||
active_value = (tfe_enable ? 1 : 0);
|
||||
active_value = (m_tfe_enabled > 0 ? 1 : 0);
|
||||
|
||||
temp_hwnd=GetDlgItem(hwnd,IDC_TFE_SETTINGS_ENABLE);
|
||||
SendMessage(temp_hwnd, CB_ADDSTRING, 0, (LPARAM)"Disabled");
|
||||
SendMessage(temp_hwnd, CB_ADDSTRING, 0, (LPARAM)"Uthernet");
|
||||
SendMessage(temp_hwnd, CB_SETCURSEL, (WPARAM)active_value, 0);
|
||||
|
||||
//resources_get_value("ETHERNET_INTERFACE", (void *)&interface_name);
|
||||
interface_name = (char *) get_tfe_interface();
|
||||
|
||||
if (tfe_enumadapter_open())
|
||||
{
|
||||
int cnt = 0;
|
||||
@ -232,7 +222,7 @@ void CPageConfigTfe::init_tfe_dialog(HWND hwnd)
|
||||
{
|
||||
BOOL this_entry = FALSE;
|
||||
|
||||
if (strcmp(pname, interface_name) == 0)
|
||||
if (strcmp(pname, m_tfe_interface_name.c_str()) == 0)
|
||||
{
|
||||
this_entry = TRUE;
|
||||
}
|
||||
@ -274,7 +264,6 @@ void CPageConfigTfe::init_tfe_dialog(HWND hwnd)
|
||||
void CPageConfigTfe::save_tfe_dialog(HWND hwnd)
|
||||
{
|
||||
int active_value;
|
||||
int tfe_enabled;
|
||||
char buffer[256];
|
||||
|
||||
buffer[255] = 0;
|
||||
@ -283,16 +272,13 @@ void CPageConfigTfe::save_tfe_dialog(HWND hwnd)
|
||||
// RGJ - Added check for NULL interface so we don't set it active without a valid interface selected
|
||||
if (strlen(buffer) > 0)
|
||||
{
|
||||
RegSaveString(TEXT(REG_CONFIG), TEXT(REGVALUE_UTHERNET_INTERFACE), 1, buffer);
|
||||
|
||||
m_tfe_interface_name = buffer;
|
||||
active_value = SendMessage(GetDlgItem(hwnd, IDC_TFE_SETTINGS_ENABLE), CB_GETCURSEL, 0, 0);
|
||||
|
||||
tfe_enabled = active_value >= 1 ? 1 : 0;
|
||||
REGSAVE(TEXT(REGVALUE_UTHERNET_ACTIVE) ,tfe_enabled);
|
||||
m_tfe_enabled = active_value >= 1 ? 1 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
REGSAVE(TEXT(REGVALUE_UTHERNET_ACTIVE) ,0);
|
||||
m_tfe_enabled = 0;
|
||||
m_tfe_interface_name.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,17 +3,23 @@
|
||||
#include "IPropertySheetPage.h"
|
||||
#include "../Tfe/Uilib.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class CPageConfigTfe : private IPropertySheetPage
|
||||
{
|
||||
public:
|
||||
CPageConfigTfe()
|
||||
{
|
||||
CPageConfigTfe::ms_this = this;
|
||||
m_tfe_enabled = 0;
|
||||
}
|
||||
virtual ~CPageConfigTfe(){}
|
||||
|
||||
static INT_PTR CALLBACK DlgProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam);
|
||||
|
||||
int m_tfe_enabled;
|
||||
std::string m_tfe_interface_name;
|
||||
|
||||
protected:
|
||||
// IPropertySheetPage
|
||||
virtual INT_PTR DlgProcInternal(HWND window, UINT message, WPARAM wparam, LPARAM lparam);
|
||||
|
@ -370,6 +370,17 @@ void CPropertySheetHelper::ApplyNewConfig(const CConfigNeedingRestart& ConfigNew
|
||||
{
|
||||
REGSAVE(TEXT(REGVALUE_VIDEO_REFRESH_RATE), ConfigNew.m_videoRefreshRate);
|
||||
}
|
||||
|
||||
if (CONFIG_CHANGED_LOCAL(m_tfeEnabled))
|
||||
{
|
||||
REGSAVE(TEXT(REGVALUE_UTHERNET_ACTIVE), ConfigNew.m_tfeEnabled);
|
||||
}
|
||||
|
||||
if (CONFIG_CHANGED_LOCAL(m_tfeInterface))
|
||||
{
|
||||
RegSaveString(TEXT(REG_CONFIG), TEXT(REGVALUE_UTHERNET_INTERFACE), 1, ConfigNew.m_tfeInterface);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CPropertySheetHelper::ApplyNewConfig(void)
|
||||
@ -387,6 +398,8 @@ void CPropertySheetHelper::SaveCurrentConfig(void)
|
||||
m_ConfigOld.m_bEnableHDD = HD_CardIsEnabled();
|
||||
m_ConfigOld.m_bEnableTheFreezesF8Rom = GetPropertySheet().GetTheFreezesF8Rom();
|
||||
m_ConfigOld.m_videoRefreshRate = GetVideo().GetVideoRefreshRate();
|
||||
m_ConfigOld.m_tfeEnabled = get_tfe_enabled();
|
||||
m_ConfigOld.m_tfeInterface = get_tfe_interface();
|
||||
|
||||
// Reset flags each time:
|
||||
m_ConfigOld.m_uSaveLoadStateMsg = 0;
|
||||
@ -470,6 +483,9 @@ bool CPropertySheetHelper::HardwareConfigChanged(HWND hWnd)
|
||||
|
||||
if (CONFIG_CHANGED(m_bEnableTheFreezesF8Rom))
|
||||
strMsgMain += ". F8 ROM changed (The Freeze's F8 Rom)\n";
|
||||
|
||||
if (CONFIG_CHANGED(m_tfeEnabled) || CONFIG_CHANGED(m_tfeInterface))
|
||||
strMsgMain += ". Ethernet (TFE) Options\n";
|
||||
}
|
||||
|
||||
std::string strMsgPost("\n");
|
||||
|
@ -60,13 +60,6 @@ typedef unsigned int UINT;
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* variables needed */
|
||||
|
||||
/*
|
||||
This variable is used when we need to postpone the initialization
|
||||
because tfe_init() is not yet called
|
||||
*/
|
||||
static int should_activate = 0;
|
||||
|
||||
|
||||
static int init_tfe_flag = 0;
|
||||
|
||||
/* status which received packages to accept
|
||||
@ -100,7 +93,7 @@ int tfe_enabled = 0;
|
||||
/* Flag: Do we use the "original" memory map or the memory map of the RR-Net? */
|
||||
//static int tfe_as_rr_net = 0;
|
||||
|
||||
char *tfe_interface = NULL;
|
||||
std::string tfe_interface;
|
||||
|
||||
/* TFE registers */
|
||||
/* these are the 8 16-bit-ports for "I/O space configuration"
|
||||
@ -397,7 +390,7 @@ static BYTE __stdcall TfeIo (WORD programcounter, WORD address, BYTE write, BYTE
|
||||
|
||||
void tfe_reset(void)
|
||||
{
|
||||
if (tfe_enabled && !should_activate)
|
||||
if (tfe_enabled)
|
||||
{
|
||||
assert( tfe );
|
||||
assert( tfe_packetpage );
|
||||
@ -550,13 +543,7 @@ int tfe_activate(void) {
|
||||
if(g_fh) fprintf( g_fh, "tfe_activate()." );
|
||||
#endif
|
||||
|
||||
if (init_tfe_flag) {
|
||||
return tfe_activate_i();
|
||||
}
|
||||
else {
|
||||
should_activate = 1;
|
||||
}
|
||||
return 0;
|
||||
return tfe_activate_i();
|
||||
}
|
||||
|
||||
static
|
||||
@ -565,28 +552,25 @@ int tfe_deactivate(void) {
|
||||
if(g_fh) fprintf( g_fh, "tfe_deactivate()." );
|
||||
#endif
|
||||
|
||||
if (should_activate)
|
||||
should_activate = 0;
|
||||
else {
|
||||
if (init_tfe_flag)
|
||||
return tfe_deactivate_i();
|
||||
}
|
||||
|
||||
return 0;
|
||||
return tfe_deactivate_i();
|
||||
}
|
||||
|
||||
void tfe_init(void)
|
||||
{
|
||||
init_tfe_flag = 1;
|
||||
|
||||
if (!tfe_arch_init()) {
|
||||
tfe_enabled = 0;
|
||||
tfe_cannot_use = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// the first time this is a NOOP
|
||||
// but when called from RepeatInitialization()
|
||||
// it ensures new settings are taken into account
|
||||
if (tfe)
|
||||
tfe_deactivate();
|
||||
|
||||
if (should_activate) {
|
||||
should_activate = 0;
|
||||
if (tfe_activate() < 0) {
|
||||
// only activate if the settings say so
|
||||
if (tfe_enabled && (tfe_activate() < 0)) {
|
||||
tfe_enabled = 0;
|
||||
tfe_cannot_use = 1;
|
||||
}
|
||||
@ -600,8 +584,7 @@ void tfe_shutdown(void)
|
||||
if (tfe)
|
||||
tfe_deactivate();
|
||||
|
||||
lib_free(tfe_interface);
|
||||
tfe_interface = NULL;
|
||||
tfe_interface.clear();
|
||||
}
|
||||
|
||||
|
||||
@ -1395,37 +1378,12 @@ int set_tfe_enabled(void *v, void *param)
|
||||
|
||||
|
||||
static
|
||||
int set_tfe_interface(void *v, void *param)
|
||||
int set_tfe_interface(const std::string & name)
|
||||
{
|
||||
const char *name = (const char *)v;
|
||||
|
||||
if (tfe_interface != NULL && name != NULL
|
||||
&& strcmp(name, tfe_interface) == 0)
|
||||
return 0;
|
||||
|
||||
util_string_set(&tfe_interface, name);
|
||||
|
||||
if (tfe_enabled) {
|
||||
/* ethernet is enabled, make sure that the new name is
|
||||
taken account of
|
||||
*/
|
||||
if (tfe_deactivate() < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (tfe_activate() < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* virtually reset the LAN chip */
|
||||
if (tfe) {
|
||||
tfe_reset();
|
||||
}
|
||||
}
|
||||
tfe_interface = name;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* commandline support functions */
|
||||
|
||||
@ -1547,21 +1505,19 @@ void get_disabled_state(int * param)
|
||||
|
||||
}
|
||||
|
||||
int update_tfe_interface(void *v, void *param)
|
||||
int update_tfe_interface(const std::string & name)
|
||||
{
|
||||
return set_tfe_interface(v,param);
|
||||
return set_tfe_interface(name);
|
||||
}
|
||||
|
||||
void * get_tfe_interface(void)
|
||||
const std::string & get_tfe_interface(void)
|
||||
{
|
||||
void *v;
|
||||
v = tfe_interface;
|
||||
return v;
|
||||
return tfe_interface;
|
||||
}
|
||||
|
||||
void get_tfe_enabled(int * param)
|
||||
int get_tfe_enabled(void)
|
||||
{
|
||||
*param = tfe_enabled;
|
||||
return tfe_enabled;
|
||||
}
|
||||
|
||||
//#endif /* #ifdef HAVE_TFE */
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
#include "../CommonVICE/types.h"
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
/* define this only if VICE should write each and every frame received
|
||||
and send into the VICE log
|
||||
@ -43,7 +44,7 @@ extern int tfe_enabled;
|
||||
extern void tfe_init(void);
|
||||
extern int tfe_resources_init(void);
|
||||
extern int tfe_cmdline_options_init(void);
|
||||
extern int update_tfe_interface(void *v, void *param);
|
||||
extern int update_tfe_interface(const std::string & name);
|
||||
void get_disabled_state(int * param);
|
||||
|
||||
extern void tfe_reset(void);
|
||||
@ -77,8 +78,8 @@ extern int tfe_enumadapter_open(void);
|
||||
extern int tfe_enumadapter(char **ppname, char **ppdescription);
|
||||
extern int tfe_enumadapter_close(void);
|
||||
|
||||
extern void* get_tfe_interface(void);
|
||||
extern void get_tfe_enabled(int *tfe_enabled);
|
||||
extern int get_tfe_enabled(void);
|
||||
extern const std::string & get_tfe_interface(void);
|
||||
|
||||
extern FILE* g_fh; // Filehandle for log file
|
||||
|
||||
|
@ -51,6 +51,7 @@
|
||||
#ifdef _MSC_VER
|
||||
|
||||
typedef pcap_t *(*pcap_open_live_t)(const char *, int, int, int, char *);
|
||||
typedef void (*pcap_close_t)(pcap_t *);
|
||||
typedef int (*pcap_dispatch_t)(pcap_t *, int, pcap_handler, u_char *);
|
||||
typedef int (*pcap_setnonblock_t)(pcap_t *, int, char *);
|
||||
typedef int (*pcap_datalink_t)(pcap_t *);
|
||||
@ -60,6 +61,7 @@ typedef int (*pcap_sendpacket_t)(pcap_t *p, u_char *buf, int size);
|
||||
typedef const char *(*pcap_lib_version_t)(void);
|
||||
|
||||
static pcap_open_live_t p_pcap_open_live;
|
||||
static pcap_close_t p_pcap_close;
|
||||
static pcap_dispatch_t p_pcap_dispatch;
|
||||
static pcap_setnonblock_t p_pcap_setnonblock;
|
||||
static pcap_findalldevs_t p_pcap_findalldevs;
|
||||
@ -80,6 +82,7 @@ void TfePcapFreeLibrary(void)
|
||||
pcap_library = NULL;
|
||||
|
||||
p_pcap_open_live = NULL;
|
||||
p_pcap_close = NULL;
|
||||
p_pcap_dispatch = NULL;
|
||||
p_pcap_setnonblock = NULL;
|
||||
p_pcap_findalldevs = NULL;
|
||||
@ -118,6 +121,7 @@ BOOL TfePcapLoadLibrary(void)
|
||||
}
|
||||
|
||||
GET_PROC_ADDRESS_AND_TEST(pcap_open_live);
|
||||
GET_PROC_ADDRESS_AND_TEST(pcap_close);
|
||||
GET_PROC_ADDRESS_AND_TEST(pcap_dispatch);
|
||||
GET_PROC_ADDRESS_AND_TEST(pcap_setnonblock);
|
||||
GET_PROC_ADDRESS_AND_TEST(pcap_findalldevs);
|
||||
@ -138,6 +142,7 @@ BOOL TfePcapLoadLibrary(void)
|
||||
|
||||
// libpcap is a standard package, just link to it
|
||||
#define p_pcap_open_live pcap_open_live
|
||||
#define p_pcap_close pcap_close
|
||||
#define p_pcap_dispatch pcap_dispatch
|
||||
#define p_pcap_setnonblock pcap_setnonblock
|
||||
#define p_pcap_findalldevs pcap_findalldevs
|
||||
@ -276,7 +281,7 @@ int tfe_arch_enumadapter_close(void)
|
||||
}
|
||||
|
||||
static
|
||||
BOOL TfePcapOpenAdapter(const char *interface_name)
|
||||
BOOL TfePcapOpenAdapter(const std::string & interface_name)
|
||||
{
|
||||
pcap_if_t *TfePcapDevice = NULL;
|
||||
|
||||
@ -289,12 +294,12 @@ BOOL TfePcapOpenAdapter(const char *interface_name)
|
||||
char *pdescription;
|
||||
BOOL found = FALSE;
|
||||
|
||||
if (interface_name) {
|
||||
if (!interface_name.empty()) {
|
||||
/* we have an interface name, try it */
|
||||
TfePcapDevice = TfePcapAlldevs;
|
||||
|
||||
while (tfe_enumadapter(&pname, &pdescription)) {
|
||||
if (strcmp(pname, interface_name)==0) {
|
||||
if (strcmp(pname, interface_name.c_str())==0) {
|
||||
found = TRUE;
|
||||
}
|
||||
lib_free(pname);
|
||||
@ -328,6 +333,8 @@ BOOL TfePcapOpenAdapter(const char *interface_name)
|
||||
{
|
||||
if(g_fh) fprintf(g_fh, "ERROR: TFE works only on Ethernet networks.\n");
|
||||
tfe_enumadapter_close();
|
||||
(*p_pcap_close)(TfePcapFP);
|
||||
TfePcapFP = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -365,7 +372,7 @@ void tfe_arch_post_reset( void )
|
||||
#endif
|
||||
}
|
||||
|
||||
int tfe_arch_activate(const char *interface_name)
|
||||
int tfe_arch_activate(const std::string & interface_name)
|
||||
{
|
||||
#ifdef TFE_DEBUG_ARCH
|
||||
if(g_fh) fprintf( g_fh, "tfe_arch_activate().\n" );
|
||||
@ -381,6 +388,10 @@ void tfe_arch_deactivate( void )
|
||||
#ifdef TFE_DEBUG_ARCH
|
||||
if(g_fh) fprintf( g_fh, "tfe_arch_deactivate().\n" );
|
||||
#endif
|
||||
if (TfePcapFP) {
|
||||
(*p_pcap_close)(TfePcapFP);
|
||||
TfePcapFP = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void tfe_arch_set_mac( const BYTE mac[6] )
|
||||
|
@ -29,11 +29,12 @@
|
||||
#define _TFEARCH_H
|
||||
|
||||
#include "../CommonVICE/types.h"
|
||||
#include <string>
|
||||
|
||||
extern int tfe_arch_init(void);
|
||||
extern void tfe_arch_pre_reset(void);
|
||||
extern void tfe_arch_post_reset(void);
|
||||
extern int tfe_arch_activate(const char *interface_name);
|
||||
extern int tfe_arch_activate(const std::string & interface_name);
|
||||
extern void tfe_arch_deactivate(void);
|
||||
extern void tfe_arch_set_mac(const BYTE mac[6]);
|
||||
extern void tfe_arch_set_hashfilter(const DWORD hash_mask[2]);
|
||||
|
@ -300,7 +300,7 @@ void LoadConfiguration(void)
|
||||
tfe_enabled = dwTfeEnabled ? 1 : 0;
|
||||
|
||||
RegLoadString(TEXT(REG_CONFIG), TEXT(REGVALUE_UTHERNET_INTERFACE), 1, szFilename, MAX_PATH, TEXT(""));
|
||||
update_tfe_interface(szFilename, NULL);
|
||||
update_tfe_interface(szFilename);
|
||||
|
||||
//
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user