Solved

String conversation in MS C 2008

Posted on 2011-09-15
17
477 Views
Last Modified: 2012-05-12
Hi experts!


I’m new to MS C 2008 and I need a little help. Look my code. It is working, but I need to make modification on it.

 There 2 questions:
1.      To make it for Unicode – I get this example from
http://msdn.microsoft.com/en-us/library/2c8d19sb(v=vs.71).aspx
where is describe how to make it Unicode, but I can’t understand it. Look code in point 2

2.      To replace the values char with LPCTSTR . Look example and read comment

long CCPlayCtrl::AnimationStaticPic(long lCard, LPCTSTR sPicFile,int ixPos,int iYPos, BOOL bUseBlendLevel, int BlendLevel, BOOL bUseTransByRGB, short R, short G, short B, short StartFadeMs, short EndFadeMs)
{

       int iRes=0; bool b=false; int iPic =0;
   STRADISANIMATION  hAn =0;

      hDecoder=hDec[lCard];
  try
  {
   
    // if sPic is more then 1 file
       char *strtok(
         char *strToken,
         const char *strDelimit
      );
      wchar_t *wcstok(
         wchar_t *strToken,
         const wchar_t *strDelimit
      );
      unsigned char *_mbstok(
         unsigned char*strToken,
         const unsigned char *strDelimit
      );

      char string[] =  "C:\Temp\logo001.tif, C:\Temp\logo002.tif, C:\Temp\logo003.tif"; // HERE I should pass sPicFile
    char seps[]   = " ,";
    char *token;

   LPCTSTR sPic[999];

         token = strtok( string, seps );
   while( token != NULL )
   {
      /* While there are tokens in "string" */
      //printf( " %s\n", token );
      /* Get next token: */
      token = strtok( NULL, seps );
        iPic++;
        sPic[iPic]=token; // HERE I shoud receve the token in LPCTSTR
   }

Note that my project is UNICODE. The only separator which I’ll use it is , there will be no space between files, just comma. I do not need universal solution , I need solution for this case EXACLTY without add any additional libraries and in C only, not C++
0
Comment
Question by:dvplayltd
  • 11
  • 6
17 Comments
 
LVL 32

Expert Comment

by:sarabande
ID: 36547420
as told in your last question LPCTSTR is const TCHAR * where TCHAR is char for ANSI and wchar_t for microsoft UNICODE.. the 'const' means you could not change it and you could not make a reassignment. in case of a pointer the complexity increases. a const of a pointer type can be a non-const pointer to a const variable or a const pointer to a non-const variable or a const pointer to a const variable.

for your array and tokens that is irrelevant. you should not and don't need to have const pointers, nor const tokens, nor const arrays. forget the const here. so your type is TCHAR* or LPTSTR what is equivalent. you can pass a LPTSTR to any function that has a LPCTSTR argument. the 'const' in the LPCTSTR is only valid for the function called it has no meaning for the caller (beside that the called function would not change the argument).

Sara
0
 
LVL 32

Expert Comment

by:sarabande
ID: 36547470
the _tcstok takes a TCHAR* as input buffer. so you can't feed it with sPicFile cause sPicFile is a const TCHAR*. the _tcstok needs the buffer to be non-const cause it wants to replace the separators found by a zero character. that way each single filename in the buffer would be properly terminated with a final zero.

because of that you need to make a copy of the sPicFile such that the buffer is writeable:

TCHAR * sFiles = _tcsdup(sPicFile);

now you can use the sFiles for _tcstok.

Sara
0
 

Author Comment

by:dvplayltd
ID: 36547511
To Sara

Thanks you, I do repleace, but I get error on other places. Could you please finish you suggestion and I'll give you point right away. Just do Copy/Paste and compile at your VC6 or VC9 or version which you use.

      TCHAR * string = _tcsdup(sPicFile); // example for value of sPicFile="C:\Temp\logo001.tif, C:\Temp\logo002.tif, C:\Temp\logo003.tif"

    char seps[]   = ",";
    char *token;

   LPCTSTR sPic[999];

   token = strtok( string, seps ); // 'strtok' : cannot convert parameter 1 from 'TCHAR *' to 'char *
   while( token != NULL )
   {
      /* While there are tokens in "string" */
      //printf( " %s\n", token );
      /* Get next token: */
      token = strtok( NULL, seps );
        iPic++;
        sPic[iPic]=token;//  '=' : cannot convert from 'char *' to 'LPCTSTR' // here I shoud receve the token in LPCTSTR
   }

The errors are 2 - I paste it like comment in row in which they appears.
Error      8      error C2440: '=' : cannot convert from 'char *' to 'LPCTSTR'      d:\AAdInserter\StardisOCX\CPlay\CPlayCtl.cpp      1081      CPlay
0
 
LVL 32

Expert Comment

by:sarabande
ID: 36547553
the function AnimationStaticPic in the moment has no way to return the array of file names parsed with _tcstok.

so either you need to use the array only in the AnimationStaticPic function itself (1), or you add an additional argument where the array could be returned (2), or you use a global array (3).

the (3) probably is the less recommendable solution as global variables are much error-prone and need a lot code to get managed correctly.

for (1) and (2) you can use a fixed-size array like you did with sPic[999]. i would opt against it cause it is not difficult to have a dynamically sized array and even when the 999 elements would be good for ever it is not good programming style to use huge fixed-size arrays and have no code for array overflow.

to find out how much elements you need you simply can count the commas in the file, or better the occurences of either single comma, single space or comma+space pair:

size_t len, i, numfiles, between;
LPTSTR * sPic;
...
len = _tcslen(sFiles);
between  = 0;
numfiles = 0;
for (i = 0; i < len; i++)
{
    if (between > 0 && sFiles[i] == _T(',') || sFiles[i] == _T(' '))
    {
         between = 0;
         numfiles++;
    }
    else
          between++;
}
// now create the dynamic array
sPic = new LPTSTR[numfiles+1];  // one more than separators
...

// delete the array after use
delete []sPic;

Open in new window


note, in C you would use malloc and free instead of new and delete. but as long as your source is cpp use the new and delete.

Sara

   
0
 
LVL 32

Expert Comment

by:sarabande
ID: 36547586
as told you need LPTSTR and not LPCTSTR.

so replace LPCTSTR sPic[999] by LPTSTR sPic[999];

Sara



0
 
LVL 32

Expert Comment

by:sarabande
ID: 36547591
error C2440: '=' : cannot convert from 'char *' to 'LPCTSTR'      

simply means that an array of LPCTSTR is const and only can be initially set but not by element.

Sara
0
 

Author Comment

by:dvplayltd
ID: 36547627
Yfff ... I have 10+ years in programming like senoir devoper, but this C is really hard ..

I need this array in function, will not return value.
The C project is OCX (ActiveX) and also I have limitation what values to use. The OCX is used from VB6 and this also put limits of possible types of text. For now I find that it work fine to pass text values like LPCTSTR ... OK I will make try to change it to LPTSTR to see does it work.

But first I want to ensure that code is OK ..then to try to change my input values type.

0
 

Author Comment

by:dvplayltd
ID: 36547675
Well, here is my 100 % limit as the function is in exernal DLL.

STRADIS_EXPORT int STRADISCALLMETHOD StradisBitmap_ImportFile(STRADISBITMAP hBitmap, LPCTSTR szFilename);

I should pass name of the file in LPCTSTR szFilename . if I pass LPTSTR  - does it work ??? I should do test .. compile do not make error, but I want to pus static value and to check final TV signal that is OK (The STradis card produce SDI output signal used for TV broadcast)

HOW TO PUT A STATIC VALUE - LIKE

LPTSTR sFileTemp="C:\TEMP\file1.tif" ???
0
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
LVL 32

Expert Comment

by:sarabande
ID: 36547737
the  LPCTSTR szFilename is ok. that is input and you need to copy the string to a writeable buffer for use in _tcstok. i already showed you how to do.

the 'static' thing i didn't understand? a static variable means that it keeps valid for next call as well, or better said, it keeps valid in memory beyond the scope of one function call:

int func()
{
     static int i = 0;
     return ++i;
}

Open in new window


here you have a static integer and it will return 1 when called first and would return incremented numbers 2, 3, ... for each following call.

in your case it makes no difference if you have

static LPTSTR sFileTemp="C:\TEMP\file1.tif";

or

LPTSTR sFileTemp="C:\TEMP\file1.tif";

beside you would pass the sFileTemp to a function which stores the pointer for later use.

normally they would not do so, but make a copy of the input same as we did with szPicFile (szFilename)..

Sara


0
 
LVL 32

Expert Comment

by:sarabande
ID: 36547768
oh, i see the StradisBitmap_ImportFile is a callback function. so the Stradis will call that function and passes the filename as input (that's why it is const). i assume it is a single filename only, so you don't need to copy it to a non-const string.

if the filename passed in the callback actually was one of the tokens you passed to Stradis before, then the sFiles buffer either should be made a static and fixed-size TCHAR array cause the callback calls were made after the AnimationStaticPic and non-static buffer would be freed, what means the pointers pointing into the buffer might be invalid in the meantime. an alternative is to have dynamic buffer created with _tcsdup as i showed above and do the free after all callbacks were done. i also can show how that works.

Sara
0
 

Author Comment

by:dvplayltd
ID: 36547794
Yes , you describe me, but here I'm like baby and you tell me a letter, while I need to make sentence. PLease give me the whole sentence, I mean whole code. I belive it is easy to you to understand what I try to get, all you are exerince in C programmer, I can see this.


My real work is AFTER i get this values, I do not want to be string C expert ! :-(

So here is again all which I need:

        // code with input values and produce output values.
Input: LPCTSTR sPicFile (example values "C:\Temp\logo001.tif,C:\Temp\logo002.tif,C:\Temp\logo003.tif")
Outputs: LPCTSTR sPic[999] (example sPic[1]="C:\Temp\logo001.tif" sPic[2]="C:\Temp\logo003.tif"
             int iMaxPic = 2 // showing real numbers of elements in array -do not need ANY check it will never be beigger than 999

             // to be more clear, later I'll use it in this way
      for (int x=1;x<=iMaxPic;x++)
      {
             b = StradisBitmap_ImportFile(hBitmaps, sPic[x]);
    }

0
 
LVL 32

Accepted Solution

by:
sarabande earned 500 total points
ID: 36548008
ok, the code is

long CCPlayCtrl::AnimationStaticPic(long lCard, LPCTSTR sPicFile,int ixPos,int iYPos, BOOL bUseBlendLevel, int BlendLevel, BOOL bUseTransByRGB, short R, short G, short B, short StartFadeMs, short EndFadeMs) 
{

    size_t len, i, numfiles, between;
    LPTSTR   sFiles;
    int iRes=0; bool b=false; int iPic =0;
    STRADISANIMATION  hAn =0;

    hDecoder=hDec[lCard];

    len = _tcslen(sPicFile);
    sFiles = new TCHAR[len+2];
    _tcscpy(sFiles, sPicFile);
    sFiles[len++] = ',';
    sFiles[len] = '\0';

    between  = 0;
    numfiles = 0;
    for (i = 0; i < len; i++)
    {
        if (between > 0 && sFiles[i] == _T(',') || sFiles[i] == _T(' '))
        {
             numfiles++;
             sFiles[i] = '\0';

             b = StradisBitmap_ImportFile(hBitmaps, &sFiles[i-between]); 

             between = 0;
        }
        else if (sFiles[i] != _T(',') && sFiles[i] != _T(' '))
        {
             between++;
        }
    }

    // delete the array after use
    delete []sFiles;

    return 0;
}

Open in new window


it doesn't need tcstok and LPTStTR array but sends file directly when a single file was parsed.


Sara
0
 

Author Closing Comment

by:dvplayltd
ID: 36548180
10x I put code in real project and now work! Aaaa! You and other here  all are best C experts, why took so long time to understand what I need ? Additional libraries, change from C to C++ in specific devices like my case can MAKE WORST POSSIBLE PROBLEMS AND BREAK ALL PROJECT. I'm 10 + years in the bussines and know what I should avoid at any cost - as simple all is, the best it is.
0
 
LVL 32

Expert Comment

by:sarabande
ID: 36548325
ee experts will not only give code but (try) teach you to do it next time yourself. i can't help you  for each such problem. you also delivered the important informations like call StradisBitmap_ImportFile with your latest posts.

better with next questions describe your problem and not try to describe the solution.

Sara
0
 
LVL 32

Expert Comment

by:sarabande
ID: 36550127
note the working code is c++ - see the 'new' operator - same as all you posted. i told you that source files with the extension .cpp all were automatically subject of c++ compiler. i tell you this cause you always should avoid wrong assumptions. c++ is in many aspects much easier than c.

i am 35 years in business and i know that the solutions that look simple took much more time than other more complex looking ways.

my very first code i posted in the previous code would have worked as well when i changed std::string to std::wstring and made the call to StradisBitmap_ImportFile as i did in the final solution. but at that time it was neither clear that you really have UNICODE enabled nor did i know your functions and their arguments. so you should accept that good solutions don't fell down from sky but were the result of a process where both side need to be as serious and willingful as possible.

Sara
0
 

Author Comment

by:dvplayltd
ID: 36565371
To sara

Well, 35 years sound very very much to me. I’m just 10+ years.

Well, I do my best to describe all my project. If I miss somthink it is becaouse to focus only on question, there many many other code which are not relative to question.

I apply you simplest solution in my project, it is enough good and working. But I have a note to you ..look code
    if (between > 0 && sFiles[j] == _T(',') || sFiles[j] == _T(' '))



I talk for this

|| sFiles[j] == _T(' '))

I remove it from one of my middle post where I show where I’m, but you return it again in you final code. And I miss this and post it on my project. First test show that it is working, but this was because my test was with path like
“C:\Temp\Logo001.bmp, C:\Temp\Logo002.bmp”

Later when I put a real file with part C:\Program Files\Logo001.bmp it not work as space is count like new file too. Bad is that I do not have any warning, just crash and I lose 3 hours before to detect problem. Once the STradis card crash it need restart of Windows to make new test. Very time consuming.  I told you more than once that this is part to files, wasn’t clear that space are allowed and only real separator is , ???

However, thank you again for you help.
P.S: About c++ and C – I’m sure you may be right, but as I’m new here and I get working solution I want to avoid any change.

I pass all code to see final result. And I return my arrar back :-).


long CCPlayCtrl::AnimationPic(long lCard, LPCTSTR sPicFile,int ixPos,int iYPos, BOOL bUseBlendLevel, int BlendLevel, BOOL bUseTransByRGB, short R, short G, short B, short StartFadeMs, short EndFadeMs) 
{
   LPCTSTR sPicFinal[999];
 	int iRes=0; bool b=false; int iPic =0;
   STRADISANIMATION  hAn =0;

	hDecoder=hDec[lCard];

  try
  {
    
    size_t len, i, numfiles, between;
    LPTSTR   sFiles;

    len = _tcslen(sPicFile);
    sFiles = new TCHAR[len+2];
    _tcscpy(sFiles, sPicFile);
    sFiles[len++] = ',';
    sFiles[len] = '\0';

    between  = 0;
    numfiles = 0;
    for (i = 0; i < len; i++)
    {
   //     if (between > 0 && sFiles[i] == _T(',') || sFiles[i] == _T(' '))
		if (between > 0 && sFiles[i] == _T(',') )
        {
             numfiles++;
             sFiles[i] = '\0';
             iPic++;

			 sPicFinal[iPic]=&sFiles[i-between];
           //  b = StradisBitmap_ImportFile(hBitmaps, &sFiles[i-between]); 

             between = 0;
        }
      //  else if (sFiles[i] != _T(',') && sFiles[i] != _T(' '))
		  else if (sFiles[i] != _T(','))
        {
             between++;
        }
    }

  STRADISBITMAP hBitmaps[999];

	
	for (int x=1;x<=iPic;x++)
	{
                     b = StradisBitmap_ImportFile(hBitmaps[x], sPicFinal[x]);
                    // ... other code
                }

Open in new window

0
 
LVL 32

Expert Comment

by:sarabande
ID: 36565871
yes , it is a bug. the or condition needs to be put into parantheses:

if (between > 0 && 
      (sFiles[i] == _T(',') || sFiles[i] == _T(' ')))

Open in new window


i checked for both comma and space cause that is the same that strtok would have made and what is ok as long the paths don't contain spaces.

so the above would take any comma or space as separator but only if there was at least one other character detected before.

Sara
0

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Preface I don't like visual development tools that are supposed to write a program for me. Even if it is Xcode and I can use Interface Builder. Yes, it is a perfect tool and has helped me a lot, mainly, in the beginning, when my programs were small…
Windows programmers of the C/C++ variety, how many of you realise that since Window 9x Microsoft has been lying to you about what constitutes Unicode (http://en.wikipedia.org/wiki/Unicode)? They will have you believe that Unicode requires you to use…
The goal of this video is to provide viewers with basic examples to understand recursion in the C programming language.
The goal of this video is to provide viewers with basic examples to understand and use switch statements in the C programming language.

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now