Yes, a single quote is the only escape character, so you are basically, but not completely alright.
Using parameters, although best of all, basically does the ' by '' replacement, which you do manually. BUT, they also provide the maximum string length. Of course, if we were talking about non-string parameters, they would have the advantage of providing a data type (i.e. ' no need to escape for numeric, date / time, etc., since this is not valid for them to begin with).
The problem that you can still leave is a subset of SQL Injection called SQL Truncation. The idea is to make part of dynamic sql leave the end of the line. I'm not sure how practical this is, but depending on how and where you are building dynamic sql, you need to make sure that the variable containing the dynamic SQL to execute is large enough to hold the static fragments in your code plus everything variables suggesting that they are represented at maximum length.
Here is an article from the MSDN journal, New SQL Truncation Attacks and How to Avoid Them , which shows both regular SQL injection and SQL Truncation. In this article, you will see that to avoid SQL Injection, they basically just use the REPLACE(@variable, '''', '''''') method REPLACE(@variable, '''', '''''') , but also show the use of QUOTENAME(@variable, '[') situations.
EDIT (2015-01-20): Here is a good resource, albeit not specific to SQL Server, that describes the various types of SQL Injection: https://www.owasp.org/index.php/Testing_for_SQL_Injection_(OTG-INPVAL-005)
The following article is related to the above. This approach is specific to SQL Server, but more general in terms of overall security. There are sections related to SQL Injection:
https://www.owasp.org/index.php/Testing_for_SQL_Server