I'm trying to package some of my MFC applications as Windows 10 apps using Desktop Bridge.
I am having no end of trouble getting my HTML help file (CHM) included and working with the installed program (new versions of VS don't include the help file, and using workaround to include that file results in a file that I don't have the rights to access).
So it makes me wonder about hosting the online help on my website. A couple of the issues that arise is how best to host multiple help topics, and how to override (on a application-wide basis) the behavior of accessing help topics. (My app is dialog-based.)
So I just wondered if anyone else has done this already. I'd be curious to review how these issues were addressed. I was not able to find anything online.
I do host my html help in a single document, using html anchors to get to the topic of interest. If you have multiple pages, adapt MyHelp accordingly.
I didn't actually use the Desktop Bridge but wondered if you have tried something like this:
BOOL CMyDialog::OnHelpInfo(HELPINFO* pHelpInfo)
{
MyHelp(_T("HIDD_MYDIALOG")); // HTML anchor goes here
return CDialog::OnHelpInfo(pHelpInfo);
}
...
// a global helper function for showing help
void MyHelp(LPCTSTR anchor)
{
extern CMyApp theApp;
TCHAR *cp, buffer[1000];
// look for the html document in the program directory
strcpy(buffer, _T("file:///"));
DWORD dw = GetModuleFileName(theApp.m_hInstance, buffer + strlen(buffer), sizeof(buffer));
if (cp = strrchr(buffer, '\\'))
{
strcpy(cp+1, _T("MyHelpDocument.htm#"));
strcat(cp+1, anchor);
// for some reason, I don't want the default browser to open, just the Internet Explorer
ShellExecute(NULL, _T("open"), _T("iexplore"), buffer, NULL, SW_SHOWNORMAL);
// or, for real online help, use just '_T("http://myurl.com/myonlinehelpdocument.html#") + anchor'
// instead of 'buffer' and ommit all before ShellExecute()
}
}
I'm not sure if ShellExecute will behave the way it used to in the shop app though. But certainly there will be a way to open a URL somehow. You might want to try if the Internet Explorer ActiveX works to display your help pages inside the app.
Related
I'm working on Visual Studio 2019 community, and I'm writing an MFC application in cpp. I want to add a functionality to the dialog box - such that when pressing a button it converts an existing xls file into pdf file. I've tried using the extension Aspose.Cells.Cpp and Aspose.PDF.Cpp with this code, but I get a lot of errors in the code of the DLL itself. I've also tried installing libHARU from here, but I didn't manage to make it work.
I've tried looking for another way to convert xls to pdf in MFC application in cpp, or another environment for creating desktop applications (which has some basic functionalities such as adding a pressing button in MFC, so I won't have to write everything from scratch with Win32 API), but I didn't find anything. Perhaps someone can explain to me how to perform this conversion in cpp so that I can use it when writing an MFC app, or could refer me to some useful information about another way of creating the application which supports this type of conversions?
You said in your comments to me that you can assume the user has Excel installed on his machine. If so, then you can use Excel's automation object model to manipulate Excel. You could do stuff like #import the type library and stuff...maybe that would make prettier C++. My experience, however, with driving Office apps is to stick more with just raw dispatch pointers. I've had less go wrong that way. This probably needs some more error checking and stuff, but that's up to you.
... and a big caveat. This is for an interactive app...which I halfway assume since you are using the MFC topic. With a service, Microsoft does not recommend you drive their Office applications in this manner. I tested this on one .xlsx file and it worked. Assume it will work for .xls as well. For other formats, you might need to use different import functions.
void ConvertFile(LPCWSTR lpszFileIn, LPCWSTR lpszFileOut)
{
CComDispatchDriver excel;
if (SUCCEEDED(excel.CoCreateInstance(_T("Excel.Application"), NULL, CLSCTX_LOCAL_SERVER)))
{
_variant_t vWorkbooks;
if (SUCCEEDED(excel.GetPropertyByName(L"Workbooks", &vWorkbooks)))
{
CComDispatchDriver workbooks(vWorkbooks.pdispVal);
_variant_t vWorksheet;
if (SUCCEEDED(workbooks.Invoke1(L"Open", &_variant_t(lpszFileIn), &vWorksheet)))
{
CComDispatchDriver worksheet(vWorksheet.pdispVal);
UINT xlTypePdf = 0;
HRESULT hr = worksheet.Invoke2(L"ExportAsFixedFOrmat", &_variant_t(xlTypePdf), &_variant_t(lpszFileOut), NULL);
if (FAILED(hr))
{
_com_error err(hr);
AfxMessageBox(err.ErrorMessage());
}
}
}
excel.Invoke0(L"Quit", NULL);
}
}
I'll give a solution, but this one doesn't use c++, just command line and LibreOffice app:
Use command line Libre Office tool: --convert-to
--convert-to output_file_extension[:output_filter_name] [--outdir output_dir] files
Batch convert files. If --outdir is not specified, then current working directory is used as output_dir.
Eg. --convert-to pdf *.doc
--convert-to pdf:writer_pdf_Export --outdir /home/user *.doc
More details about how to use this command you'll find here: https://help.libreoffice.org/Common/Starting_the_Software_With_Parameters
Later edit: Here is a sample of how to implement the above solution in a C++/MFC code:
STARTUPINFO si = { 0 };
si.cb = sizeof(si);
PROCESS_INFORMATION pi = { 0 };
sCommand.Format(_T("C:\\WINDOWS\\System32\\cmd.exe /c
C:\\LibreOffice\\program\\swriter.exe --convert-to pdf -outdir
c:\\temp\\ c:\\temp\\MyFile.doc"));
::CreateProcess(0, sCommand, 0, 0, TRUE, CREATE_NO_WINDOW, 0, 0, &si, &pi);
How do I get the list of open file handles by process id in C#?
I'm interested in digging down and getting the file names as well.
Looking for the programmatic equivalent of what process explorer does.
Most likely this will require interop.
Considering adding a bounty on this, the implementation is nasty complicated.
Ouch this is going to be hard to do from managed code.
There is a sample on codeproject
Most of the stuff can be done in interop, but you need a driver to get the filename cause it lives in the kernel's address space. Process Explorer embeds the driver in its resources. Getting this all hooked up from C# and supporting 64bit as well as 32, is going to be a major headache.
You can also run the command line app, Handle, by Mark Rusinovich, and parse the output.
Have a look at this file :
http://vmccontroller.codeplex.com/SourceControl/changeset/view/47386#195318
And use:
DetectOpenFiles.GetOpenFilesEnumerator(processID);
Demo:
using System;
using System.Diagnostics;
namespace OpenFiles
{
class Program
{
static void Main(string[] args)
{
using (var openFiles = VmcController.Services.DetectOpenFiles.GetOpenFilesEnumerator(Process.GetCurrentProcess().Id))
{
while (openFiles.MoveNext())
{
Console.WriteLine(openFiles.Current);
}
}
Console.WriteLine();
Console.ReadKey();
}
}
}
It has dependency over assembly System.EnterpriseServices
You can P/INVOKE into the NtQuerySystemInformation function to query for all handles and then go from there. This Google groups discussion has details.
Take a look at wj32's Process Hacker version 1, which can do what you asked, and more.
Handle is great program, and the link to codeproject is good.
#Brian
The reason for the code is that handle.exe is NOT redistributable. Nor do they release their source.
It looks as if .Net will not easily do this since it appears that an embedded device drive is requried to access the information. This cannot be done in .net without an unmanged DLL. It's relatviely deep kernel code when compared to typical .net coding. I'm surprised that WMI does not expose this.
Perhaps using command line tool:
OpenedFilesView v1.50 - View opened/locked files in your system (sharing violation issues)
http://www.nirsoft.net/utils/opened_files_view.html
How do we make our application start on computer startup (and of course, after the user had signed in)?
And no, I am not making a virus.
Does registry editing sound like a good idea?
My OS is Windows 8.
However, I will try to make my application available for all possible Window OS.
The correct way to do this is simply to add a shortcut to your application's executable to the user's Startup folder. You do not need to (and should not) modify the registry.
Advanced users know how to do this manually already, but it may also be an option you want to provide as part of your installer and/or a configuration dialog in your application.
To do this from C++ code, you will need to do two things:
Retrieve the location of the current user's Startup folder.
This is accomplished by calling the SHGetKnownFolderPath function and specifying the KNOWNFOLDERID of the folder you're interested in. In this case, that would be FOLDERID_Startup.
Sample code:
std::wstring GetStartupFolderPath()
{
PWSTR pszPath;
HRESULT hr = SHGetKnownFolderPath(&FOLDERID_Startup,
0, // no special options required
NULL, // no access token required
&pszPath);
if (SUCCEEDED(hr))
{
// The function succeeded, so copy the returned path to a
// C++ string, free the memory allocated by the function,
// and return the path string.
std::wstring path(pszPath);
CoTaskMemFree(static_cast<LPVOID>(pszPath));
return path;
}
else
{
// The function failed, so handle the error.
// ...
// You might want to throw an exception, or just return an
// empty string here.
throw std::runtime_error("The SHGetKnownFolderPath function failed");
}
}
Note, however, that while SHGetKnownFolderPath is the recommended function to use, it is supported only by Windows Vista and later. If you need to support older versions of the operating system, you'll need to call it dynamically on newer versions where it is available, and otherwise fall back to calling the SHGetFolderPath function. This one takes a different type of identifier, a CSIDL value. The one you want is CSIDL_STARTUP.
Create a shortcut to your application's executable.
This is accomplished using a different set of Shell API functions. I won't bother writing up sample code here because it's all quite well explained on MSDN already: Shell Links
Now you just connect the dots: when you create the shortcut to your application's executable, specify the user's Startup folder as its destination path.
The only other thing to be aware of is that there are actually multiple Startup folders. Each user has one, which is the one we retrieved above using FOLDERID_Startup. About 99% of the time, that's the one you want. Putting a shortcut to your app there will cause it to be launched automatically when that user logs on.
However, there is also a global Startup folder that is shared by all users. This one is identified by FOLDERID_CommonStartup (or CSIDL_COMMON_STARTUP) and requires administrative privileges to add items to. That makes sense, of course, because whatever you put in there is going to launch automatically when any user logs on to the computer. Only administrators can affect global behavior like this. And chances are, your app doesn't need this anyway.
Start menu
Simplest solution is to place .lnk of .bat file into the Start Menu\On startup folder. This is easiest and not too sneaky against the user.
Registry:
Another solution is creating the key in the registry keys:
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run] //All users
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce] //All users once
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run] //Currend user
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce] //Current user once
This is not that transparent - so a bit more agressive against the user.
On windows you can put a shortcut to your application in the Startup folder, or you can implement it as a service.
And that "I am not making a virus" does make you sound guilty... Maybe it is a keylogger? ;)
There are a lot of ways, but they all depend on your OS. For windows take a look at the "Task Schedualer" under "Administrative tools" in the control panel.
Maybe something like this? Note, this code snippet is not written by me.
#include <windows.h>
void Reg() {
::HKEY Handle_Key = 0;
::DWORD Dispoition = 0;
::RegOpenKeyEx( HKEY_LOCAL_MACHINE,
"Software\\Microsoft\\Windows\\CurrentVersion\\Run",
0,
KEY_ALL_ACCESS,
&Handle_Key );
const unsigned char Path[ MAX_PATH ] = "C:\\Windows\\YourProgramName.exe";
::RegSetValueEx( Handle_Key, "My Directory", 0, 1, Path, sizeof( unsigned char ) );
};
What do you guys think?
I'm new to the topic shell extensions and I'm looking for resources about namespace extensions. I would like to write a namespace extension which supports SFTP with all options to browse like FTP in the explorer.
I read the examples 1, 2 of zengxi from codeproject, but they don't compile right and seems to be old. I think that there were also many changes like the folder selection in the address bar.
Can somebody provide me some resources in the right direction or some working examples?
UPDATE:
It is important that the source is free. This is a non-profit project.
At the moment I found a good source on the MSDN called Explorer Data Provider Sample. This is up to date and provides some aliases Explorer Data Provider and Shell Data Source. What is yet missing is drop & drag support and a glue for supporting protocol links.
For future usage it would be great to find a way to associate a file extension with that shell data source like zip files.
Here is the full example of creating a namespace to mapping real files on Flickr.
However, only source codes available. No tutorial.
Hope it helps....
http://www.viksoe.dk/code/flickrdrive.htm
For Drag&Drop, this series of articles are a great point to start. After I understood that the files must have the flag can copy, can move, etc. I had almost the solution. The magic was to add one line in GetAttributesOf:
*rgfInOut |= SFGAO_CANCOPY|SFGAO_CANMOVE;
Also I had to publish the IDataObject in GetUIObjectOf like this:
if(riid == IID_IDataObject) {
PWSTR pszName;
hr = _GetName(apidl[0], &pszName);
hr = SHCreateDataObject(m_pidl, cidl, apidl,
new CFileDataObject(pszName), riid, ppv);
} else if(riid == IID_IDropTarget) {
// TODO publish
return E_NOINTERFACE;
}
That's all.
By the way what is the best practice for allocating CFileDataObject here?
Take a look at the EZNamespaceExtensionsMFC library which makes it very easy to develop namespace extensions. Check out its FileBrowser and RegBrowser samples which you can use a starting point.
DISCLAIMER: I work for LogicNP Software, the developer of EZNamespaceExtensionsMFC
I'm trying to write a Windows Explorer thumbnail handler for our custom file type. I've got this working fine for the preview pane, but am having trouble getting it to work for the thumbnails.
Windows doesn't even seem to be trying to call the DllGetClassObject entry point.
Before I continue, note that I'm using Windows 7 and unmanaged C++.
I've registered the following values in the registry:
HKCR\CLSID\<my guid>
HKCR\CLSID\<my guid>\InprocServer32 (default value = path to my DLL)
HKCR\CLSID\<my guid>\InprocServer32\ThreadingModel (value = "Apartment")
HKCR\.<my ext>\shellex\{E357FCCD-A995-4576-B01F-234630154E96} (value = my guid)
I've also tried using the Win SDK sample, and that doesn't work. And also the sample project in this article (http://www.codemonkeycodes.com/2010/01/11/ithumbnailprovider-re-visited/), and that doesn't work.
I'm new to shell programming, so not really sure the best way of debugging this. I've tried attaching the debugger to explorer.exe, but that doesn't seem to work (breakpoints get disabled, and none of my OutputDebugStrings get displayed in the output window). Note that I tried setting the "DesktopProcess" in the registry as described in the WinSDK docs for debugging the shell, but I'm still only seeing one explorer.exe in the task manager - so that "may" be why I can't debug it??
Any help with this would be greatly appreciated!
Regards,
Dan.
I stumbled across this since you mentioned my blog ( codemonkeycodes.com ).
What problem are you having with my sample? Did you register you DLL using regsvr32? What version of Windows 7 are you on, 32 or 64?
Update:
I can't say what is or isn't working for you. I just downloaded the sample from my site, followed the directions and change the function
STDMETHODIMP CThumbnailProvider::GetThumbnail... to look like
{
*phbmp = NULL;
*pdwAlpha = WTSAT_UNKNOWN;
ULONG_PTR token;
GdiplusStartupInput input;
if (Ok == GdiplusStartup(&token, &input, NULL))
{
//gcImage.LogBuffer();
Bitmap * pBitmap = new Bitmap(188, 141);
if( pBitmap )
{
Color color(0, 0, 0);
pBitmap->GetHBITMAP(color, phbmp);
}
}
GdiplusShutdown(token);
if( *phbmp != NULL )
return NOERROR;
return E_NOTIMPL;
}
I registered the DLL and then created a new file with the proper extension, and tada, I had a nice black thumbnail.
I wish I could help you. Maybe you want to email me your code?
I've exactly the same problem. I cant make SDK or any sample works. I need COM sample because I must call Microsoft.Jet.OLEDB.4.0 which works only on 32 bits system.
I couldnt make this work: link
This works if AnyCPU is specified when compiling. Cant make it works for x86: link
This was nice under XP works like a charm: link
This show Adobe had problems with thumbnail An MS with Office 2007 (32 bits): link