You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1072 lines
25 KiB
1072 lines
25 KiB
/* embed.c - Contains the routines for pseudo-embedding objects.
|
|
*
|
|
* Copyright (c) Microsoft Corporation, 1991-
|
|
*
|
|
* Why is it called pseudo-embedding? Because it is not embedding
|
|
* the object in the OLE sense; rather, it just pulls the entire
|
|
* file into memory.
|
|
*/
|
|
#define _SECOND ((ULONGLONG) 10000000)
|
|
#define _MINUTE (60 * _SECOND)
|
|
#define _HOUR (60 * _MINUTE)
|
|
|
|
#include "packager.h"
|
|
#include <shellapi.h>
|
|
#include "dialogs.h"
|
|
#include <wininet.h>
|
|
// #include <shell.h> // For RealShellExecute() call.
|
|
|
|
#define OLEVERB_EDIT 1
|
|
|
|
|
|
static CHAR szDefTempFile[] = "PKG";
|
|
static OLECLIENTVTBL embClivtbl;
|
|
static BOOL bOleReleaseError = OLE_OK;
|
|
static HWND hTaskWnd;
|
|
static INT cEmbWait = 0;
|
|
|
|
|
|
DWORD MainWaitOnChild(LPVOID lpv);
|
|
static VOID ReplaceExtension(LPSTR lpstrTempFile, LPSTR lpstrOrigFile);
|
|
static DWORD GetFileLength(INT fh);
|
|
BOOL CALLBACK GetTaskWndProc(HWND hwnd, LPARAM lParam);
|
|
static BOOL EmbError(OLESTATUS retval);
|
|
|
|
|
|
|
|
BOOL _EmbExecute(LPCSTR pszFile, LPEMBED lpembed)
|
|
{
|
|
DWORD err = NO_ERROR;
|
|
SHELLEXECUTEINFO sei = {0};
|
|
sei.cbSize = sizeof(sei);
|
|
sei.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_DDEWAIT;
|
|
sei.lpFile = pszFile;
|
|
sei.nShow = SW_SHOWNORMAL;
|
|
|
|
if (ShellExecuteEx(&sei))
|
|
{
|
|
if (lpembed->hContents)
|
|
{
|
|
GlobalFree(lpembed->hContents);
|
|
lpembed->aTempName = AddAtom(pszFile);
|
|
lpembed->dwSize = 0;
|
|
lpembed->hContents = NULL;
|
|
}
|
|
|
|
if (sei.hProcess)
|
|
{
|
|
// Start a thread to wait on the app and close packager once it has ended
|
|
DWORD id;
|
|
HANDLE hThd = CreateThread(NULL, 0, MainWaitOnChild, sei.hProcess, 0, &id );
|
|
if (hThd)
|
|
{
|
|
CloseHandle(hThd);
|
|
}
|
|
else
|
|
{
|
|
CloseHandle(sei.hProcess);
|
|
err = GetLastError();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (gfInvisible)
|
|
PostMessage(ghwndFrame, WM_SYSCOMMAND, SC_CLOSE, 0L);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
err = GetLastError();
|
|
}
|
|
|
|
if (err != NO_ERROR)
|
|
{
|
|
ErrorMessage((err == ERROR_NO_ASSOCIATION) ? E_FAILED_TO_FIND_ASSOCIATION : E_FAILED_TO_EXECUTE_COMMAND);
|
|
}
|
|
|
|
return (err == NO_ERROR);
|
|
}
|
|
|
|
// Taken from shell code but slightly modified to eliminate problesm with finding ":" in the url
|
|
STDAPI_(LPTSTR) PathFindExtension(LPCTSTR pszPath)
|
|
{
|
|
LPCTSTR pszDot = NULL;
|
|
|
|
if (pszPath)
|
|
{
|
|
for (; *pszPath; pszPath = CharNext(pszPath))
|
|
{
|
|
switch (*pszPath)
|
|
{
|
|
case TEXT('.'):
|
|
pszDot = pszPath; // remember the last dot
|
|
break;
|
|
|
|
case '\\':
|
|
case TEXT(' '): // extensions can't have spaces
|
|
pszDot = NULL; // forget last dot, it was in a directory
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if we found the extension, return ptr to the dot, else
|
|
// ptr to end of the string (NULL extension) (cast->non const)
|
|
return pszDot ? (LPTSTR)pszDot : (LPTSTR)pszPath;
|
|
}
|
|
|
|
/* EmbActivate() - Performs activation of a pseudo-embedded file.
|
|
*
|
|
* Notes: Assumes that lpstrFile is in the OEM character set.
|
|
*/
|
|
BOOL EmbActivate(LPEMBED lpembed, UINT wVerb)
|
|
{
|
|
LPSTR lpFileData = NULL;
|
|
|
|
CHAR szFileName[CBPATHMAX];
|
|
CHAR szDefPath[CBPATHMAX];
|
|
CHAR szTemp[CBPATHMAX];
|
|
INT fh;
|
|
BOOL fError = TRUE;
|
|
LPSTR pExt = NULL;
|
|
CHAR szCacheName[MAX_PATH];
|
|
CHAR szUrlName[MAX_PATH + 20];
|
|
FILETIME ftNow = {0};
|
|
FILETIME ft = {0};
|
|
SYSTEMTIME sysTime;
|
|
ULONGLONG qwResult;
|
|
//
|
|
// If no hContents, we launched the server at some point...
|
|
// so use the same temporary file name.
|
|
//
|
|
if (!lpembed->hContents)
|
|
{
|
|
if (lpembed->bOleSvrFile)
|
|
return EmbDoVerb(lpembed, wVerb);
|
|
|
|
if (lpembed->hTask)
|
|
{
|
|
hTaskWnd = NULL;
|
|
EnumTaskWindows(lpembed->hTask, GetTaskWndProc, 0);
|
|
|
|
if (hTaskWnd)
|
|
BringWindowToTop(hTaskWnd);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
if (!GetAtomName(lpembed->aTempName, szCacheName, ARRAYSIZE(szCacheName)))
|
|
goto errRtn;
|
|
}
|
|
else
|
|
{
|
|
if (!GetAtomName(lpembed->aFileName, szFileName, ARRAYSIZE(szFileName))
|
|
|| !(lpFileData = GlobalLock(lpembed->hContents)))
|
|
goto errRtn;
|
|
|
|
GlobalUnlock(lpembed->hContents);
|
|
|
|
// Find the extension -- we need it for the urlcache funcion
|
|
pExt = PathFindExtension(szFileName);
|
|
if('.' == *pExt) // not expecting the '.'
|
|
pExt++;
|
|
|
|
GetSystemTime(&sysTime);
|
|
SystemTimeToFileTime(&sysTime, &ft);
|
|
|
|
// Create a fake URL in the format expected -- While not totally unique, close enough for our purposes (4 billion)
|
|
StringCchPrintf(szUrlName, ARRAYSIZE(szUrlName), TEXT("Packager%u:%s"), ft.dwLowDateTime, szFileName);
|
|
// So, now I'm pointing at the ext, and I have a fake url name, so
|
|
if(!CreateUrlCacheEntry(szUrlName, ARRAYSIZE(szCacheName), pExt, szCacheName, 0))
|
|
goto errRtn;
|
|
|
|
if ((fh = _lcreat(szCacheName, 0)) < 0)
|
|
goto errRtn;
|
|
|
|
if (_lwrite(fh, lpFileData, lpembed->dwSize) < lpembed->dwSize)
|
|
{
|
|
_lclose(fh);
|
|
DeleteFile(szCacheName);
|
|
goto errRtn;
|
|
}
|
|
|
|
_lclose(fh);
|
|
|
|
// exire this in 12 hours (arbitrarily longer than a work day) since we can't always clean it up ourselves.
|
|
// Normally we'd only care about it for a very short time, and it probably
|
|
// wouldn't hurt to have it cleaned up if it was open anyway.
|
|
SystemTimeToFileTime(&sysTime, &ftNow);
|
|
// Copy the time into a quadword.
|
|
qwResult = (((ULONGLONG) ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
|
|
qwResult += (12 * _HOUR);
|
|
// Copy the result back into the FILETIME structure.
|
|
ft.dwLowDateTime = (DWORD) (qwResult & 0xFFFFFFFF );
|
|
ft.dwHighDateTime = (DWORD) (qwResult >> 32 );
|
|
|
|
if(!CommitUrlCacheEntry(
|
|
szUrlName,
|
|
szCacheName,
|
|
ft,
|
|
ftNow,
|
|
0,
|
|
NULL,
|
|
0,
|
|
pExt,
|
|
szUrlName))
|
|
{
|
|
goto errRtn;
|
|
}
|
|
|
|
}
|
|
|
|
if (lpembed->bOleSvrFile)
|
|
{
|
|
fError = !EmbActivateThroughOle(lpembed, szCacheName, wVerb);
|
|
if (!fError)
|
|
{
|
|
GlobalFree(lpembed->hContents);
|
|
lpembed->aTempName = AddAtom(szCacheName);
|
|
lpembed->dwSize = 0;
|
|
lpembed->hContents = NULL;
|
|
}
|
|
|
|
goto errRtn;
|
|
}
|
|
|
|
// Try to execute the file
|
|
lpembed->hTask = NULL;
|
|
fError = !_EmbExecute(szCacheName, lpembed);
|
|
if (fError)
|
|
{
|
|
DeleteFile(szCacheName);
|
|
}
|
|
|
|
errRtn:
|
|
if (fError)
|
|
{
|
|
if (gfInvisible)
|
|
PostMessage(ghwndFrame, WM_SYSCOMMAND, SC_CLOSE, 0L);
|
|
}
|
|
else
|
|
{
|
|
Dirty();
|
|
}
|
|
|
|
return !fError;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* MainWaitOnChild
|
|
*
|
|
* Waits for the specified child process to exit, then posts a message
|
|
* back to the main window.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* LPVOID lpv - Handle to the child process to wait on.
|
|
*
|
|
* Returns:
|
|
* 0
|
|
*
|
|
\*****************************************************************************/
|
|
|
|
DWORD
|
|
MainWaitOnChild(
|
|
LPVOID lpv
|
|
)
|
|
{
|
|
if (WaitForSingleObject((HANDLE)lpv, INFINITE) == 0)
|
|
{
|
|
PostMessage(ghwndFrame, WM_READEMBEDDED, 0, 0);
|
|
}
|
|
|
|
CloseHandle((HANDLE)lpv);
|
|
|
|
GetLastError(); //This seems ominous
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/* EmbCreate() - Performs the pseudo-embedding of a file.
|
|
*
|
|
* Notes: Assumes that lpstrFile is in the OEM character set.
|
|
*
|
|
* This function is used by File Import..., is called
|
|
* when the Embed modifier is used on Drag&Drop, and
|
|
* is also used when Paste-ing a File manager file.
|
|
*/
|
|
LPEMBED
|
|
EmbCreate(
|
|
LPSTR lpstrFile
|
|
)
|
|
{
|
|
ATOM aFileName = 0;
|
|
BOOL fError = TRUE;
|
|
DWORD dwSize = 0;
|
|
HANDLE hdata = NULL;
|
|
HANDLE hFileData = NULL;
|
|
LPEMBED lpembed = NULL;
|
|
LPSTR lpFileData = NULL;
|
|
INT fh = 0;
|
|
|
|
if (lpstrFile)
|
|
{
|
|
if ((fh = _lopen(lpstrFile, OF_READ | OF_SHARE_DENY_WRITE)) == HFILE_ERROR)
|
|
{
|
|
ErrorMessage(IDS_ACCESSDENIED);
|
|
goto errRtn;
|
|
}
|
|
|
|
// Seek to EOF, then to the top of the file.
|
|
dwSize = GetFileLength(fh);
|
|
if (0 == dwSize)
|
|
{
|
|
ErrorMessage(IDS_NOZEROSIZEFILES);
|
|
goto errRtn;
|
|
}
|
|
|
|
if (!(aFileName = AddAtom(lpstrFile))
|
|
|| !(hFileData = GlobalAlloc(GMEM_MOVEABLE, dwSize))
|
|
|| !(lpFileData = GlobalLock(hFileData)))
|
|
{
|
|
ErrorMessage(IDS_LOWMEM);
|
|
goto errRtn;
|
|
}
|
|
|
|
if (_lread(fh, lpFileData, dwSize) != dwSize)
|
|
{
|
|
ErrorMessage(E_FAILED_TO_READ_FILE);
|
|
goto errRtn;
|
|
}
|
|
}
|
|
|
|
if (!(hdata = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(EMBED)))
|
|
|| !(lpembed = (LPEMBED)GlobalLock(hdata)))
|
|
{
|
|
ErrorMessage(IDS_LOWMEM);
|
|
goto errRtn;
|
|
}
|
|
|
|
lpembed->aFileName = aFileName;
|
|
lpembed->dwSize = dwSize;
|
|
lpembed->hContents = hFileData;
|
|
lpembed->hdata = hdata;
|
|
lpembed->bOleSvrFile = IsOleServerDoc(lpstrFile);
|
|
fError = FALSE;
|
|
|
|
errRtn:
|
|
if (fh)
|
|
_lclose(fh);
|
|
|
|
if (lpFileData)
|
|
GlobalUnlock(hFileData);
|
|
|
|
if (fError)
|
|
{
|
|
if (hdata)
|
|
GlobalFree(hdata);
|
|
|
|
if (aFileName)
|
|
DeleteAtom(aFileName);
|
|
|
|
if (hFileData)
|
|
GlobalFree(hFileData);
|
|
}
|
|
|
|
return lpembed;
|
|
}
|
|
|
|
|
|
|
|
/* EmbDelete() - Deallocate the pseudo-embedded file.
|
|
*/
|
|
VOID
|
|
EmbDelete(
|
|
LPEMBED lpembed
|
|
)
|
|
{
|
|
HANDLE hdata;
|
|
|
|
if (!lpembed)
|
|
return;
|
|
|
|
if (lpembed->lpLinkObj)
|
|
{
|
|
EmbRead(glpobj[CONTENT]);
|
|
EmbDeleteLinkObject(lpembed);
|
|
}
|
|
else {
|
|
/* If the task is active, there's nothing we can do */
|
|
#if 0
|
|
if (lpembed->hSvrInst)
|
|
TermToolHelp(lpembed);
|
|
#endif //FEATURE: Does anything need to be done for this case? Like terminating the waiting thread, perhaps?
|
|
}
|
|
|
|
if (lpembed->aFileName)
|
|
{
|
|
DeleteAtom(lpembed->aFileName);
|
|
lpembed->aFileName = 0;
|
|
}
|
|
|
|
if (lpembed->aTempName)
|
|
{
|
|
DeleteAtom(lpembed->aTempName);
|
|
lpembed->aTempName = 0;
|
|
}
|
|
|
|
if (lpembed->hContents)
|
|
{
|
|
GlobalFree(lpembed->hContents);
|
|
lpembed->dwSize = 0;
|
|
lpembed->hContents = NULL;
|
|
}
|
|
|
|
GlobalUnlock(hdata = lpembed->hdata);
|
|
GlobalFree(hdata);
|
|
}
|
|
|
|
|
|
|
|
/* EmbDraw() - Draw the pseudo-embedded object.
|
|
*
|
|
* Note: This drawing is DESCRIPTION-ONLY.
|
|
*/
|
|
VOID
|
|
EmbDraw(
|
|
LPEMBED lpembed,
|
|
HDC hdc,
|
|
LPRECT lprc,
|
|
BOOL fFocus
|
|
)
|
|
{
|
|
RECT rcFocus;
|
|
CHAR szEmbedFile[CBMESSAGEMAX];
|
|
CHAR szFileName[CBPATHMAX];
|
|
CHAR szMessage[CBMESSAGEMAX + CBPATHMAX];
|
|
|
|
if (GetAtomName(lpembed->aFileName, szFileName, CBPATHMAX)
|
|
&& LoadString(ghInst, IDS_EMBEDFILE, szEmbedFile, CBMESSAGEMAX))
|
|
{
|
|
Normalize(szFileName);
|
|
StringCchPrintf(szMessage, ARRAYSIZE(szMessage), szEmbedFile, (LPSTR)szFileName);
|
|
|
|
DrawText(hdc, szMessage, -1, lprc,
|
|
DT_NOPREFIX | DT_CENTER | DT_VCENTER | DT_SINGLELINE);
|
|
|
|
if (fFocus)
|
|
{
|
|
rcFocus = *lprc;
|
|
DrawText(hdc, szMessage, -1, &rcFocus, DT_CALCRECT | DT_NOPREFIX |
|
|
DT_LEFT | DT_TOP | DT_SINGLELINE);
|
|
OffsetRect(&rcFocus, (lprc->left + lprc->right - rcFocus.right) /
|
|
2, (lprc->top + lprc->bottom - rcFocus.bottom) / 2);
|
|
DrawFocusRect(hdc, &rcFocus);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* EmbReadFromNative() - Reads a pseudo-embedded object from memory.
|
|
*
|
|
* Notes: This function is called by GetNative().
|
|
*/
|
|
LPEMBED
|
|
EmbReadFromNative(
|
|
LPSTR *lplpstr
|
|
)
|
|
{
|
|
BOOL fError = TRUE;
|
|
DWORD dwSize;
|
|
HANDLE hData = NULL;
|
|
LPEMBED lpembed = NULL;
|
|
LPSTR lpData = NULL;
|
|
CHAR szFileName[CBPATHMAX];
|
|
|
|
MemRead(lplpstr, (LPSTR)&dwSize, sizeof(dwSize));
|
|
MemRead(lplpstr, (LPSTR)szFileName, dwSize);
|
|
MemRead(lplpstr, (LPSTR)&dwSize, sizeof(dwSize));
|
|
|
|
if (!(lpembed = EmbCreate(NULL))
|
|
|| !(hData = GlobalAlloc(GMEM_MOVEABLE, dwSize))
|
|
|| !(lpData = GlobalLock(hData)))
|
|
goto errRtn;
|
|
|
|
MemRead(lplpstr, (LPSTR)lpData, dwSize);
|
|
|
|
lpembed->aFileName = AddAtom(szFileName);
|
|
lpembed->dwSize = dwSize;
|
|
lpembed->hContents = hData;
|
|
lpembed->bOleSvrFile = IsOleServerDoc(szFileName);
|
|
fError = FALSE;
|
|
|
|
errRtn:
|
|
if (lpData)
|
|
GlobalUnlock(hData);
|
|
|
|
if (fError)
|
|
{
|
|
if (hData)
|
|
GlobalFree(hData);
|
|
|
|
if (lpembed)
|
|
{
|
|
EmbDelete(lpembed);
|
|
lpembed = NULL;
|
|
}
|
|
}
|
|
|
|
return lpembed;
|
|
}
|
|
|
|
|
|
|
|
/* EmbWriteToNative() - Used to save pseudo-embed to memory.
|
|
*
|
|
* Note: This function is called by GetNative().
|
|
*/
|
|
DWORD
|
|
EmbWriteToNative(
|
|
LPEMBED lpembed,
|
|
LPSTR *lplpstr
|
|
)
|
|
{
|
|
BOOL fError = TRUE;
|
|
DWORD cBytes = 0;
|
|
DWORD dwSize;
|
|
HANDLE hData = NULL;
|
|
LPSTR lpData = NULL;
|
|
LPSTR lpFileData = NULL;
|
|
CHAR szFileName[CBPATHMAX];
|
|
INT fhTemp = -1;
|
|
CHAR * hplpstr;
|
|
|
|
if (!GetAtomName(lpembed->aFileName, szFileName, CBPATHMAX))
|
|
goto errRtn;
|
|
|
|
if (!lplpstr)
|
|
{
|
|
cBytes = lstrlen(szFileName) + 1 + sizeof(dwSize);
|
|
}
|
|
else
|
|
{
|
|
dwSize = lstrlen(szFileName) + 1;
|
|
MemWrite(lplpstr, (LPSTR)&dwSize, sizeof(dwSize));
|
|
MemWrite(lplpstr, (LPSTR)szFileName, dwSize);
|
|
}
|
|
|
|
// Read from memory if it's there; otherwise, it's executing
|
|
if (lpembed->hContents)
|
|
{
|
|
cBytes += sizeof(lpembed->dwSize) + lpembed->dwSize;
|
|
|
|
if (lplpstr)
|
|
{
|
|
if (!(lpFileData = GlobalLock(lpembed->hContents)))
|
|
goto errRtn;
|
|
|
|
MemWrite(lplpstr, (LPSTR)&(lpembed->dwSize), sizeof(lpembed->dwSize));
|
|
MemWrite(lplpstr, (LPSTR)lpFileData, lpembed->dwSize);
|
|
}
|
|
} else {
|
|
int i;
|
|
|
|
if (!GetAtomName(lpembed->aTempName, szFileName, CBPATHMAX))
|
|
goto errRtn;
|
|
|
|
for (i = 0; i < 5; i++ ) {
|
|
int j;
|
|
|
|
fhTemp = _lopen(szFileName, OF_READ | OF_SHARE_DENY_WRITE);
|
|
|
|
if (fhTemp != HFILE_ERROR) {
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* We could not open the file. It is probably still open by the
|
|
* server. Wait 5 seconds for the server to finish closing the
|
|
* file and then try again.
|
|
*/
|
|
for (j=0; j<25; j++) {
|
|
MSG msg;
|
|
PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
|
|
Sleep(200);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If after 25 seconds we still could not open the file, then it
|
|
* must be screwed
|
|
*/
|
|
if (fhTemp == HFILE_ERROR)
|
|
goto errRtn;
|
|
|
|
dwSize = GetFileLength(fhTemp);
|
|
|
|
if (!lplpstr)
|
|
cBytes += sizeof(dwSize) + dwSize;
|
|
else
|
|
{
|
|
MemWrite(lplpstr, (LPSTR)&dwSize, sizeof(dwSize));
|
|
_lread(fhTemp, *lplpstr, dwSize);
|
|
|
|
// Increment the pointer being read into
|
|
hplpstr = *lplpstr;
|
|
hplpstr += dwSize;
|
|
*lplpstr = hplpstr;
|
|
}
|
|
}
|
|
|
|
fError = FALSE;
|
|
|
|
errRtn:
|
|
if (fhTemp >= 0)
|
|
{
|
|
_lclose(fhTemp);
|
|
if (!fError && lplpstr && !(lpembed->hTask || lpembed->lpLinkObj))
|
|
DeleteFile(szFileName);
|
|
}
|
|
|
|
if (lpData)
|
|
GlobalUnlock(hData);
|
|
|
|
if (hData)
|
|
GlobalFree(hData);
|
|
|
|
if (lpFileData)
|
|
GlobalUnlock(lpembed->hContents);
|
|
|
|
return (fError ? ((DWORD)(-1L)) : cBytes);
|
|
}
|
|
|
|
|
|
|
|
/* EmbWriteToFile() - Used to save pseudo-embed to a file.
|
|
*
|
|
* Note: This function is called by File Export...
|
|
*/
|
|
VOID
|
|
EmbWriteToFile(
|
|
LPEMBED lpembed,
|
|
INT fh
|
|
)
|
|
{
|
|
BOOL fError = TRUE;
|
|
DWORD dwSize;
|
|
HANDLE hData = NULL;
|
|
LPSTR lpData = NULL;
|
|
LPSTR lpFileData = NULL;
|
|
CHAR szTempName[CBPATHMAX];
|
|
INT fhTemp = -1;
|
|
CHAR szMessage[CBMESSAGEMAX];
|
|
|
|
// Read from memory if it's there
|
|
if (lpembed->hContents)
|
|
{
|
|
if (!(lpFileData = GlobalLock(lpembed->hContents)))
|
|
goto errRtn;
|
|
|
|
if (_lwrite(fh, lpFileData, lpembed->dwSize) != lpembed->dwSize)
|
|
goto errRtn;
|
|
}
|
|
else
|
|
{
|
|
// otherwise, it is/was executing
|
|
if (lpembed->hTask && !gfInvisible)
|
|
{
|
|
// Object being edited, snapshot current contents?
|
|
LoadString(ghInst, IDS_ASKCLOSETASK, szMessage, CBMESSAGEMAX);
|
|
BringWindowToTop(ghwndFrame);
|
|
switch (MessageBoxAfterBlock(ghwndError, szMessage, szAppName,
|
|
MB_OKCANCEL))
|
|
{
|
|
case IDOK:
|
|
break;
|
|
|
|
case IDCANCEL:
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!GetAtomName(lpembed->aTempName, szTempName, CBPATHMAX)
|
|
|| (fhTemp = _lopen(szTempName, OF_READ | OF_SHARE_DENY_WRITE)) == HFILE_ERROR)
|
|
goto errRtn;
|
|
|
|
dwSize = GetFileLength(fhTemp);
|
|
while (dwSize && !(hData = GlobalAlloc(GMEM_MOVEABLE, dwSize)))
|
|
dwSize = dwSize >> 1;
|
|
|
|
if (!dwSize || !(lpData = GlobalLock(hData)))
|
|
goto errRtn;
|
|
|
|
while (dwSize)
|
|
{
|
|
dwSize = _lread(fhTemp, lpData, dwSize);
|
|
|
|
if (dwSize)
|
|
_lwrite(fh, lpData, dwSize);
|
|
}
|
|
}
|
|
|
|
fError = FALSE;
|
|
|
|
errRtn:
|
|
if (fhTemp >= 0)
|
|
{
|
|
_lclose(fhTemp);
|
|
|
|
if (!fError && !lpembed->hTask)
|
|
DeleteFile(gszFileName);
|
|
}
|
|
|
|
if (lpData)
|
|
GlobalUnlock(hData);
|
|
|
|
if (hData)
|
|
GlobalFree(hData);
|
|
|
|
if (lpFileData)
|
|
GlobalUnlock(lpembed->hContents);
|
|
}
|
|
|
|
|
|
|
|
/* ReplaceExtension() - Replaces the extension of the temp file.
|
|
*
|
|
* This routine ensures that the temp file has the same extension as the
|
|
* original file, so that the ShellExecute() will load the same file.
|
|
*/
|
|
static VOID
|
|
ReplaceExtension(
|
|
LPSTR lpstrTempFile,
|
|
LPSTR lpstrOrigFile
|
|
)
|
|
{
|
|
LPSTR lpstrBack = NULL;
|
|
|
|
// Get temp file extension
|
|
while (*lpstrTempFile)
|
|
{
|
|
if (*lpstrTempFile == '\\')
|
|
lpstrBack = lpstrTempFile;
|
|
|
|
if (gbDBCS)
|
|
{
|
|
lpstrTempFile = CharNext(lpstrTempFile);
|
|
}
|
|
else
|
|
{
|
|
lpstrTempFile++;
|
|
}
|
|
}
|
|
|
|
while (lpstrBack && *lpstrBack && *lpstrBack != '.')
|
|
lpstrBack++;
|
|
|
|
if (lpstrBack && *lpstrBack)
|
|
lpstrTempFile = lpstrBack + 1;
|
|
|
|
// Get original file extension
|
|
while (*lpstrOrigFile)
|
|
{
|
|
if (*lpstrOrigFile == '\\')
|
|
lpstrBack = lpstrOrigFile;
|
|
|
|
if (gbDBCS)
|
|
{
|
|
lpstrOrigFile = CharNext(lpstrOrigFile);
|
|
}
|
|
else
|
|
{
|
|
lpstrOrigFile++;
|
|
}
|
|
}
|
|
|
|
while (lpstrBack && *lpstrBack && *lpstrBack != '.')
|
|
lpstrBack++;
|
|
|
|
if (lpstrBack && *lpstrBack)
|
|
{
|
|
lpstrOrigFile = lpstrBack + 1;
|
|
|
|
// Move the extension on over
|
|
lstrcpy(lpstrTempFile, lpstrOrigFile);
|
|
}
|
|
else
|
|
{
|
|
/* Wipe out the extension altogether */
|
|
*lpstrTempFile = 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* GetFileLength() - Obtain the size of the temporary file used.
|
|
*
|
|
* Returns: The length of the file in bytes.
|
|
* Side effects: Resets fh to the beginning of the file.
|
|
*/
|
|
static DWORD
|
|
GetFileLength(
|
|
INT fh
|
|
)
|
|
{
|
|
DWORD dwSize;
|
|
|
|
dwSize = _llseek(fh, 0L, 2);
|
|
_llseek(fh, 0L, 0);
|
|
|
|
return dwSize;
|
|
}
|
|
|
|
|
|
|
|
/* EmbRead() - Reads the contents back when the task has terminated.
|
|
*/
|
|
VOID
|
|
EmbRead(
|
|
LPEMBED lpembed
|
|
)
|
|
{
|
|
BOOL fError = TRUE;
|
|
DWORD dwSize;
|
|
HANDLE hFileData = NULL;
|
|
LPSTR lpFileData = NULL;
|
|
CHAR szTempFileName[CBPATHMAX];
|
|
INT fhTemp = -1;
|
|
|
|
if (!lpembed || !lpembed->aTempName)
|
|
return;
|
|
|
|
if (!GetAtomName(lpembed->aTempName, szTempFileName, CBPATHMAX))
|
|
return;
|
|
|
|
if ((fhTemp = _lopen(szTempFileName, OF_READ | OF_SHARE_DENY_WRITE)) == HFILE_ERROR)
|
|
goto errRtn;
|
|
|
|
dwSize = GetFileLength(fhTemp);
|
|
|
|
if (!(hFileData = GlobalAlloc(GMEM_MOVEABLE, dwSize))
|
|
|| !(lpFileData = GlobalLock(hFileData))
|
|
|| (_lread(fhTemp, lpFileData, dwSize) != dwSize))
|
|
goto errRtn;
|
|
|
|
DeleteAtom(lpembed->aTempName);
|
|
lpembed->aTempName = 0;
|
|
lpembed->dwSize = dwSize;
|
|
lpembed->hContents = hFileData;
|
|
lpembed->hTask = NULL;
|
|
|
|
fError = FALSE;
|
|
|
|
errRtn:
|
|
if (fhTemp >= 0)
|
|
{
|
|
_lclose(fhTemp);
|
|
|
|
if (!fError)
|
|
DeleteFile(szTempFileName);
|
|
}
|
|
|
|
if (lpFileData)
|
|
GlobalUnlock(hFileData);
|
|
|
|
if (fError && hFileData)
|
|
GlobalFree(hFileData);
|
|
}
|
|
|
|
|
|
|
|
BOOL CALLBACK
|
|
GetTaskWndProc(
|
|
HWND hwnd,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
if (IsWindowVisible(hwnd))
|
|
{
|
|
hTaskWnd = hwnd;
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
EmbDoVerb(
|
|
LPEMBED lpembed,
|
|
UINT wVerb
|
|
)
|
|
{
|
|
if (wVerb == IDD_PLAY)
|
|
{
|
|
if (EmbError(OleActivate(lpembed->lpLinkObj, OLEVERB_PRIMARY, TRUE,
|
|
TRUE, NULL, NULL)))
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
// it must be verb IDD_EDIT
|
|
if (EmbError(OleActivate(lpembed->lpLinkObj, OLEVERB_EDIT, TRUE,
|
|
TRUE, NULL, NULL)))
|
|
return FALSE;
|
|
}
|
|
|
|
WaitForObject(lpembed->lpLinkObj);
|
|
|
|
if (bOleReleaseError != OLE_OK)
|
|
{
|
|
bOleReleaseError = OLE_OK;
|
|
return FALSE;
|
|
}
|
|
|
|
// if the verb is IDD_PLAY then we need not do any more
|
|
if (wVerb == IDD_PLAY)
|
|
return TRUE;
|
|
|
|
// If the verb is IDD_EDIT, then we must show the server, and we will do
|
|
// that by calling server's show method
|
|
if (EmbError((*(lpembed->lpLinkObj)->lpvtbl->Show)(lpembed->lpLinkObj,
|
|
TRUE)))
|
|
return FALSE;
|
|
|
|
WaitForObject(lpembed->lpLinkObj);
|
|
|
|
if (bOleReleaseError != OLE_OK)
|
|
{
|
|
bOleReleaseError = OLE_OK;
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
EmbActivateThroughOle(
|
|
LPEMBED lpembed,
|
|
LPSTR lpdocname,
|
|
UINT wVerb
|
|
)
|
|
{
|
|
bOleReleaseError = OLE_OK;
|
|
|
|
if (!(lpembed->lpclient = PicCreateClient(&EmbCallBack, &embClivtbl)))
|
|
return FALSE;
|
|
|
|
if (EmbError(OleCreateLinkFromFile(gszProtocol, lpembed->lpclient, NULL,
|
|
lpdocname, NULL, glhcdoc, gszCaption[CONTENT], &lpembed->lpLinkObj,
|
|
olerender_none, 0)))
|
|
return FALSE;
|
|
|
|
WaitForObject(lpembed->lpLinkObj);
|
|
|
|
if (bOleReleaseError == OLE_OK)
|
|
{
|
|
if (gfEmbObjectOpen = EmbDoVerb(lpembed, wVerb))
|
|
return TRUE;
|
|
}
|
|
|
|
EmbDeleteLinkObject(lpembed);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
/* EmbCallBack() - Routine that OLE client DLL calls when events occur.
|
|
*/
|
|
INT CALLBACK
|
|
EmbCallBack(
|
|
LPOLECLIENT lpclient,
|
|
OLE_NOTIFICATION flags,
|
|
LPOLEOBJECT lpObject
|
|
)
|
|
{
|
|
switch (flags)
|
|
{
|
|
case OLE_CLOSED:
|
|
case OLE_SAVED:
|
|
case OLE_CHANGED:
|
|
break;
|
|
|
|
case OLE_RELEASE:
|
|
if (cEmbWait)
|
|
--cEmbWait;
|
|
|
|
bOleReleaseError = OleQueryReleaseError(lpObject);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
EmbDeleteLinkObject(
|
|
LPEMBED lpembed
|
|
)
|
|
{
|
|
HGLOBAL hg;
|
|
|
|
bOleReleaseError = OLE_OK;
|
|
|
|
if (!lpembed->lpLinkObj)
|
|
return;
|
|
|
|
WaitForObject(lpembed->lpLinkObj);
|
|
|
|
if (!EmbError(OleDelete(lpembed->lpLinkObj)))
|
|
WaitForObject (lpembed->lpLinkObj);
|
|
|
|
lpembed->lpLinkObj = NULL;
|
|
|
|
if (lpembed->lpclient)
|
|
{
|
|
if (hg = GlobalHandle(lpembed->lpclient))
|
|
{
|
|
GlobalUnlock(hg);
|
|
GlobalFree(hg);
|
|
}
|
|
|
|
lpembed->lpclient = NULL;
|
|
}
|
|
|
|
gfEmbObjectOpen = FALSE;
|
|
bOleReleaseError = OLE_OK;
|
|
}
|
|
|
|
|
|
|
|
static BOOL
|
|
EmbError(
|
|
OLESTATUS retval
|
|
)
|
|
{
|
|
switch (retval)
|
|
{
|
|
case OLE_WAIT_FOR_RELEASE:
|
|
cEmbWait++;
|
|
return FALSE;
|
|
|
|
case OLE_OK:
|
|
return FALSE;
|
|
|
|
default:
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
|