Editing summary info properties

I was given the project to add information to the summary property page of non-office files. I have almost no experience with C++, but I managed to find a program that does add information to the summary page. I need to read in the information from a text file, which contain four lines of information which are assigned to the following 'variables' Filename, RevLevel,CadStatus and RevReason.

I am not sure if the code is correct to read in the data and then assign the data.

The second part of the problem I am having is I get an error when I compile the project.

SummaryPropPage.cpp
H:\SummaryPropPage\SummaryPropPage.cpp(70) : error C2440: '=' : cannot convert from 'class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *' to 'char *'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
H:\SummaryPropPage\SummaryPropPage.cpp(96) : error C2664: 'StgOpenStorageEx' : cannot convert parameter 1 from 'char' to 'const unsigned short *'
Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast
Error executing cl.exe.

SummaryPropPage.obj - 2 error(s), 0 warning(s)

It seems to me that the value I am trying to use (*ptrFileName) is not the same type as required by the function.

Any help is greatly appreciated.

Thanks,
Craig


// SummaryPropPage.cpp : Defines the entry point
// for the application.
//

#include "stdafx.h"

#include <stdio.h>
#include <windows.h>
#include <ole2.h>
#include <fstream>
#include <iostream>
#include <string>

// Implicitly link ole32.dll
#pragma comment( lib, "ole32.lib" )
using namespace std;


const FMTID PropSetfmtid ={
/* F29F85E0-4FF9-1068-AB91-08002B27B3D9 */
0xf29f85e0,
0x4ff9,
0x1068,
{0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9 }
};

string FileName;
string RevLevel;
string CadStatus;
string RevReason;
fstream infile;

int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)



{

// ifstream is used for reading files
// We'll read from a file
ifstream infile ("H:\\summary_info.txt");

// If we couldn't open the input file stream for reading
if (!infile)
{
// Print an error and exit
cerr << "File could not be opened for reading!" << endl;
exit(1);
}

// While there's still stuff left to read
while (!infile.eof())
{
// read stuff from the file into a string. Not sure if this is working correctly. The summary_info.txt file has 4 lines of data
//std::string strInput;
getline(infile, FileName);
getline(infile, RevLevel);
getline(infile, CadStatus);
getline(infile, RevReason);
}
infile.close();
//set_property ()




char *ptrFileName; // this is a guess in an attempt to correct the error
ptrFileName = &FileName; // Ditto




IPropertySetStorage *pPropSetStg = NULL;
IPropertyStorage *pPropStg = NULL;
PROPSPEC propspec;
PROPVARIANT propWrite;
PROPVARIANT propRead;
HRESULT hr = S_OK;


// Open a file and a property set within it.
hr = StgOpenStorageEx( *ptrFileName, // When this is hard coded it works fine, but the filename changes so I need a way to open a different file each time the program is run.
STGM_DIRECT|STGM_SHARE_EXCLUSIVE| // hard coded means "H:\\summary_info.txt"
STGM_READWRITE,
STGFMT_ANY,
// STGFMT_STORAGE //Structured
//Storage property sets
// STGFMT_FILE //NTFS file system
//property sets
0,
NULL,
NULL,
IID_IPropertySetStorage,
reinterpret_cast<void**>(&pPropSetStg) );


if( FAILED(hr) )
throw L"Failed StgOpenStorageEx";

/*
hr = pPropSetStg->Open( PropSetfmtid,
STGM_WRITE|
STGM_SHARE_EXCLUSIVE,
&pPropStg );
*/

hr = pPropSetStg->Create( PropSetfmtid, NULL,
PROPSETFLAG_DEFAULT,
STGM_CREATE|STGM_READWRITE|
STGM_SHARE_EXCLUSIVE,
&pPropStg );

if( FAILED(hr) )
throw L"Failed IPropertySetStorage::Open";


//we can identify any property through its Name or its ID
// propspec.ulKind = PRSPEC_LPWSTR;
// propspec.lpwstr = L"Title"; // this is also going to need to be changed to a variable/pointer as well

propspec.ulKind = PRSPEC_PROPID;
propspec.propid = 0x00000002;


//specify the value of property
propWrite.vt = VT_LPWSTR;
propWrite.pwszVal = L"Rev Level";


hr = pPropStg->WriteMultiple( 1, &propspec,
&propWrite, PID_FIRST_USABLE );

if( FAILED(hr) )
throw L"Failed IPropertyStorage::WriteMultiple";





propspec.ulKind = PRSPEC_PROPID;
propspec.propid = 0x00000003;


//specify the value of property
propWrite.vt = VT_LPWSTR;
propWrite.pwszVal = L"Cad Status";

hr = pPropStg->WriteMultiple( 1, &propspec,
&propWrite, PID_FIRST_USABLE );

if( FAILED(hr) )
throw L"Failed IPropertyStorage::WriteMultiple";


propspec.ulKind = PRSPEC_PROPID;
propspec.propid = 0x00000004;


//specify the value of property
propWrite.vt = VT_LPWSTR;
propWrite.pwszVal = L"User Name";

hr = pPropStg->WriteMultiple( 1, &propspec,
&propWrite, PID_FIRST_USABLE );

if( FAILED(hr) )
throw L"Failed IPropertyStorage::WriteMultiple";


propspec.ulKind = PRSPEC_PROPID;
propspec.propid = 0x00000006;


//specify the value of property
propWrite.vt = VT_LPWSTR;
propWrite.pwszVal = L"Reason for Revision";

hr = pPropStg->WriteMultiple( 1, &propspec,
&propWrite, PID_FIRST_USABLE );

if( FAILED(hr) )
throw L"Failed IPropertyStorage::WriteMultiple";




pPropStg->Release();
pPropStg = NULL;


//again open the property set

hr = pPropSetStg->Open( PropSetfmtid,
STGM_READ|STGM_SHARE_EXCLUSIVE,
&pPropStg );

if( FAILED(hr) )
throw L"Failed IPropertySetStorage::Open";


// Read the property back and validate it
hr = pPropStg->ReadMultiple( 1, &propspec, &propRead );
if( FAILED(hr) )
throw L"Failed IPropertyStorage::ReadMultiple";


char* str = new char [wcslen(propRead.pwszVal) + 1];
// the "%S" will implicitly convert UNICODE to ANSI.
wsprintfA ( str, "%S", propRead.pwszVal);

//if you want to display
//MessageBox(NULL,str,"Reading Value",MB_OK);

if( hr == S_FALSE )
throw L"Property didn't exist after "
L"reopening the property set";
else if( propWrite.vt != propRead.vt )
throw L"Property types didn't match "
L"after reopening the property set";
else if( wcscmp( propWrite.pwszVal, propRead.pwszVal ) != 0 )
throw L"Property values didn't match"
L" after reopening the property set";
else
wprintf( L"Success\n" );

return 0;
}


StgOpenStorageEx() takes a pointer to a wide string as the first parameter.
The compiler error is cause because you're trying to implicitly convert a pointer to an std::string to a pointer to a C string (don't even dare do the explicit conversion).
This does not work: ptrFileName = &FileName;
There's a method for returning the internal C string: std::string::c_str().
But there's more. Since StgOpenStorageEx() takes a pointer to a wide string, you need to use a string that uses wide characters, instead. There's a typedef for that: std::wstring. I'm not sure if getline() will work with it, though.

In summary, this is what you need to do:
1. Make FileName an std::wstring.
2. Pass FileName.c_str() as the first parameter of StgOpenStorageEx().
Thanks Helios. I will try that and see what happens.
Here is my next attempt at getting this to work, though I am still not sure what is a proper way to read in a wstring, but when I use the cstring I can watch the values and see that I am reading the text file correctly. I can not do this with the wstring. This compiles and builds with no errors, but when I run it it terminates with a Debug error. I have marked the line where the error occurs.
Any ideas or suggestions?

Thank you,

Craig


// SummaryPropPage.cpp : Defines the entry point
// for the application.
//



//#include <stdlib.h> // these four line were added for wstring conversion
//#include "atlbase.h"
//#include "atlstr.h"
//#include "comutil.h"


#include "stdafx.h"
#include <stdio.h>
#include <windows.h>
#include <ole2.h>
#include <fstream>
#include <iostream>
#include <string>

// Implicitly link ole32.dll
#pragma comment( lib, "ole32.lib" )
using namespace std;


const FMTID PropSetfmtid ={
/* F29F85E0-4FF9-1068-AB91-08002B27B3D9 */
0xf29f85e0,
0x4ff9,
0x1068,
{0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9 }
};

wstring wFileName;
string RevLevel;
string CadStatus;
string RevReason;
fstream infile;
string FileName;

int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)



{

// ifstream is used for reading files
// We'll read from a file
ifstream infile ("H:\\summary_info.txt");

// If we couldn't open the input file stream for reading
if (!infile)
{
// Print an error and exit
cerr << "File could not be opened for reading!" << endl;
exit(1);
}

// While there's still stuff left to read
while (!infile.eof())
{
// read stuff from the file into a string and print it
//std::string FileName;
getline(infile, FileName);
getline(infile, RevLevel);
getline(infile, CadStatus);
getline(infile, RevReason);
}
infile.close();


// added to convert string to wstring
// Convert to a wchar_t*
size_t origsize = strlen(FileName.c_str()) + 1;
const size_t newsize = 100;
size_t convertedChars = 0;
wchar_t wcstring[newsize];
mbstowcs(wcstring, FileName.c_str(),newsize);
wcscat(wcstring, L" (wchar_t *)");
wFileName = wcstring;

//mbstowcs( wcstring, search.c_str(), newsize);


IPropertySetStorage *pPropSetStg = NULL;
IPropertyStorage *pPropStg = NULL;
PROPSPEC propspec;
PROPVARIANT propWrite;
PROPVARIANT propRead;
HRESULT hr = S_OK;


// Open a file and a property set within it.
hr = StgOpenStorageEx(wFileName.c_str(),
STGM_DIRECT|STGM_SHARE_EXCLUSIVE|
STGM_READWRITE,
STGFMT_ANY,
// STGFMT_STORAGE //Structured
//Storage property sets
// STGFMT_FILE //NTFS file system
//property sets
0,
NULL,
NULL,
IID_IPropertySetStorage,
reinterpret_cast<void**>(&pPropSetStg) );


if( FAILED(hr) )
throw L"Failed StgOpenStorageEx"; // this is where the Debug error occurs when I step through the program

/*
hr = pPropSetStg->Open( PropSetfmtid,
STGM_WRITE|
STGM_SHARE_EXCLUSIVE,
&pPropStg );
*/

hr = pPropSetStg->Create( PropSetfmtid, NULL,
PROPSETFLAG_DEFAULT,
STGM_CREATE|STGM_READWRITE|
STGM_SHARE_EXCLUSIVE,
&pPropStg );

if( FAILED(hr) )
throw L"Failed IPropertySetStorage::Open";


//we can identify any property through its Name or its ID
// propspec.ulKind = PRSPEC_LPWSTR;
// propspec.lpwstr = L"Title";

propspec.ulKind = PRSPEC_PROPID;
propspec.propid = 0x00000002;


//specify the value of property
propWrite.vt = VT_LPWSTR;
propWrite.pwszVal = L"Rev Level";


hr = pPropStg->WriteMultiple( 1, &propspec,
&propWrite, PID_FIRST_USABLE );

if( FAILED(hr) )
throw L"Failed IPropertyStorage::WriteMultiple";





propspec.ulKind = PRSPEC_PROPID;
propspec.propid = 0x00000003;


//specify the value of property
propWrite.vt = VT_LPWSTR;
propWrite.pwszVal = L"Cad Status";

hr = pPropStg->WriteMultiple( 1, &propspec,
&propWrite, PID_FIRST_USABLE );

if( FAILED(hr) )
throw L"Failed IPropertyStorage::WriteMultiple";


propspec.ulKind = PRSPEC_PROPID;
propspec.propid = 0x00000004;


//specify the value of property
propWrite.vt = VT_LPWSTR;
propWrite.pwszVal = L"User Name";

hr = pPropStg->WriteMultiple( 1, &propspec,
&propWrite, PID_FIRST_USABLE );

if( FAILED(hr) )
throw L"Failed IPropertyStorage::WriteMultiple";


propspec.ulKind = PRSPEC_PROPID;
propspec.propid = 0x00000006;


//specify the value of property
propWrite.vt = VT_LPWSTR;
propWrite.pwszVal = L"Reason for Revision";

hr = pPropStg->WriteMultiple( 1, &propspec,
&propWrite, PID_FIRST_USABLE );

if( FAILED(hr) )
throw L"Failed IPropertyStorage::WriteMultiple";




pPropStg->Release();
pPropStg = NULL;


//again open the property set

hr = pPropSetStg->Open( PropSetfmtid,
STGM_READ|STGM_SHARE_EXCLUSIVE,
&pPropStg );

if( FAILED(hr) )
throw L"Failed IPropertySetStorage::Open";


// Read the property back and validate it
hr = pPropStg->ReadMultiple( 1, &propspec, &propRead );
if( FAILED(hr) )
throw L"Failed IPropertyStorage::ReadMultiple";


char* str = new char [wcslen(propRead.pwszVal) + 1];
// the "%S" will implicitly convert UNICODE to ANSI.
wsprintfA ( str, "%S", propRead.pwszVal);

//if you want to display
//MessageBox(NULL,str,"Reading Value",MB_OK);

if( hr == S_FALSE )
throw L"Property didn't exist after "
L"reopening the property set";
else if( propWrite.vt != propRead.vt )
throw L"Property types didn't match "
L"after reopening the property set";
else if( wcscmp( propWrite.pwszVal, propRead.pwszVal ) != 0 )
throw L"Property values didn't match"
L" after reopening the property set";
else
wprintf( L"Success\n" );

return 0;
}


Don't use strlen() on the pointer returned by std::string::c_str(). There already is std::string::size().
DEFINITELY don't use mbstowcs() to convert between strings of different size. I'm pretty sure if you just do wFileName = FileName the conversion will be done automatically.

Did you try passing different flags to StgOpenStorageEx()? It may be that it's not giving you the access rights you ask for.

Next time you post code, put code tags around it. Like this:
[code]
int main(){
std::cout <<"Hello, World!"<<std::endl;
return 0;
}

[/code]
Helios,
I tried to use wFileName= FileName and got the following error.

H:\SummaryPropPage\SummaryPropPage.cpp(74) : error C2679: binary '=' : no operator defined which takes a right-hand operand of type 'class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >' (or there is no acceptable
conversion).


Also, can you be more specific (show an example) as to the best way to read in std::wstrings from a text file. I have not found anything that I can use and that really makes sense to me on my many searches on the internet.

Getfile does not work with wstrings as you suggested, but I did get it to work with std::string.


Thank you very much for the help,
Craig
You're right, it doesn't work. This does work, though:
1
2
3
4
5
6
7
8
9
#include <iostream>
#include <string>

int main(){
	std::string s="Hello, World!";
	std::wstring s2(s.begin(),s.end());
	std::wcout <<s2<<std::endl;
	return 0;
}

And yeah, doing input and output for wide strings is not easy. You might want to consider doing the IO to a narrow string and then copying the data to the wide string.
Topic archived. No new replies allowed.