1

I am implementing a custom action for a WindowsCE CAB file, and I need to concat a LPCTSTR to get a proper path to an exe.

My custom action receives a LPCTSTR as an argument.

So (pseudocode):

extern "C" codeINSTALL_EXIT MYCUSTOMACTION_API Install_Exit(
    HWND    hwndParent,
    LPCTSTR pszInstallDir,
    WORD    cFailedDirs,
    WORD    cFailedFiles,
    WORD    cFailedRegKeys,
    WORD    cFailedRegVals,
    WORD    cFailedShortcuts
)
{
    if (FALSE == LaunchApp(pszInstallDir + "\\MyApp.exe"))
       ::MessageBox(hwndParent, L"Could not launch app!", L"Setup", MB_ICONINFORMATION );
    return codeINSTALL_EXIT_DONE;
}

This is using the imaginary "+" operator, that I would use in my standard language, C#.

I have relatively little experience in C++. What is the proper way to append a LPCTSTR for my purposes? The LaunchApp method uses this type as an argument.

Also if I want to display the resulting path (for debugging purposes) in a MessageBox, is there a quick way to convert to a LPCWSTR?

jonathanpeppers
  • 26,115
  • 21
  • 99
  • 182
  • You probably do not want to add pointers even if the compiler didn't complain. Consider using C++ objects such as `std::string` or `std::wstring` where appropriate. – AJG85 Mar 08 '11 at 17:23
  • 1
    That is (pseudocode), I used the + as its meaning would imply in C#. I thought I was clear on that, sorry. – jonathanpeppers Mar 08 '11 at 17:25
  • 1
    For concatenating paths, you could use `PathCombine` from the *shlwapi* library. Not sure it's available on Windows CE, though. – Rob Kennedy Mar 08 '11 at 17:41
  • See also [`_makepath_s`, `_wmakepath_s`](http://msdn.microsoft.com/en-us/library/5a1745t0.aspx) – johnsyweb Mar 08 '11 at 19:15

3 Answers3

6

For concatenation use StringCchCat

TCHAR pszDest[260] = _T("");
StringCchCat(pszDest, 260, pszInstallDir); 
StringCchCat(pszDest, 260, _T("\\MyApp.exe"));
LaunchApp(pszDest);
ctacke
  • 66,480
  • 18
  • 94
  • 155
Cosmin
  • 2,365
  • 2
  • 23
  • 29
  • Can you post an example for my situation? – jonathanpeppers Mar 08 '11 at 16:58
  • This may or may not be available depending on the version of your OS and the components in the image. See @Rup's answer for CE 5.0? (I forget the exact OS version where they added these) and earlier. – ctacke Mar 08 '11 at 17:25
2

You need to allocate a new buffer to assemble the combined string in and then copy both parts into it. You can either pick a fixed, large buffer size

TCHAR fullPath[MAX_PATH + 11]; // 11 = length of "\MyApp.exe" + nul in characters
_sntprintf_s(fullPath, MAX_PATH + 11, _T("%s\\MyApp.exe"), pszInstallDir);

or allocate it dynamically to fit:

size_t installDirLen = tcslen(pszInstallDir);
size_t bufferLen = installDirLen + 11; // again 11 = len of your string
LPWSTR fullPath = new TCHAR[bufferLen];
// if you're paranoid, check allocation succeeded: fullPath != null
tcsncpy_s(fullPath, bufferLen, pszInstallDir);
tcsncat_s(fullPath, bufferLen, _T"\\MyApp.exe");
// use it
delete fullPath;

If you're in Unicode mode then LPCTSTR == LPCWSTR (in MBCS mode == LPCSTR instead). Either way the MessageBox macro should work for you - it'll choose between MessageBoxA or MessageBoxW as appropriate.


As ctacke points out below, this in on Windows CE and I can't assume you're going to have the _s functions. I think in the second case it's OK to use the non _s variants since we know the buffer is big enough, but in the first _sntprintf does not guarantee a trailing null on the output string (as the _s version does) and so we need to initialise the buffer ourselves first:

size_t bufferLen = MAX_PATH + 11;
TCHAR fullPath[bufferLen];
// zero the buffer out first
memset(fullPath, 0, sizeof(TCHAR) * bufferLen);
// only write up to bufferLen - 1, i.e. ensure the last character is left zero
_sntprintf(fullPath, bufferLen - 1, _T("%s\\MyApp.exe"), pszInstallDir);

(It might also be possible to do this by omitting the memset and using _sntprintf's return value to find the end of the combined generated string and nul the next character.)

AFAICR Windows CE is Unicode only and so LPCTSTR == LPCWSTR always.

Rup
  • 33,765
  • 9
  • 83
  • 112
  • One comment on this - it assumes that the safe string APIs are in the OS. If they are not (it's a modular OS after all) then you'll have to use the fallbacks of `_tcsncpy` and `_tcsncat` – ctacke Mar 08 '11 at 17:22
  • Sorry, completely missed it was Windows CE. Yes, I guess the second case should be safe to use the non-secure functions because we know the buffer is big enough; in the first case we'd need to guarantee there was a trailing null. I'll edit that in. – Rup Mar 08 '11 at 17:25
1

You can use string to be concatenated and then cast the result to LPCTSTR using ATL helpers like CA2T:

std::string filePath = "\\\\user\\Home\\";
std::string fileName = "file.ex";
std::string fullPath = filePath + fileName;
CA2T t(fullPath.c_str());
LPCTSTR lpctsrFullPath = t;
neurona.dev
  • 1,347
  • 1
  • 14
  • 12