I have a huge program that started it's life 15 years ago as a VS6 project under Windows 9.x. It's always been a multi-byte program. We've decided to finally convert to unicode and I'm attempting the task now. However I'm running into a weird issue. When I switch to the unicode config I get errors everywhere we use ASSERT....
Error C2664 'BOOL AfxAssertFailedLine(LPCSTR,int)': cannot convert argument 1 from 'TCHAR [89]' to 'LPCSTR'
If I start a brand new MFC project and use ASSERT it works fine, so I assume it's some sort of project/solution configuration thing but I'm not sure where to even look. These projects have been upgraded through at least 5 versions of VS, and there are probably close to 100 projects in the solution.
Has anyone ever run into this issue before? Any clue how to fix it?
↧
[RESOLVED] Unicode and ASSERT
↧
SetScrollSize and FormView
Hello,
I created a formview with nested controls. My problem is setting the correct values for vertical scroll size so that I can scroll thru the complete range of the view. At the moment, my code cannot scroll to the bottom of the view.
My code:
void CMyFormView::OnInitialUpdate()
{
CFormView::OnInitialUpdate();
#define MM_SCALETOFIT (-1)
CRect rectFrame;
CFrameWnd* pFrame = GetParentFrame();
ASSERT_VALID(pFrame);
pFrame->GetWindowRect(rectFrame);
CSize size = rectFrame.Size();
SetScrollSizes(MM_TEXT, size);
….
}
Notice in the left portion of the attached screen capture that the scroll thumb occupies almost the entire vertical scrollbar which limits the range to scroll.
I found out that if I increased the cy member of CSize, the scrollbar thumb is smaller and it now allows me to scroll down to the bottom of the formview.
See right portion of the screen capture.
My question is what do I need to do to set the correct value for CSize?
I assume I will also need the same code to change the scroll size when the user resizes the frame window in the call to OnSize.
Thank you for your assistance.
↧
↧
Why is `float` so much faster than `int` in this program?
This simple program copy data from the array `xy` to `arr` and prints the time it takes
Code:
---------
#include
#include
class Point
{
public:
float x, y;
Point() :x(0), y(0) {}
Point(float x, float y) : x(x), y(y) {}
};
int main()
{
const size_t n = 99999999;
Point *arr = new Point[n];
float *xy = new float[2 * n];
for (size_t i = 0; i < 2 * n; i++)
xy[i] = (float)i;
clock_t start = clock();
for (size_t i = 0, j = 0; i < n; i++)
{
float x = xy[j++];
float y = xy[j++];
arr[i] = Point(x, y);
}
clock_t end = clock();
printf("time: %d\n", (end - start));
delete[] arr;
delete[] xy;
return 0;
}
---------
It takes about 250 ms. If I change everything to `int`:
Code:
---------
#include
#include
class Point
{
public:
int x, y;
Point() :x(0), y(0) {}
Point(int x, int y) : x(x), y(y) {}
};
int main()
{
const size_t n = 99999999;
Point *arr = new Point[n];
int *xy = new int[2 * n];
for (size_t i = 0; i < 2 * n; i++)
xy[i] = (int)i;
clock_t start = clock();
for (size_t i = 0, j = 0; i < n; i++)
{
int x = xy[j++];
int y = xy[j++];
arr[i] = Point(x, y);
}
clock_t end = clock();
printf("time: %d\n", (end - start));
delete[] arr;
delete[] xy;
return 0;
}
---------
it takes almost 3 times the time, around 700 ms. Why is there is a difference? I expected it to be the same because they are both 32 bits and there are no arithmetic operations involved.
I am using Visual Studio 2015, Configuration: Release x64. Processor: intel i7-4510U.
↧
C++ OOP-Revision Question on Class, Data Members, and Member Methods
Having acquired very basic skills in C++, I've started learning Object Oriented Programming in C++ for a week now. I came across a revision question below and got stuck. I feel there are some other details the question expects me to include the coding. I'm still a beginner in as far as C++ structures are concerned, and will appreciate your guidance/assistance on this as I had no other references or examples that could guide me. For any incorrect presentations here or formatting, kindly correct me. I'm still learning. Thanks you.
Question:
Create a C++ program with a class Account
Data members:
1.accountName
2.openBalance
3.deposit
Member methods:
1.getdetails()
2.calculatecurrentbalance()
Code:
---------
<#include
using namespace std;
//My first attempt in creating class, data members and member methods..
class Account
getdetails()
calculatecurrentbalance()
// I'm not sure I'm right...and do not know how to continue...I guess I need an intervention on this...
{
char accountName;
double openBalance;
double deposit;{
{Account() {Balance=0.0;}
getdetails()
calculatecurrentbalance()
}
---------
↧
CDockablePane in CMDIChildWndEx
I have an MDI app, built in VS2008. On some childframes, I have inserted some CDockablePane. But I have a probem: They don't know to save their state and position. The CDockablePane's ones that is part of CMainFrame know how to save their state and position without any written code, through CDockingManager class ...
But this is not the case, when CDockablePane is part of CChildFrame ...
I have tried this: https://stackoverflow.com/questions/...49341#39449341
not worked.
I have tried this:
and
I also tried this:
and
but sometimes I get memory leaks:
and
is there any solution to save/restore the pane's from child frame ?
I attach here a sample code that illustrate the problem ...
But this is not the case, when CDockablePane is part of CChildFrame ...
I have tried this: https://stackoverflow.com/questions/...49341#39449341
not worked.
I have tried this:
Code:
int CChildFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
..........
CDockState state;
state.LoadState(_T("MyDockPane"));
SetDockState(state);
return 0;
}
Code:
void CChildFrame::OnDestroy()
{
CDockState state;
GetDockState(state);
state.SaveState(_T("MyDockPane"));
CMDIChildWndEx::OnDestroy();
}
Code:
int CChildFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CMDIChildWndEx::OnCreate(lpCreateStruct) == -1)
return -1;
// enable Visual Studio 2005 style docking window behavior
CDockingManager::SetDockingMode(DT_SMART);
// enable Visual Studio 2005 style docking window auto-hide behavior
EnableAutoHidePanes(CBRS_ALIGN_ANY);
CMDIChildWndEx::m_bEnableFloatingBars = TRUE;
// Create properties window
CString strPropertiesWnd;
BOOL bNameValid = strPropertiesWnd.LoadString(IDS_PROPERTIES_WND);
ASSERT(bNameValid);
if(! m_wndProperties.Create(strPropertiesWnd, this, CRect(0, 0, 200, 200), TRUE, ID_VIEW_PROPERTIESWND, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CBRS_LEFT | CBRS_FLOAT_MULTI))
{
TRACE(_T("Failed to create Properties window\n"));
return FALSE; // failed to create
}
if(! m_wndFilter.Create(_T("Filter"), this, CRect(0, 0, 200, 200), TRUE, 0, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CBRS_LEFT | CBRS_FLOAT_MULTI))
{
TRACE(_T("Failed to create Properties window\n"));
return FALSE; // failed to create
}
SetDockingWindowIcons(theApp.m_bHiColorIcons);
AddPane(&m_wndFilter);
AddPane(&m_wndProperties);
m_wndFilter.EnableDocking(CBRS_ALIGN_ANY);
m_wndProperties.EnableDocking(CBRS_ALIGN_ANY);
DockPane(&m_wndFilter);
CDockablePane* pTabbedBar = NULL;
m_wndProperties.AttachToTabWnd(&m_wndFilter, DM_SHOW, TRUE, &pTabbedBar);
EnableAutoHidePanes(CBRS_ALIGN_ANY);
m_dockManager.LoadState(theApp.GetRegSectionPath(_T("ChildFrame")));
m_dockManager.SetDockState();
return 0;
}
Code:
void CChildFrame::OnDestroy()
{
if(! m_wndProperties.IsFloating() &&
! m_wndFilter.IsFloating())
m_dockManager.SaveState(theApp.GetRegSectionPath(_T("ChildFrame")));
CMDIChildWndEx::OnDestroy();
}
Code:
Detected memory leaks!
Dumping objects ->
f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\afxpanecontainer.cpp(2382) : {27179} client block at 0x0267BEC8, subtype c0, 156 bytes long.
a CPaneContainer object at $0267BEC8, 156 bytes long
Object dump complete.
The program '[8876] Model.exe: Native' has exited with code 0 (0x0).
Code:
DestroyWindow in CWnd::~CWnd; OnDestroy or PostNcDestroy in derived class will not be called.
I attach here a sample code that illustrate the problem ...
↧
↧
Customizing print preview
Hi all of you.
I intend to customize the print preview, after what doctor ordered:
https://msdn.microsoft.com/en-us/library/aabc3hc6.aspx
And I have tried in MFC feature pack this solution ... but I get an mixed dialogbar for print-preview:
http://imgur.com/a/SFNID
Strange mix of MFC feature pack print preview dialogbar, and my custom print preview dialogbar ... I attach the test VS2008 project below.
It is possible to customize the print-preview in MFC feature pack apps ?
↧
Windows that has the lowest Z-order so that all objects are above it?
I am looking into something like a Owned window, which is owned by the Desktop
Code:
---------
HWND owner_hwnd = GetDesktopWindow();
CreateWindow(L"ABC", L"ABC", WS_POPUP , ...., owner_hwnd, ...);
---------
Sorry, I can't remember exactly all the parameters,
But is this the way to create a owned window, (by specifying only the owner hwnd)?
Thanks
Jack
↧
how to change the color of property sheet wizard button in VC++
Hi All,
I want to change the color of property sheet wizard button. The wizard has ID_WIZNEXT, ID_WIZFINISH and other default button. the button label and position is changed. i want to change the color of this default button.
Code:
---------
class CDiskSanPropertySheet : public CPropertySheet
{
}
BOOL CDiskSanPropertySheet::OnInitDialog()
{
CPropertySheet::OnInitDialog();
CButton *tmpButtonNext = reinterpret_cast(GetDlgItem(ID_WIZNEXT));
CButton *tmpButtonFinish = reinterpret_cast(GetDlgItem(ID_WIZFINISH));
CButton *tmpButtonBack = reinterpret_cast(GetDlgItem(ID_WIZBACK));
CButton *tmpButtonCancel = reinterpret_cast(GetDlgItem(IDCANCEL));
buttonString.LoadStringW(IDS_TEXT_BUTTON_NEXT);
tmpButtonNext->SetWindowTextW(buttonString.GetBuffer());
buttonString.ReleaseBuffer();
LONG rightPos, nextRightPos;
//inc. to 1.7 for greek issue
MoveButton(tmpButtonCancel,shiftFactorX, 1.7,NULL,tmpButtonNext,&nextRightPos);
MoveButton(tmpButtonFinish,shiftFactorX, 1.7,NULL,NULL,NULL);
rightPos = nextRightPos;
MoveButton(tmpButtonNext,shiftFactorX, 1.7,&rightPos,tmpButtonBack,&nextRightPos);
rightPos = nextRightPos;
MoveButton(tmpButtonBack,shiftFactorX, 1.7,&rightPos,NULL,NULL);
}
HBRUSH CDiskSanPropertySheet::OnCtlColor(CDC* pDC, CWnd *pWnd, UINT nCtlColor)
{
HBRUSH hbr = CPropertySheet::OnCtlColor(pDC,pWnd, nCtlColor);
COLORREF myColor = RGB(250,250,250);
//COLORREF myColor = RGB(0, 0, 255);
TCHAR classname[MAX_PATH];
if(::GetClassName(pWnd->m_hWnd, classname, MAX_PATH) == 0)
return hbr;
if(_tcsicmp(classname, _T("EDIT")) == 0)
if(_tcsicmp(classname, _T("LISTBOX")) == 0)
return hbr;
if(_tcsicmp(classname, WC_TREEVIEW) == 0)
return hbr;
pDC->SetTextColor((myColor));
if ((HBRUSH)brush == NULL)
brush.CreateSolidBrush((myColor));
return (HBRUSH) brush;
}
---------
I want to change the color of the above button. Please help me to resolve this.
Regards,
Rani
↧
How to regain right-click context menu after creating a window-based desktop?
Code:
---------
winClass.lpszClassName = "Alt_Desktop";
winClass.cbSize = sizeof(WNDCLASSEX);
winClass.style = CS_HREDRAW | CS_VREDRAW;
winClass.lpfnWndProc = WindowProc;
winClass.hInstance = hInstance;
winClass.hIcon = LoadIcon(hInstance, NULL);
winClass.hIconSm = LoadIcon(hInstance, NULL);
winClass.hCursor = LoadCursor(NULL, IDC_ARROW);
winClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
winClass.lpszMenuName = NULL;
winClass.cbClsExtra = 0;
winClass.cbWndExtra = 0;
if( !RegisterClassEx(&winClass) )
return E_FAIL;
g_hWnd = CreateWindowEx( NULL, "Alt_Desktop",
"Alt_Desktop",
WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
0, 0, 640, 480, NULL, NULL, hInstance, NULL );
if( g_hWnd == NULL )
return E_FAIL;
SetWindowPos(g_hWnd, HWND_BOTTOM, 0, 0, 1920, 1079, 0);
---------
I can't use the context menu anymore after creating the desktop like this.
How to regain the context menu from this code?
Thanks
Jack
↧
↧
[RESOLVED] Why doesn't this method of closing a worker thread work?
I have an MFC application whose GUI has a start and a stop button. The start button calls a function which I want to run in the background, periodically. My solution was to use the *SetTimer *function to call the *OnTimer *function at regular intervals. This function then creates a thread using *AfxBeginThread *and then populates the structure that I pass to the thread as a parameter. All this works just fine.
What I would like to do now is the make the stop button end the thread. I have read about *TerminateThread *but it seems too risky. Since I want to close the worker thread from another thread, I know I can't use *AfxEndThread*, but I wanted to know why the following solution doesn't work.
What I have tried:
I created an *int *variable called count and set it to *0 *whenever start is pressed, and set it to *1 *whenever stop is pressed.
The structure I am passing into *AfxBeginThread *looks like this
Code:
---------
typedef struct THREADSTRUCT
{
MyGUIDlg* _this;
int flag;
//you can add here other parameters you might be interested on
} THREADSTRUCT;
---------
When start is pressed the SetTimer function is called, whose callback function is defined like this:
Code:
---------
void MyGUIDlg::OnTimer(UINT_PTR nIDEvent)
{
THREADSTRUCT* _param = new THREADSTRUCT;
_param->_this=this;
_param->flag = count;
AfxBeginThread(StartThread, _param);
CDialog::OnTimer(nIDEvent);
}
---------
In my StartThread function I have added the following:
Code:
---------
UINT MyGUIDlg::StartThread(LPVOID param)
{
THREADSTRUCT *ts = (THREADSTRUCT*)param;
if((ts->flag)==1)
{
//Use AfxEndThread to close this thread
}
return 0;
}
---------
But this doesn't seem to work, any thoughts why?
↧
Using Structure to Create Accounts and Calculating Currentbalance.
As part of my C++(OOP) learning process, I'm I have a tempted a question that requires a user to enter details of 3 bank account holders then calculate and display their Current Balances. I know current balances=Open balance +Deposit. I however cannot figure out where exactly to include the calculation and have all results display after entering accounts holders' details. Below is my code. Your inputs/guidance will be highly appreciated. As I indicated before, I'm still a beginner by all standards.
Thanks.
Code:
---------
#include
using namespace std;
struct Account
{
char AccName[12];
int Openbalance, Deposit;
//where do I insert current balance calculation(Currentbalanace=Openbalance+Deposit?
} x[3];
int main()
{
int Currentbalance;
int Openbalance;
int Deposit;
Currentbalance = Openbalance + Deposit;
int i;
for (i = 0; i <= 2; i++)
{
cout << "Enter name, openbalance and depostit for " << i + 1 << endl;
cin >> x[i].AccName;
cin >> x[i].Openbalance;
cin >> x[i].Deposit;
}
for (i = 0, i <= 2;i++;)
{
cout << x[i].AccName << "\t" << x[i].Openbalance << "\t" << x[i].Deposit << x[i].Openbalance + x[i].Deposit << endl;
cout << "Current Balance is " << x[i].Openbalance + x[i].Deposit << endl;
}
system("pause");
return 0;
}
---------
↧
Error when using Nodes in C++
Code:
---------
void LIST::insertEvent(EVENT *e)
{
LLNODE* curr = front;
LLNODE* newn = new LLNODE(e);
LLNODE* old = NULL;
if (curr == NULL)
{
front = newn;
}
do {
old = curr;
curr = curr->next; <------------------------------------------------------------------------------------the error spot
} while ((curr->ev->getprocessTime() <= newn->ev->getprocessTime()) && curr != NULL);
if (old == NULL)
{
newn->next = front;
front = newn;
}
old->next = newn;
newn->next = curr;
}
---------
is my function, and
Code:
---------
class LLNODE {
friend class LIST; //"LIST is my friend!"
private:
LLNODE *next;
EVENT *ev;
public:
LLNODE(EVENT *e);
~LLNODE();
};
---------
is the header function for it. At the line "curr = curr->next;" (in the do-while loop), there is a "Unhandled exception thrown: read access violation. curr was nullptr." error. Why is the exception being thrown there?
↧
C++ Read access violation when accessing private data member
Hello, so I am trying to make a member function that returns the int processTime of an event. The class for the Event class is:
Code:
---------
class EVENT {
private:
string device;
int type;
int processTime;
public:
EVENT(string n, int t, int pt);
void display();
int getprocessTime();
};
---------
and the member function (called getProcessTime() plus the exception being thrown (I also put in the constructor for events) are:
Code:
---------
EVENT::EVENT(string n, int v, int pt)
{
device = n;
type = v;
processTime = pt;
}
int EVENT::getprocessTime() {
return processTime;
}
---------
The error:
Exception thrown: read access violation.
this was 0xCDCDCDCD.
Why is a read access violation being thrown? processTime is made in the event class, so shouldn't it be accessible outside? What should I do differently to make it be accessible by getProcessTime(); i.e add the -> operator.
↧
↧
Multiple user input and task execution
Hello there . SO I have a question about my program .
↧
Need help finishing with this c++ project
I need help on how to get my program like it is.
prompt:
One large chemical company pays its salespeople on a commission basis. The salespeople each receive $200 per week plus 9 percent of their gross sales for that week. For example, a salesperson who sells $5000 worth of chemicals in a week receives $200 plus 9 percent of $5000, or a total of $650. Develop a C++ program that uses a while statement to input each salesperson’s gross sales for last week and calculates and displays that salesperson’s earnings. Process one salesperson’s figures at a time.
Your program should have one member data named grossSales.
Your program should have a constructor, a get and a set member function for the data.
The result salaries must be displayed in 2 decimal places.
Sample run:
Enter sales in dollars:(-1 to end): 5000 //input
Salary is : 650.00 //output
Enter sales in dollars:(-1 to end): 5678
Salary is: 711.02
cpp:
Code:
---------
#include
#include "Sales.h"
using namespace std;
int main()
{
double salary, sales;
Sales mySales;
//double commision=0.09;//rate given
cout<<"Enter sales In dollar(-1 to end)";
cin>>sales; //input
// write the loop to get more values
while(sales!=-1)
{
}
mySales.setGrossSales( sales );
salary = mySales.findSalary();
cout<<"Salary is "<
↧
printing multiple figures side by side
hello there . So this is my code where I had to display right triangle shapes in different position . Everything is working fine . But I have a problem using a for loop statement to display them side by side . how can I use a for loop to display them on CMD side by side . thx . this is my code below :
Code:
---------
#include
using namespace std;
int main ()
{
for ( int i = 1 ; i <= 10 ; ++i ) {
for ( int j = 1 ; j <= i ; j++ ) {
if ( j <= i )
cout << "*";
}
cout << endl;
}
cout <<"\n";
for ( int i = 10 ; i >= 1 ; --i ) {
for ( int j = 1 ; j <= i ; j++ ) {
cout << "*";
}
cout << endl;
}
cout <<"\n";
int i , j;
for ( i = 1 ; i <= 10 ; i++ ) {
for ( j = 1 ; j < i ; j++ ) {
cout << " ";
}
for ( j = i ; j <= 10 ; ++j ) {
cout << "*";
}
cout << endl;
}
cout <<"\n";
int k , l ;
for ( k = 1 ; k <= 10 ; k++ ) {
for ( l = k ; l < 10 ; l++ ) {
cout << " ";
}
for ( l = 1 ; l <= k ; l++ ) {
cout << "*";
}
cout << endl;
}
system ("pause");
return 0 ;
}
---------
↧
compute a growth with variable rate
Hello there . So I was asked to solve this problem which I don't fully understand that's why I have difficulties starting with it since I'm still a beginner. here it is :
There are approximately 2.5 billion people on the Internet as of
January 2013. Facebook reached one billion users in October of 2012. In this exercise, youll
write a program to determine when Facebook will reach 2.5 billion people if it were to grow at
fixed monthly percentage rates of 2%, 3%, 4% or 5%.
As u see the rate is not stable and I should each time using a for loop , get month and year when it reach 2.5 billion user . I was given this hint from another exercise to use inside the for loop but I didnt understand how to use it . I will appreciate ur help thx ..
Code:
---------
amount = pow ( 1.0 * rate , year )
---------
↧
↧
Changing mode MM_ISOTROPIC causes control to resize
Now if I try to draw a simple rectangle which occupies the whole control, I get that as expected.
Code:
---------
BOOL CZoomDemoDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// .... typical default contents (omitted)
// TODO: Add extra initialization here
CRect rect;
GetDlgItem(IDC_STATIC1)->GetWindowRect(&rect);
ScreenToClient(&rect);
m_ZoomWnd = new CZoomWnd;
m_ZoomWnd->Create(_T("STATIC"), NULL, WS_CHILD | WS_VISIBLE | SS_NOTIFY, rect, this, 1234);
return TRUE; // return TRUE unless you set the focus to a control
}
---------
The problem now is when I do the following, I get the red color rectange of the same size that was the control size.
Code:
---------
void CZoomWnd::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
CRect rect;
GetClientRect(&rect);
dc.FillSolidRect(&rect, RGB(255, 0, 0, 0));
}
---------
Here is the problem, if I change the mapping mode, the rect control changes size (shrinks considerbly in this case but I guess result can vary based on monitor resolution perhaps).
Code:
---------
void CZoomWnd::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
// Do not call CWnd::OnPaint() for painting messages
const CSize origWindowExtText = dc.GetWindowExt(); // logical coordinates
const CSize origViewportExtText = dc.GetViewportExt(); // device coordinate (typically pixels).
dc.SetMapMode(MM_ISOTROPIC);
const CSize origWindowExt = dc.GetWindowExt(); // logical coordinates
const CSize origViewportExt = dc.GetViewportExt(); // device coordinate (typically pixels).
// dc.SetWindowExt( origWindowExt.cx , -origWindowExt.cy ); // dive by 2 gives the normal size
dc.SetWindowExt(origWindowExt.cx , -origWindowExt.cy ); // dive by 2 gives the normal size
dc.SetViewportExt(origViewportExt);
dc.SetViewportOrg(m_ViewportOrigin);
CRect rect;
GetClientRect(&rect);
dc.FillSolidRect(&rect, RGB(255, 0, 0, 0));
}
---------
My question is why does the control changes size? See the output below. What can I do so my control size remains the same with MM_ISOTROPIC mode? I do need it for zooming.
Attachment 34891 (http://forums.codeguru.com/attachment.php?attachmentid=34891).
↧
[RESOLVED] What is secret inside address of string C++?
Here is my test code:
Code:
---------
std::cout << &str << '\t' << (void *)&str[0] << '\t' << (void *)&str[1] << '\t' << (void *)&str[2] << '\t' << (void *)&str[3] << std::endl;
---------
And here is the result:
Attachment 34893 (http://forums.codeguru.com/attachment.php?attachmentid=34893)
Why &str and &str[0] is not the same address? What is the sceret inside this?
↧
How to make Qt-grade GUI with resedit?
Is it possible to make a very beautiful GUI by using the resedit and vc++ 2010 express software, much like the product created by Qt?
Are there any good tutorials to recommend?
Thanks
Jack
Are there any good tutorials to recommend?
Thanks
Jack
↧