MFC Dialog Based Application

Completely new to C++ and have been given a task that includes creating an application that uses CString data from a completely separate .h file.
The CStrings consist of info that I need to be able to copy to the clipboard, then be able to paste that text into word etc. I have set up a button in the application so when that button is pressed it executes what I want it to do (read the CString data and copy it to the clipboard).
For a person of my skill level this is difficult and my colleagues do not have the time to support me on this learning project so I thought I could get some advice and pointers here. Any help would be greatly appreciated. I am an apprentice working in software for 2 months.

Kind regards,
Luke
Last edited on
I can help you write data directly into Word, if that would help. I've never used the clipboard programatically (I'm a bit embarressed to admit), so if you indeed want to go that route perhaps somebody else could help.
Try checking https://msdn.microsoft.com/en-us/library/ms649014(v=vs.85).aspx for reference info on how to program clipboard
Freddie1, I think that would work better for what I am after to be honest. Any help with that would be great. :)
Last edited on
If Freddie method is correct then I think what you need is to write to a word document using a COM object. Check if this link provides a better link in understanding what you need to do: http://www.codeproject.com/Articles/34998/MS-Office-OLE-Automation-Using-C
Copying a string to the clipboard is straight forward.
http://www.cplusplus.com/forum/general/48837/#msg266435

If Freddie method is correct then I think what you need is to write to a word document using a COM object. Check if this link provides a better link in understanding what you need to do:


Yep, that's the Freddie method. I'm a heavy COM user, and have recently updated my includes for connecting to and reading/writting Excel/Word docs. I can easily provide code, but it would be easier for me not to use the CString Class of MFC. Also, I'm a bit 'put off' by MFC Dialog apps. Straight SDK style is more my forte. But I can deal with it if I have to I guess. What version of Visual Studio are you using OP?
Here is a console program to get you started Luke. It is essentially just a "Hello, World!" program, but instead of writing "Hello, World!" to the console screen, it opens a Word *.doc file and writes "Hello, World!" to there...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#ifndef   UNICODE
#define   UNICODE
#endif
#ifndef   _UNICODE
#define   _UNICODE
#endif
#include <windows.h>
#include <cstdio>
#include "WordFunctions.h"


int main()
{
 const CLSID CLSID_WordApplication = {0x000209FF,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
 const IID   IID_Application       = {0x00020970,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
 IDispatch*  pWordApp              = NULL;
 IDispatch*  pWordDocuments        = NULL;
 IDispatch*  pWordDocument         = NULL;
 IDispatch*  pWordSelection        = NULL;
 wchar_t     szText[512];
 HRESULT     hr;
 LCID        lcid;

 CoInitialize(NULL);
 lcid=GetUserDefaultLCID();
 hr=CoCreateInstance(CLSID_WordApplication, NULL, CLSCTX_LOCAL_SERVER, IID_Application, (void**)&pWordApp);
 if(SUCCEEDED(hr))
 {
    SetVisible(pWordApp,lcid);
    pWordDocuments=GetDispatchObject(pWordApp,0x06,DISPATCH_PROPERTYGET,lcid);
    if(pWordDocuments)
    {
       pWordDocument=GetDispatchObject(pWordDocuments,0x0E,DISPATCH_METHOD,lcid);
       if(pWordDocument)
       {
          pWordSelection=GetDispatchObject(pWordApp,0x05,DISPATCH_PROPERTYGET,lcid);
          if(pWordSelection)
          {
             wcscpy(szText,L"Hello, World!");
             TypeText(pWordSelection,szText,lcid);
             pWordSelection->Release();
             getchar();
          }
          pWordDocument->Release();
       }
       pWordDocuments->Release();
    }
    WordClose(pWordApp,lcid);
    pWordApp->Release();
 }
 CoUninitialize();

 return 0;
}


This is just to get you started. You'll note at top an include file WordFunctions.h. Here is that file...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// WordFunctions.h
#ifndef WordFunctions_h
#define WordFunctions_h

enum WdViewType
{
  wdNormalView               = 1,
  wdOutlineView              = 2,
  wdPrintView                = 3,
  wdPrintPreview             = 4,
  wdMasterView               = 5,
  wdWebView                  = 6
};


enum WdSeekView
{
  wdSeekMainDocument         = 0,
  wdSeekPrimaryHeader        = 1,
  wdSeekFirstPageHeader      = 2,
  wdSeekEvenPagesHeader      = 3,
  wdSeekPrimaryFooter        = 4,
  wdSeekFirstPageFooter      = 5,
  wdSeekEvenPagesFooter      = 6,
  wdSeekFootnotes            = 7,
  wdSeekEndnotes             = 8,
  wdSeekCurrentPageHeader    = 9,
  wdSeekCurrentPageFooter    = 10
};


enum WdPageNumberAlignment
{
  wdAlignPageNumberLeft      = 0,
  wdAlignPageNumberCenter    = 1,
  wdAlignPageNumberRight     = 2,
  wdAlignPageNumberInside    = 3,
  wdAlignPageNumberOutside   = 4
};


enum WdParagraphAlignment
{
  wdAlignParagraphLeft       = 0,
  wdAlignParagraphCenter     = 1,
  wdAlignParagraphRight      = 2,
  wdAlignParagraphJustify    = 3,
  wdAlignParagraphDistribute = 4,
  wdAlignParagraphJustifyMed = 5,
  wdAlignParagraphJustifyHi  = 7,
  wdAlignParagraphJustifyLow = 8
};


enum WdUnderline
{
  wdUnderlineNone            = 0,
  wdUnderlineSingle          = 1,
  wdUnderlineWords           = 2,
  wdUnderlineDouble          = 3,
  wdUnderlineDotted          = 4,
  wdUnderlineThick           = 6,
  wdUnderlineDash            = 7,
  wdUnderlineDotDash         = 9,
  wdUnderlineDotDotDash      = 10,
  wdUnderlineWavy            = 11,
  wdUnderlineWavyHeavy       = 27,
  wdUnderlineDottedHeavy     = 20,
  wdUnderlineDashHeavy       = 23,
  wdUnderlineDotDashHeavy    = 25,
  wdUnderlineDotDotDashHeavy = 26,
  wdUnderlineDashLong        = 39,
  wdUnderlineDashLongHeavy   = 55,
  wdUnderlineWavyDouble      = 43
};


enum WdBreakType
{
  wdSectionBreakNextPage     = 2,
  wdSectionBreakContinuous   = 3,
  wdSectionBreakEvenPage     = 4,
  wdSectionBreakOddPage      = 5,
  wdLineBreak                = 6,
  wdPageBreak                = 7,
  wdColumnBreak              = 8,
  wdLineBreakClearLeft       = 9,
  wdLineBreakClearRight      = 10,
  wdTextWrappingBreak        = 11
};


enum WdOrientation
{
  wdOrientPortrait           = 0,
  wdOrientLandscape          = 1
};


enum
{
  wdPaper10x14               = 0,
  wdPaper11x17               = 1,
  wdPaperLetter              = 2,
  wdPaperLetterSmall         = 3,
  wdPaperLegal               = 4,
  wdPaperExecutive           = 5,
  wdPaperA3                  = 6,
  wdPaperA4                  = 7,
  wdPaperA4Small             = 8,
  wdPaperA5                  = 9,
  wdPaperB4                  = 10,
  wdPaperB5                  = 11,
  wdPaperCSheet              = 12,
  wdPaperDSheet              = 13,
  wdPaperESheet              = 14,
  wdPaperFanfoldLegalGerman  = 15,
  wdPaperFanfoldStdGerman    = 16,
  wdPaperFanfoldUS           = 17,
  wdPaperFolio               = 18,
  wdPaperLedger              = 19,
  wdPaperNote                = 20,
  wdPaperQuarto              = 21,
  wdPaperStatement           = 22,
  wdPaperTabloid             = 23,
  wdPaperEnvelope9           = 24,
  wdPaperEnvelope10          = 25,
  wdPaperEnvelope11          = 26,
  wdPaperEnvelope12          = 27,
  wdPaperEnvelope14          = 28,
  wdPaperEnvelopeB4          = 29,
  wdPaperEnvelopeB5          = 30,
  wdPaperEnvelopeB6          = 31,
  wdPaperEnvelopeC3          = 32,
  wdPaperEnvelopeC4          = 33,
  wdPaperEnvelopeC5          = 34,
  wdPaperEnvelopeC6          = 35,
  wdPaperEnvelopeC65         = 36,
  wdPaperEnvelopeDL          = 37,
  wdPaperEnvelopeItaly       = 38,
  wdPaperEnvelopeMonarch     = 39,
  wdPaperEnvelopePersonal    = 40,
  wdPaperCustom              = 41
};


void SetVisible(IDispatch* pWordApp, LCID lcid);
void TypeText(IDispatch* pWordSelection, wchar_t* pStr, LCID lcid);
HRESULT SetFontName(IDispatch* pFont, wchar_t* szFontName, LCID lcid);
HRESULT SetFontSize(IDispatch* pFont, float& sngSize, LCID lcid);
void TypeParagraph(IDispatch* pWordSelection, LCID lcid);
void SetMargin(IDispatch* pPageSetup, LCID lcid, float& sngMargin, wchar_t cMargin);
IDispatch* GetPageNumber(IDispatch* pPageNumbers, LCID lcid);
IDispatch* AddHyperlink(IDispatch* pHyperlinks, IDispatch* pRange, wchar_t* szHyperLink, LCID lcid);
void WordClose(IDispatch* pWordApp, LCID lcid);
IDispatch* GetDispatchObject(IDispatch* pCallerObject, DISPID dispid, WORD wFlags, LCID lcid);
HRESULT SetDispIntProperty(IDispatch* pCallerObject, DISPID dispid, int iProperty, LCID lcid);
void InsertPageBreak(IDispatch* pWordSelection, LCID lcid);
HRESULT SaveAs(IDispatch* pWordDocument, wchar_t* szFilename, LCID lcid);

#endif 


Those functions are in a seperate "WordFunctions.cpp" file which you'll have to include in your project to get it to run. Next post is that...

continued...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
//WordFunctions.cpp
#ifndef   UNICODE
   #define   UNICODE
#endif
   #ifndef   _UNICODE
#define   _UNICODE
#endif
#include <windows.h>
#include <cstdio>
#include "Strings.h"
#include "WordFunctions.h"


void SetVisible(IDispatch* pWordApp, LCID lcid)
{
 VARIANT         vArgArray[1];
 DISPPARAMS      DispParams;
 DISPID          dispidNamed;
 VARIANT         vResult;

 VariantInit(&vArgArray[0]);
 vArgArray[0].vt                = VT_BOOL;
 vArgArray[0].boolVal           = TRUE;
 dispidNamed                    = DISPID_PROPERTYPUT;
 DispParams.rgvarg              = vArgArray;
 DispParams.rgdispidNamedArgs   = &dispidNamed;
 DispParams.cArgs               = 1;
 DispParams.cNamedArgs          = 1;
 VariantInit(&vResult);
 pWordApp->Invoke(23,IID_NULL,lcid,DISPATCH_PROPERTYPUT,&DispParams,&vResult,NULL,NULL);
}


void TypeText(IDispatch* pWordSelection, wchar_t* pStr, LCID lcid)
{
 VARIANT         vArgArray[1];
 VARIANT         vResult;
 DISPPARAMS      DispParams;
 DISPID          dispidNamed;

 VariantInit(&vResult);
 vArgArray[0].vt                = VT_BSTR;
 vArgArray[0].bstrVal           = SysAllocString(pStr);
 DispParams.rgvarg              = vArgArray;
 DispParams.rgdispidNamedArgs   = &dispidNamed;
 DispParams.cArgs               = 1;
 DispParams.cNamedArgs          = 0;
 pWordSelection->Invoke(0x000001fb,IID_NULL,lcid,DISPATCH_METHOD,&DispParams,&vResult,NULL,NULL);
 VariantClear(&vArgArray[0]);
}


HRESULT SetFontName(IDispatch* pFont, wchar_t* szFontName, LCID lcid)
{
 VARIANT         vArgArray[1];
 VARIANT         vResult;
 DISPPARAMS      DispParams;
 DISPID          dispidNamed=0;
 HRESULT         hr;

 VariantInit(&vResult);
 vArgArray[0].vt                = VT_BSTR;
 vArgArray[0].bstrVal           = SysAllocString(szFontName);
 DispParams.rgvarg              = vArgArray;
 DispParams.rgdispidNamedArgs   = &dispidNamed;
 DispParams.cArgs               = 1;
 DispParams.cNamedArgs          = 0;
 pFont->Invoke(0x0000008e,IID_NULL,lcid,DISPATCH_PROPERTYPUT,&DispParams,&vResult,NULL,NULL);
 hr=VariantClear(&vArgArray[0]);

 return hr;
}


HRESULT SetFontSize(IDispatch* pFont, float& sngSize, LCID lcid)
{
 VARIANT         vArgArray[1];
 DISPPARAMS      DispParams;
 DISPID          dispidNamed=0;
 VARIANT         vResult;
 HRESULT         hr;

 VariantInit(&vResult);
 VariantInit(&vArgArray[0]);
 vArgArray[0].vt                = VT_R4 | VT_BYREF;
 vArgArray[0].pfltVal           = &sngSize;
 dispidNamed                    = DISPID_PROPERTYPUT;
 DispParams.rgvarg              = vArgArray;
 DispParams.rgdispidNamedArgs   = &dispidNamed;
 DispParams.cArgs               = 1;
 DispParams.cNamedArgs          = 0;
 hr=pFont->Invoke(0x8D,IID_NULL,lcid,DISPATCH_PROPERTYPUT,&DispParams,&vResult,NULL,NULL);

 return hr;
}


void TypeParagraph(IDispatch* pWordSelection, LCID lcid)
{
 DISPPARAMS   NoArgs     = {NULL,NULL,0,0};
 VARIANT      vResult;

 VariantInit(&vResult);
 pWordSelection->Invoke(0x00000200,IID_NULL,lcid,DISPATCH_METHOD,&NoArgs,&vResult,NULL,NULL);
}


void SetMargin(IDispatch* pPageSetup, LCID lcid, float& sngMargin, wchar_t cMargin)
{
 VARIANT                        vArgArray[1];
 DISPPARAMS                     DispParams;
 DISPID                         dispidNamed=0;
 VARIANT                        vResult;
 int                            iDispatchId;

 VariantInit(&vArgArray[0]);
 vArgArray[0].vt              = VT_R4 | VT_BYREF;
 vArgArray[0].pfltVal         = &sngMargin;
 dispidNamed                  = DISPID_PROPERTYPUT;
 DispParams.rgvarg            = vArgArray;
 DispParams.rgdispidNamedArgs = &dispidNamed;
 DispParams.cArgs             = 1;
 DispParams.cNamedArgs        = 0;
 VariantInit(&vResult);
 switch(cMargin)
 {
   case L'b':
     iDispatchId=0x65;
     break;
   case L't':
     iDispatchId=0x64;
     break;
   case L'l':
     iDispatchId=0x66;
     break;
   case L'r':
     iDispatchId=0x67;
     break;
 }
 pPageSetup->Invoke(iDispatchId,IID_NULL,lcid,DISPATCH_PROPERTYPUT,&DispParams,&vResult,NULL,NULL);
}



IDispatch* GetPageNumber(IDispatch* pPageNumbers, LCID lcid)
{
 VARIANT         vArgArray[2];
 DISPPARAMS      DispParams;
 DISPID          dispidNamed=0;
 VARIANT         vResult;
 HRESULT         hr;

 VariantInit(&vArgArray[0]);
 vArgArray[0].vt                  = VT_BOOL;
 vArgArray[0].boolVal             = TRUE;

 VariantInit(&vArgArray[1]);
 vArgArray[1].vt                  = VT_I2;
 vArgArray[1].boolVal             = wdAlignPageNumberRight;

 DispParams.rgvarg                = vArgArray;
 DispParams.rgdispidNamedArgs     = &dispidNamed;
 DispParams.cArgs                 = 2;
 DispParams.cNamedArgs            = 0;
 VariantInit(&vResult);

 hr=pPageNumbers->Invoke(0x00000065,IID_NULL,lcid,DISPATCH_METHOD,&DispParams,&vResult,NULL,NULL);
 if(FAILED(hr))
    return NULL;
 else
    return vResult.pdispVal;
}



IDispatch* AddHyperlink(IDispatch* pHyperlinks, IDispatch* pRange, wchar_t* szHyperLink, LCID lcid)
{
 VARIANT         vArgArray[2];
 DISPPARAMS      DispParams;
 DISPID          dispidNamed=2;
 VARIANT         vResult;
 HRESULT         hr;

 VariantInit(&vArgArray[0]);
 vArgArray[0].vt                  = VT_BSTR;
 vArgArray[0].bstrVal             = SysAllocString(szHyperLink);
 VariantInit(&vArgArray[1]);
 vArgArray[1].vt                  = VT_DISPATCH;
 vArgArray[1].pdispVal            = pRange;
 DispParams.rgvarg                = vArgArray;
 DispParams.rgdispidNamedArgs     = &dispidNamed;
 DispParams.cArgs                 = 2;
 DispParams.cNamedArgs            = 0;
 VariantInit(&vResult);
 hr=pHyperlinks->Invoke(0x00000065,IID_NULL,lcid,DISPATCH_METHOD,&DispParams,&vResult,NULL,NULL);
 VariantClear(&vArgArray[0]);
 if(FAILED(hr))
    return NULL;
 else
    return vResult.pdispVal;
}


void WordClose(IDispatch* pWordApp, LCID lcid)
{
 DISPPARAMS NoArgs = {NULL,NULL,0,0};
 pWordApp->Invoke(1105,IID_NULL,LOCALE_USER_DEFAULT,DISPATCH_METHOD,&NoArgs,NULL,NULL,NULL);  // Close
}


IDispatch* GetDispatchObject(IDispatch* pCallerObject, DISPID dispid, WORD wFlags, LCID lcid)
{
 DISPPARAMS   NoArgs     = {NULL,NULL,0,0};
 VARIANT      vResult;
 HRESULT      hr;

 VariantInit(&vResult);
 hr=pCallerObject->Invoke(dispid,IID_NULL,lcid,wFlags,&NoArgs,&vResult,NULL,NULL);
 if(FAILED(hr))
    return NULL;
 else
    return vResult.pdispVal;
}


HRESULT SetDispIntProperty(IDispatch* pCallerObject, DISPID dispid, int iProperty, LCID lcid)
{
 VARIANT         vArgArray[1];
 DISPPARAMS      DispParams;
 DISPID          dispidNamed;
 VARIANT         vResult;
 HRESULT         hr;

 VariantInit(&vArgArray[0]);
 vArgArray[0].vt                = VT_I4;
 vArgArray[0].lVal              = iProperty;
 dispidNamed                    = DISPID_PROPERTYPUT;
 DispParams.rgvarg              = vArgArray;
 DispParams.rgdispidNamedArgs   = &dispidNamed;
 DispParams.cArgs               = 1;
 DispParams.cNamedArgs          = 1;
 VariantInit(&vResult);
 hr=pCallerObject->Invoke(dispid,IID_NULL,lcid,DISPATCH_PROPERTYPUT,&DispParams,&vResult,NULL,NULL);

 return hr;
}


void InsertPageBreak(IDispatch* pWordSelection, LCID lcid)
{
 DISPID      dispidNamed=0;
 VARIANT     vArgArray[1];
 DISPPARAMS  DispParams;
 VARIANT     vResult;

 VariantInit(&vResult);
 vArgArray[0].vt=VT_I4;
 vArgArray[0].lVal=wdPageBreak;
 DispParams.rgvarg=vArgArray;
 DispParams.rgdispidNamedArgs=&dispidNamed;
 DispParams.cArgs=1;
 DispParams.cNamedArgs=0;
 pWordSelection->Invoke(0x7a,IID_NULL,lcid,DISPATCH_METHOD,&DispParams,&vResult,NULL,NULL);
 VariantClear(&vArgArray[0]);
}


HRESULT SaveAs(IDispatch* pWordDocument, wchar_t* szFilename, LCID lcid)
{
 VARIANT     vArgArray[1];
 VARIANT     vResult;
 DISPPARAMS  DispParams;
 DISPID      dispidNamed=0;
 HRESULT     hr;

 VariantInit(&vResult);
 vArgArray[0].vt=VT_BSTR;
 vArgArray[0].bstrVal=SysAllocString(szFilename);
 DispParams.rgvarg=vArgArray;
 DispParams.rgdispidNamedArgs=&dispidNamed;
 DispParams.cArgs= 1;
 DispParams.cNamedArgs          = 0;
 hr=pWordDocument->Invoke(0x00000066,IID_NULL,lcid,DISPATCH_METHOD,&DispParams,&vResult,NULL,NULL);
 VariantClear(&vArgArray[0]);

 return hr;
}
This will compile for you but it won't link. Next I'll post the linkage instructions...

(hint:ole32.lib, oleaut32.lib, and uuid.lib).

And after that I'll show how to incorporate it within your MFC Dialog app.
Last edited on
Continuing, some of the functions I used above are not in kernel32.dll or anything else most console programs link with, so you have to tell the linker where they are at. Various versions of Visual Studio have different interfaces for informing the linker of these facts. If you were compiling from the command line you would simply add ...

ole32.lib oleaut32.lib uuid.lib

to the compilation string fed into cl. I compiled the above program with mingw x64 and ended up with about a 20 k stand alone executable. With the older 4.4 series x86 mingw its only about 10k.

But I know you want a GUI app, so lets make the necessary modifications to the above code to work within a GUI framework.

I haven't done MFC or CString work since Visual Studio 6 circa 1998 or so, but as I last recall MFC included the CString Class within the MFC dlls. I think they might have changed that, but since I don't use any of that stuff it doesn't matter too much to me. For most folks the C++ Std. Lib's string and wstring classes are more advantaegous to use. I actually use my own String Class I wrote years ago. Strings only show up in "WordFunctions.cpp" in a couple places. You can see that wherever you see wchar_t*. For example, here ...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void TypeText(IDispatch* pWordSelection, wchar_t* pStr, LCID lcid)
{
 VARIANT         vArgArray[1];
 VARIANT         vResult;
 DISPPARAMS      DispParams;
 DISPID          dispidNamed;

 VariantInit(&vResult);
 vArgArray[0].vt                = VT_BSTR;
 vArgArray[0].bstrVal           = SysAllocString(pStr);
 DispParams.rgvarg              = vArgArray;
 DispParams.rgdispidNamedArgs   = &dispidNamed;
 DispParams.cArgs               = 1;
 DispParams.cNamedArgs          = 0;
 pWordSelection->Invoke(0x000001fb,IID_NULL,lcid,DISPATCH_METHOD,&DispParams,&vResult,NULL,NULL);
 VariantClear(&vArgArray[0]);
}


I changed my code for presenting it here because I felt that wchar_t* were a bit more string class agnostic than any other way of doing it. My code actually looks like this ...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void TypeText(IDispatch* pWordSelection, String& strText, LCID lcid)
{
 VARIANT         vArgArray[1];
 VARIANT         vResult;
 DISPPARAMS      DispParams;
 DISPID          dispidNamed;

 VariantInit(&vResult);
 vArgArray[0].vt                = VT_BSTR;
 vArgArray[0].bstrVal           = SysAllocString(strText.lpStr());
 DispParams.rgvarg              = vArgArray;
 DispParams.rgdispidNamedArgs   = &dispidNamed;
 DispParams.cArgs               = 1;
 DispParams.cNamedArgs          = 0;
 pWordSelection->Invoke(0x000001fb,IID_NULL,lcid,DISPATCH_METHOD,&DispParams,&vResult,NULL,NULL);
 VariantClear(&vArgArray[0]);
}


What the difference is is that instead of wchar_t* pStr I use String& strText. That entity needs to be used to initialize a BSTR in a call to SysAllocString() as you can see. I borrowed from MFC's CString Class their CString::lpstr() member for my String Class, as you can see. The C++ Std. Lib's String Class - string, has a ...

 
string::c_str() 


...member thar returns a pointer to the null terminated C String held within the string class. So in the code I'm presenting below, which is fully compilable/linkable code, if you really want to use it within an MFC / CString context, all you need do is make a few simple substitutions and everything will work fine. I'd personally never ever use anything whatsoever from MFC or the C++ Standard Library because as far as I'm concerned its all worthless bloatware.

So below is a pure SDK WinApi style program which simply does what you described in your 1st post, i.e., it creates a window with a button on it that is codeless as for now (until we fill the event procedure). If you care to build this skeleton you'll need to tell Visual Studio you want to create an 'empty' GUI Frame based project with no files in it...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
//Main.cpp
#ifndef UNICODE
#define  UNICODE
#endif
#ifndef _UNICODE
#define  _UNICODE
#endif
#include <windows.h>
#define IDC_WRITE_TO_WORD  1500


void Button_Click(HWND hWnd)
{
 MessageBox(hWnd,L"You Want To Write Something To Word!",L"Button Click Report!",MB_OK);
}


LRESULT CALLBACK fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
 switch(msg)
 {
   case WM_CREATE:
    {
        HINSTANCE hInst=((LPCREATESTRUCT)lParam)->hInstance;
        HWND hCtl=CreateWindowEx(0,L"button",L"Write To Word",WS_CHILD|WS_VISIBLE,72,55,160,30,hwnd,(HMENU)IDC_WRITE_TO_WORD,hInst,0);
        return 0;
    }
   case WM_COMMAND:
    {
        Button_Click(hwnd);
        return 0;
    }
   case WM_DESTROY:
    {
       PostQuitMessage(0);
       return 0;
    }
 }

 return (DefWindowProc(hwnd, msg, wParam, lParam));
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{
 wchar_t szClassName[]=L"Form1";
 WNDCLASSEX wc;
 MSG messages;
 HWND hWnd;

 memset(&wc,0,sizeof(wc));
 wc.lpszClassName = szClassName;
 wc.lpfnWndProc   = fnWndProc;
 wc.cbSize        = sizeof(WNDCLASSEX);
 wc.hbrBackground = (HBRUSH)COLOR_BTNSHADOW;
 wc.hInstance     = hInstance;
 RegisterClassEx(&wc);
 hWnd=CreateWindowEx(0,szClassName,szClassName,WS_OVERLAPPEDWINDOW,200,175,320,200,HWND_DESKTOP,0,hInstance,0);
 ShowWindow(hWnd,iShow);
 while(GetMessage(&messages,NULL,0,0))
 {
    TranslateMessage(&messages);
    DispatchMessage(&messages);
 }

 return messages.wParam;
}


So what we'll do now is try to fill the Button_Click(HWND hWnd) procedure with code to open Word and write the string "Hello, World!" to it. Next post is that app...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
//Main.cpp
#ifndef UNICODE
#define  UNICODE
#endif
#ifndef _UNICODE
#define  _UNICODE
#endif
#include <windows.h>
#include "WordFunctions.h"
#define IDC_WRITE_TO_WORD  1500


void Button_Click(HWND hWnd)
{
 const CLSID CLSID_WordApplication = {0x000209FF,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
 const IID   IID_Application       = {0x00020970,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
 IDispatch*  pWordApp              = NULL;
 IDispatch*  pWordDocuments        = NULL;
 IDispatch*  pWordDocument         = NULL;
 IDispatch*  pWordSelection        = NULL;
 wchar_t     szText[512];
 LCID        lcid;
 HRESULT     hr;

 lcid=GetUserDefaultLCID();
 hr=CoCreateInstance(CLSID_WordApplication, NULL, CLSCTX_LOCAL_SERVER, IID_Application, (void**)&pWordApp);
 if(SUCCEEDED(hr))
 {
    SetVisible(pWordApp,lcid);
    pWordDocuments=GetDispatchObject(pWordApp,0x06,DISPATCH_PROPERTYGET,lcid);
    if(pWordDocuments)
    {
       pWordDocument=GetDispatchObject(pWordDocuments,0x0E,DISPATCH_METHOD,lcid);
       if(pWordDocument)
       {
          pWordSelection=GetDispatchObject(pWordApp,0x05,DISPATCH_PROPERTYGET,lcid);
          if(pWordSelection)
          {
             wcscpy(szText,L"Hello, World!");
             TypeText(pWordSelection,szText,lcid);
             pWordSelection->Release();
          }
          pWordDocument->Release();
       }
       pWordDocuments->Release();
    }
    pWordApp->Release();
 }
}


LRESULT CALLBACK fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
 switch(msg)
 {
   case WM_CREATE:
    {
        HINSTANCE hInst=((LPCREATESTRUCT)lParam)->hInstance;
        HWND hCtl=CreateWindowEx(0,L"button",L"Write To Word",WS_CHILD|WS_VISIBLE,72,55,160,30,hwnd,(HMENU)IDC_WRITE_TO_WORD,hInst,0);
        CoInitialize(NULL);
        return 0;
    }
   case WM_COMMAND:
    {
        Button_Click(hwnd);
        return 0;
    }
   case WM_DESTROY:
    {
       PostQuitMessage(0);
       CoUninitialize();
       return 0;
    }
 }

 return (DefWindowProc(hwnd, msg, wParam, lParam));
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{
 wchar_t szClassName[]=L"Form1";
 WNDCLASSEX wc;
 MSG messages;
 HWND hWnd;

 memset(&wc,0,sizeof(wc));
 wc.lpszClassName = szClassName;
 wc.lpfnWndProc   = fnWndProc;
 wc.cbSize        = sizeof(WNDCLASSEX);
 wc.hbrBackground = (HBRUSH)COLOR_BTNSHADOW;
 wc.hInstance     = hInstance;
 RegisterClassEx(&wc);
 hWnd=CreateWindowEx(0,szClassName,szClassName,WS_OVERLAPPEDWINDOW,200,175,320,200,HWND_DESKTOP,0,hInstance,0);
 ShowWindow(hWnd,iShow);
 while(GetMessage(&messages,NULL,0,0))
 {
    TranslateMessage(&messages);
    DispatchMessage(&messages);
 }

 return messages.wParam;
}


The above code needs to link with kernel32.lib, gdi32.lib, user32.lib, ole32.lib, oleaut32.lib, and uuid.lib. That should compile to no more than 20k as a stand alone executable. Modified to use string classes in MFC or C++ Std. Lib and you'll be looking at several hundred k to several MB.
Last edited on
Topic archived. No new replies allowed.