|
|
Sebas,
It looks like you have done some work on MS Word automation more like to what I'm trying to do. Can you help? I have done word automation in VB but I am new to C++ and running into problems.
|
|
|
|
|
What do you need to accomplish ? What problems are you facing ?
If you've done Word automation in VB, you know a whole lot of the work already. All Office applications, whether running or stopped, expose an interface that can be used to invoke the methods. The procedure is similar: initialize COM (CoInitialize-call), either create a new object (CoCreateInstance) or try to find an existing one (GetActiveObject).
When the object is created, you always have access to the IUnknown interface. You can use this interface to query for alternative interfaces on the object (see the Word Automation Model reference for a comprehensive list of interfaces) to accomplish your needs.
Remember to release all interfaces, so that the object gets terminated and will not remain in memory after your program execution has stopped.
-Antti Keskinen
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|
For starters, I need a starting push. Do I start with a wrapper class with a type library or something else? Any reference code on how to initialize COM,instantiate
a COM object will help...
|
|
|
|
|
With Visual Studio, you get a handy little application installed that's called 'OLEViewer'. This program can be easily used to browse through the COM libraries installed on your machine. For example, if you go there, and find the Word Automation Server, you can fire up Word by creating an instance of that server. Know, however that if you start Word this way, it will not display it's user interface. But you can use CTRL+ALT+DEL and see 'WinWord.exe', which is the Word's executable, running there. Word is running, acting as an automation server, but just doesn't show an UI.
Another tool, called 'Runtime Object Table Viewer' or 'ROT Viewer' is also installed with Visual Studio. It probably doesn't have a shortcut, but you can easily add one. The name of the executable is 'irotview.exe'. Find it on your machine and add a shortcut. This application shows all running objects that are registered with OLE/COM. In english, if you fire up Word, it starts it's own automation server at the same time, and this server is registered to OLE/COM. So, if you run Word, you'll see it's automation server instance there.
I can create a small sample application that will help you get started. It will show step-by-step how to initialize COM, and allow you to query for a running Word instance or start a new instance, and then shut this instance down. It should take a few days. I'll send it to your e-mail when it's done.
-Antti Keskinen
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|
Thanks a lot, I await your sample app. I forgot to mention that my environment is Visual C++ 7.1
|
|
|
|
|
Dear all,
I checked through the network, it appears need SOAP Client SDK which only comes with XP Pro. Just wondering is there any SOAP Client which installed automatically with .NET Framework or XP Home+.
Thank you in advance.
|
|
|
|
|
Dear Sir,
I actually want some code which can get the Processor's or Mainboard's Serial Number.
Regards,
Kashif Mughal.
|
|
|
|
|
Go to Intel's website and try to find an article on how to retrieve the Processor Serial Number if there is one. I have some code from last year which I don't remember if it works or not and since I cannot compile it and test it right now I will leave that up to you. Sorry, but I don't remember much about getting a number from the motherboard. To my knowledge you can dump the BIOS info (I don't even remember how to do) and somewhere in there you can find the number of the motherboard but my memory on that area is very murky, so I cannot help you at all.
CString strPSN;
BOOL bPSNExists;
LARGE_INTEGER liPI64, liPI32;
__asm
{
mov eax, 01h;
cpuid;
mov liPI64.LowPart, edx;
}
if( (liPI64.LowPart & 0x00040000) > 0 )
bPSNExists = TRUE;
else
bPSNExists = FALSE;
if( bPSNExists )
{
__asm
{
mov eax, 01h;
cpuid;
mov liPI32.LowPart, eax;
mov eax, 03h;
cpuid;
mov liPI64.HighPart, edx;
mov liPI64.LowPart, ecx;
}
strPSN.Format( "%08x-%08x-%08x", liPI32.LowPart,
liPI64.HighPart, liPI64.LowPart );
}
// Afterall, I realized that even my comment lines have bugs
If the sun were to blow up, it would take us 7-8 minutes to realize it.
|
|
|
|
|
See here.
A rich person is not the one who has the most, but the one that needs the least.
|
|
|
|
|
Hi!
Is there a way to convert key codes like VK_ENTER or DIK_ENTER (DirectInput), e.g. to a char/string "Enter"?
One more question: How do I save a WPARAM value (like the VK_ codes are passed) into a config file and read back the value?
thanks in advance
modified 12-Sep-18 21:01pm.
|
|
|
|
|
There is no ready-built conversion routine, but you can easily construct one yourself. Just compare the virtual-key value and format a CString object to represent the text string, like this
CString str;<br />
<br />
if ( vKey == VK_ENTER )<br />
str.Format("Enter");
The WPARAM value, in the 64-bit compatible environment, is typedeffed as UINT_PTR. This, on a 32-bit compiler, is typedeffed to standard type integer. Thus, the WPARAM value is an integer. You can directly convert the virtual-key code into an integer, then into a character string by using, for example, _itoa routine. Now, having the integer as a character string, you can write it into a file. The same process works just as good in reverse.
-Antti Keskinen
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|
Hi all,
I have created a new ATL-COM Object (supporting MFC)
I've defined a method that returns the workspace of the current project.
Here is the code i am using:
CWinApp* pApp = AfxGetApp();
ASSERT(NULL != pApp);
CString szWorkspace(_T(""));
POSITION posdt = pApp->GetFirstDocTemplatePosition();
while (NULL != posdt)
{
CDocTemplate* pdt = pApp->GetNextDocTemplate(posdt);
if (0 == strcmp("CProjectWorkspaceDocTemplate",
pdt->GetRuntimeClass()->m_lpszClassName))
{
POSITION posdoc = pdt->GetFirstDocPosition();
if (NULL == posdoc)
break;
CDocument* pdoc = pdt->GetNextDoc(posdoc);
if (NULL == pdoc)
break;
szWorkspace = pdoc->GetPathName();
if (!szWorkspace.IsEmpty())
break;
}
}
trouble is , when i debug it this line returns NULL:
POSITION posdt = pApp->GetFirstDocTemplatePosition();
Why does it never succeed in getting the first doc template position?
can any1 help me here?
thanks in advanced
Yaron
Ask not what your application can do for you,
Ask what you can do for your application
|
|
|
|
|
According the MSDN Library:
POSITION GetFirstDocTemplatePosition( ) const;
Return Value
A POSITION value that can be used for iteration or object pointer retrieval; NULL if the list is empty.
Thus, logical deduction is that your document template is empty. Also, you're asking for the document template position from your ATL-COM application. In order to access the IDE from your application, see this extract from MSDN.
Add-ins are time- and labor-saving applications that attach to and are used within the IDE. They are COM objects that implement the IDTExtensibility2 Interface and communicate with the IDE through the automation object model contained in the EnvDTE type library (dte.olb)
Like said, you can use the provided automation object model (DTE) to access the Visual Studio IDE. This object model is located in the dte.olb file, and it's COM name is 'Microsoft Development Environment', added with a version number. You must use this approach if you're not writing an add-in. If you are, the DTE object is provided to you automatically.
To actually utilize the DTE object, here is a code fragment that first loads the Microsoft Development Environment 7.0 object, then requests a pointer to the running instance of Visual Studio .NET:
#import "libid:80cc9f66-e7d8-4ddd-85b6-d9e6cd0e93e2" version("7.0") lcid("0") raw_interfaces_only named_guids
#pragma warning( default : 4278 )
using namespace EnvDTE;
CComPtr<EnvDTE::_DTE> m_pDTE;
CLSID clsid;
CLSIDFromProgID(L"VisualStudio.DTE.7.1",&clsid);
CComPtr<IUnknown> punk;
HRESULT hr = GetActiveObject(clsid,NULL,&punk);
m_pDTE = punk; The same approach ideas should work just as well for other environments, just the version numbers change. See your own IDE documentation for the correct object name, or browse through the COM object adder.
-Antti Keskinen
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|
thanks for the reply...
you said : "If you are, the DTE object is provided to you automatically."
how? where?
can you show me an example?
thanks again
Yaron
Ask not what your application can do for you,
Ask what you can do for your application
|
|
|
|
|
If you are writing an add-in, your add-in must implement an interface called IDTExtensibility2 . OnConnection is a method on this interface. This method has one interesting parameter, called IDispatch* pDispatch. This is a pointer to the IDispatch interface of the running IDE.
The IDispatch interface pointer is used in combination with the COleDispDriver class to implement an easy and flexible way to communicate with the IDE. When creating an add-in, use the ClassView/ClassWizard to add a new MFC class from type library. Select 'Microsoft Development Environment' as the type library source. If you cannot find this entry in the registry, search your machine for the earlier mentioned dte.olb file, and implement the class from there.
Now, the wizard creates a wrapper class for you, based on the type library. The most interesting member of our newly created class is m_lpDispatch implemented in the base class. Now, assuming you have the OnConnection method implemented (you MUST have, otherwise your add-in will not work), here is a code extract on how to put it into use:
HRESULT __stdcall MyDispatchInterface::OnConnection( IDispatch* Application, ext_ConnectMode ConnectMode, IDispatch* AddInInst, SAFEARRAY** custom
)
{
m_ptrMyDTEDispatchClass->AttachDispatch( (LPDISPATCH) Application );
} In the above example, m_ptrMyDTEDispatchClass is a pointer to the wizard-generated wrapper class, which is a static object in the actual add-in application class. You must create a pointer to this type of class as a member of MyDispatchInterface , thus allowing the interface class to access the object on the other class. Then we just attach the dispatch class to the provided IDispatch interface, that is coming from the IDE when the add-in is loaded.
Unfortunately I cannot give you a more concrete example right now, as I don't have any add-in source code available. Also, the example I am providing here applies for sure in the .NET versions of VS. I am unsure how it works on the VS 6.0/5.0 IDE, you must see the IDE-specific documentations.
-Antti Keskinen
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|
Well, for my leisure time, I quickly built a sample application that queries for the necessary interfaces, and then uses them a bit.
You can download the VS .NET solution and VS 6.0 workspace files from here[^].
The only difference is that the DTE IDispatch pointer is not provided automatically, so I query it myself. Not sure if it will run on your computer as is, but at least the source code is there.
Remember, I take no responsibility if running the app crashes your machine and you lose valuable work :P
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|
Hi, I really appreciate your help here
the example code has errors in compilation (which i've solved) and does not run properly due to the CLSIDFromProgID( L"VisualStudio.DTE", &VS_DTEID );
line which returns 0000-0000-0000-0000-0000
i am using the visual studio add in, and use OnConnection as you mentioned, can you point me from there how to obtain the WS path?
thanks again for all your help
Yaron
Ask not what your application can do for you,
Ask what you can do for your application
|
|
|
|
|
The errors happen because I use .NET version of VS, and you apparently have version 6.0/5.0 installed. You must search your own registry for the correct ProgID (Name) of the Microsoft Development Environment Object (DTE Object).
The IDispatch interface pointer that is provided to you points to the IDispatch interface of the DTE object. According to my MSDN Library copy, the DTE object has a method called Solution (wrapped as get_Solution) that provides you with a pointer to the IDispatch interface of the Solution object. The Solution object, again, has a method called FullName (wrapped as get_FullName) that gives you the full path name of the solution file.
You can then use any path parser class or function to parse the actual solution name from this string.
Note that this applies only to Visual Studio .NET. I will attempt to create a Visual Studio 6.0 compatible version today, when I have access to a 6.0 environment. Will post more information later.
-Antti Keskinen
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|
ok , now i am starting to understand....
but as you have mentioned, the solution is a .Net only, i need the coresponding VC++6 ......
so if you have the time maybe you can reply with the correct object and methods?
thanks again for all your help
Yaron
Ask not what your application can do for you,
Ask what you can do for your application
|
|
|
|
|
The VC++ 6.0 implements an IApplication interface. This interface allows access to a VC++ 6.0 object and it's sub-objects. These objects and how to automate tasks in VC6 are discussed in detail at an MSDN Link here[^].
Note, that I could not get the IApplication.ActiveProject method to work. It always caused a violation when ran. Instead, I built an example application that gets the project collection, queries for a project in the first slot, then gets this project's name.
You can download this example from here[^]. It is made completely with Visual Studio 6.0, so it should compile and run properly straight through. Remember, though that if you run the provided example application, you must have Visual Studio 6.0 running, and it must have a workspace and a project open. Otherwise the example app will crash !
You can add more wrappers for different objects in Visual Studio by using the ClassWizard. Just search your computer for a file named DEVSHL.DLL, then use the ClassWizard's 'Add -> From type library ' and specify the DEVSHL.DLL file. You will then be presented with a dialog showing the available interfaces.
Remember, that the ClassWizard automatically builds wrappers for the IDispatch interfaces of the available ones. Thus, if you want to access the IDispatch of IApplication, you choose 'IApplication' from the list, and code will be generated.
For the add-ins, the OnConnect method automatically receives a pointer to the IApplication interface. If you have an IDispatch wrapper for IApplication, you can use QueryInterface to ask for the interface IID_IDispatch from this interface. The returned LPDISPATCH can be used again in the AttachDispatch call of the wrapper class.
For further info, see the provided MSDN link and the comments in the source files.
-Antti Keskinen
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|
hi,
Now i see where you're getting.....indeed when i open a new project in VC++6 called 'dev-studio' i get a wrapper for all the methods....
i can retrieve the project name easily... the touble is (actually that was the trouble to begin with) i don't need the project path, i need the workspace path......
can you help me here?
thanks so much for other replies
Yaron
Ask not what your application can do for you,
Ask what you can do for your application
|
|
|
|
|
That is the oddity in the documentation. There doesn't seem to be a function available for getting the actual workspace object or it's name. I honestly do not know how to get the workspace name, but you can extract the path from the project path, as they are usually the same.
The .Net version has the _Solution interface, and this interface is applied everywhere else in Visual Studio environment. It allows easy access to the solution name. However, I don't know why the Visual C++ 6.0 doesn't implement this. Perhaps you could get the IApplication object (In VC6) and query it for the _Solution interface manually. I am not sure if it will work, though, and I seriously doubt it, but you can always try..
Perhaps it is completely impossible to the workspace name in VC6. For this, blame Microsoft
-Antti Keskinen
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|
this what leads me to the first code i've shown you:
CWinApp* pApp = AfxGetApp();
ASSERT(NULL != pApp);
CString szWorkspace(_T(""));
POSITION posdt = pApp->GetFirstDocTemplatePosition();
while (NULL != posdt)
{
CDocTemplate* pdt = pApp->GetNextDocTemplate(posdt);
if (0 == strcmp("CProjectWorkspaceDocTemplate",
pdt->GetRuntimeClass()->m_lpszClassName))
{
POSITION posdoc = pdt->GetFirstDocPosition();
if (NULL == posdoc) break;
CDocument* pdoc = pdt->GetNextDoc(posdoc);
if (NULL == pdoc) break;
szWorkspace = pdoc->GetPathName();
if (!szWorkspace.IsEmpty())
break;
}
}
this code does not work when i create a dev-studio add in using the wizard of VC++6....but this code does work! when i tried the windows tabs (d/l it from code project), it uses the WWhizIntefaceHelper the has the above method, and if i am placing a break point, at the above code, the line:
POSITION posdt = pApp->GetFirstDocTemplatePosition();
doesn't return NULL....my guess is that this project was not created using the dev-studio wizard.....
can you tell me how it was created then??? it must be COM- ATL - Object right???
if i will solve this, then i will solve my problem...
thanks again
Yaron
Ask not what your application can do for you,
Ask what you can do for your application
|
|
|
|
|
Ah, so..
You should've told me earlier about the article: reading it completely through offered a good set of knowledge on how the Visual C++ 6 works. For other possible readers, a link to the article is available here[^].
Like this article states, an MFC extension DLL can share the CWinApp object provided by a loading application. This theorem is used as a base on the concept that Visual C++ is a BIG MFC program that loads a few extension DLLs when it starts up. Nothing prevents us from writing Add-ins as extension DLLs instead of regular add-ins, which are generated by the Dev-Studio Add-In wizard.
In order to utilize the code piece placed there, you must generate your Add-in module by using the alternative code wizard mentioned in the article: "CoDeveloper's Extension Add-in Wizard", instead of using the built-in DevStudio Add-in Wizard. Modules created with the prior wizard have access to the CWinApp object of Visual C++, and can thus enumerate through it's document templates and so on.
Basically, to solve your problem and answer your question in a single sentence: use the CoDeveloper's wizard to generate your add-in instead of the built-in one, and then write the necessary code again. By using the alternative wizard, you have access to the CWinApp object of Visual C++. For more information on how it works, you should read the original article with careful thought. You can find the wizard accompanied in the ZIP file that is with the article. Just read the Readme file and install the wizard accordingly.
Unfortunately, you cannot write a seperate module that does the same. This means that the code examples I have posted cannot be altered to access the workspace name on a VC6 platform. The .Net version works, because VC .NET's Automation interface is much more sophisticated.
-Antti Keskinen
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|