I have a piece of c code main.c.
#define STRICT
#ifndef UNICODE
#define T_MAX_PATH MAX_PATH
#else
#define T_MAX_PATH 32767
#endif
#include <tchar.h>
#include <windows.h>
#include <windowsx.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <commdlg.h>
// tcc, any other compiler support wWinMain() and '__argc/__targv'
//shlguid.h
DEFINE_GUID(IID_IDropTarget, 0x00000122, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
DEFINE_GUID(IID_IDataObject, 0x0000010e, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
//
#define WINGDIPAPI __stdcall
#define GDIPCONST const
typedef enum GpStatus {
Ok = 0,
GenericError = 1,
InvalidParameter = 2,
OutOfMemory = 3,
ObjectBusy = 4,
InsufficientBuffer = 5,
NotImplemented = 6,
Win32Error = 7,
WrongState = 8,
Aborted = 9,
FileNotFound = 10,
ValueOverflow = 11,
AccessDenied = 12,
UnknownImageFormat = 13,
FontFamilyNotFound = 14,
FontStyleNotFound = 15,
NotTrueTypeFont = 16,
UnsupportedGdiplusVersion = 17,
GdiplusNotInitialized = 18,
PropertyNotFound = 19,
PropertyNotSupported = 20,
ProfileNotFound = 21
} GpStatus;
typedef DWORD ARGB;
typedef void GpBitmap;
typedef void* DebugEventProc;
typedef GpStatus(WINGDIPAPI* NotificationHookProc)(ULONG_PTR* token);
typedef VOID(WINGDIPAPI* NotificationUnhookProc)(ULONG_PTR token);
typedef struct GdiplusStartupInput {
UINT32 GdiplusVersion;
DebugEventProc DebugEventCallback;
BOOL SuppressBackgroundThread;
BOOL SuppressExternalCodecs;
} GdiplusStartupInput;
typedef struct GdiplusStartupOutput {
NotificationHookProc NotificationHook;
NotificationUnhookProc NotificationUnhook;
} GdiplusStartupOutput;
GpStatus WINGDIPAPI GdiplusStartup(ULONG_PTR*, GDIPCONST GdiplusStartupInput*, GdiplusStartupOutput*);
VOID WINGDIPAPI GdiplusShutdown(ULONG_PTR);
GpStatus WINGDIPAPI
GdipCreateBitmapFromHICON(HICON hicon, GpBitmap** bitmap);
GpStatus WINGDIPAPI
GdipCreateHBITMAPFromBitmap(GpBitmap* bitmap, HBITMAP* hbmReturn, ARGB background);
VOID WINGDIPAPI GdipFree(VOID*);
#define IDM_SENDTOFIRST 0
TCHAR* FOLDER_SENDTO;
UINT idm_g = IDM_SENDTOFIRST;
TCHAR** PSENDTO; /* store the shourtcuts full path */
//
HBITMAP* hBmpImageA; /* MenuItemBitmap */
HINSTANCE g_hinst; /* My hinstance */
HMENU g_hmenuSendTo; /* Our SendTo popup */
LPSHELLFOLDER g_psfDesktop; /* The desktop folder */
UINT FORKING = 0; /* compatible with UAC focus changes */
LPSHELLFOLDER PIDL2PSF(LPITEMIDLIST pidl)
{
LPSHELLFOLDER psf = NULL;
if (pidl) {
g_psfDesktop->lpVtbl->BindToObject(g_psfDesktop, pidl, NULL, &IID_IShellFolder, (LPVOID*)&psf);
// failed: got NULL
}
return psf;
}
LPITEMIDLIST PidlFromPath(HWND hwnd, LPCTSTR pszPath)
{
LPITEMIDLIST pidl;
ULONG ulEaten;
DWORD dwAttributes;
HRESULT hres;
WCHAR* wszName;
//
wszName = calloc(T_MAX_PATH 1, sizeof(WCHAR));
#ifdef UNICODE
if (wcslen(pszPath) >= T_MAX_PATH) { return NULL; }
wcscpy(wszName, pszPath);
#else
if (!MultiByteToWideChar(CP_ACP, 0, pszPath, -1, wszName, T_MAX_PATH)) {
return NULL;
}
#endif
hres = g_psfDesktop->lpVtbl->ParseDisplayName(g_psfDesktop, hwnd, NULL, wszName, &ulEaten, &pidl, &dwAttributes);
free(wszName);
if (FAILED(hres)) {
return NULL;
}
return pidl;
}
LPSHELLFOLDER GetFolder(HWND hwnd, LPCTSTR pszPath)
{
LPITEMIDLIST pidl;
pidl = PidlFromPath(hwnd, pszPath);
return PIDL2PSF(pidl);
}
/*****************************************************************************
* GetUIObjectOfAbsPidl
* Given an absolute (desktop-relative) LPITEMIDLIST, get the
* specified UI object.
*****************************************************************************/
HRESULT GetUIObjectOfAbsPidls(HWND hwnd, LPITEMIDLIST* pidls, INT NumOfpidls, REFIID riid, LPVOID* ppvOut)
{
LPITEMIDLIST* pidlLasts;
LPSHELLFOLDER psf;
HRESULT hres;
INT i;
/* Just for safety's sake. */
*ppvOut = NULL;
pidlLasts = malloc(sizeof(LPITEMIDLIST) * NumOfpidls);
if (pidlLasts == NULL) return E_FAIL;
for (i = 0; i < NumOfpidls; i ) {
hres = SHBindToParent(pidls[i], &IID_IShellFolder, (LPVOID*)&psf, (LPCITEMIDLIST*)&pidlLasts[i]);
if (FAILED(hres)) goto Fail;
if (i < NumOfpidls - 1) psf->lpVtbl->Release(psf);
}
/* Now ask the parent for the the UI object of the child. */
hres = psf->lpVtbl->GetUIObjectOf(psf, hwnd, NumOfpidls, pidlLasts, riid, NULL, ppvOut);
/*
* Regardless of whether or not the GetUIObjectOf succeeded,
* we have no further use for the parent folder.
*/
Fail:
psf->lpVtbl->Release(psf);
return hres;
}
HRESULT GetUIObjectOfPaths(HWND hwnd, LPCTSTR* pszPaths, INT NumOfPaths, REFIID riid, LPVOID* ppvOut)
{
LPITEMIDLIST* pidls;
HRESULT hres;
INT i;
/* Just for safety's sake. */
*ppvOut = NULL;
pidls = calloc(NumOfPaths, sizeof(LPITEMIDLIST));
if (pidls == NULL) return E_FAIL;
for (i = 0; i < NumOfPaths; i ) {
pidls[i] = PidlFromPath(hwnd, pszPaths[i]);
if (pidls[i] == NULL) goto Fail;
}
hres = GetUIObjectOfAbsPidls(hwnd, pidls, NumOfPaths, riid, ppvOut);
Fail:
for (i = 0; i < NumOfPaths; i ) {
CoTaskMemFree(pidls[i]);
}
free(pidls);
return hres;
}
/*****************************************************************************
* DoDrop
* Drop a data object on a drop target.
*****************************************************************************/
void DoDrop(LPDATAOBJECT pdto, LPDROPTARGET pdt)
{
POINTL pt = { 0, 0 };
DWORD dwEffect;
HRESULT hres;
dwEffect = DROPEFFECT_COPY | DROPEFFECT_MOVE | DROPEFFECT_LINK;
hres = pdt->lpVtbl->DragEnter(pdt, pdto, MK_LBUTTON, pt, &dwEffect);
if (SUCCEEDED(hres) && dwEffect) {
hres = pdt->lpVtbl->Drop(pdt, pdto, MK_LBUTTON, pt, &dwEffect);
}
else {
hres = pdt->lpVtbl->DragLeave(pdt);
}
}
LPTSTR pidl_to_name(LPSHELLFOLDER psf, LPITEMIDLIST pidl, SHGDNF uFlags) {
HRESULT hres;
STRRET str;
LPTSTR pszName = NULL;
//
hres = psf->lpVtbl->GetDisplayNameOf(psf, pidl, uFlags, &str);
if (hres == S_OK) {
hres = StrRetToStr(&str, pidl, &pszName);
}
return pszName;
}
BOOL GethBitMapByPath(LPTSTR pszPath, HBITMAP* phbmp) {
SHFILEINFO ShFI = { 0 };
BOOL hasBmpImage = FALSE;
//
if (SUCCEEDED(SHGetFileInfo(pszPath, FILE_ATTRIBUTE_NORMAL, &ShFI, sizeof(SHFILEINFO), SHGFI_ICON | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES))) {
GpBitmap* bitmap = NULL;
if (GdipCreateBitmapFromHICON(ShFI.hIcon, &bitmap) == Ok) {
hasBmpImage = !(GdipCreateHBITMAPFromBitmap(bitmap, phbmp, 0));
GdipFree(bitmap);
}
DestroyIcon(ShFI.hIcon);
}
//
return hasBmpImage;
}
void FolderToMenu(HWND hwnd, HMENU hmenu, LPCTSTR pszFolder)
{
LPSHELLFOLDER psf;
HRESULT hres;
STRRET str;
/* OS_WOW6432 */
if ((PROC)(GetProcAddress(GetModuleHandle(_T("Shlwapi")), (LPCSTR)437))(30)) {
AppendMenu(hmenu, MF_GRAYED | MF_DISABLED | MF_STRING, idm_g, TEXT("64-bit OS needs 64-bit version :p"));
return;
}
psf = GetFolder(hwnd, pszFolder);
if (psf) {
LPENUMIDLIST peidl;
hres = psf->lpVtbl->EnumObjects(psf, hwnd,
SHCONTF_FOLDERS | SHCONTF_NONFOLDERS,
&peidl);
if (SUCCEEDED(hres)) {
LPITEMIDLIST pidl;
MENUITEMINFO mii;
MENUINFO mi;
BOOL hasBmpImage;
while (peidl->lpVtbl->Next(peidl, 1, &pidl, NULL) == S_OK) {
LPTSTR pszPath, pszName;
//
pszPath = pidl_to_name(psf, pidl, SHGDN_FORPARSING);
if (pszPath == NULL) { continue; }
pszName = pidl_to_name(psf, pidl, SHGDN_NORMAL);
if (pszName == NULL) { continue; }
//
// path should be enough
CoTaskMemFree(pidl);
//
// store path rather than retrial, as we check if it is dir.
PSENDTO = (TCHAR**)realloc(PSENDTO, sizeof(TCHAR*) * (idm_g - IDM_SENDTOFIRST 1));
if (PSENDTO == NULL) { continue; }
PSENDTO[idm_g] = _tcsdup(pszPath);
//
hBmpImageA = (HBITMAP*)realloc(hBmpImageA, sizeof(HBITMAP*) * (idm_g - IDM_SENDTOFIRST 1));
hasBmpImage = GethBitMapByPath(pszPath, &hBmpImageA[idm_g]);
//
if (PathIsDirectory(pszPath)) {
HMENU hSubMenu = CreatePopupMenu();
if (AppendMenu(hmenu, MF_ENABLED | MF_POPUP | MF_STRING, (UINT)hSubMenu, pszName)) {
mi.cbSize = sizeof(mi);
mi.fMask = MIM_HELPID;
mi.dwContextHelpID = idm_g;
SetMenuInfo(hSubMenu, &mi);
idm_g ;
//FolderToMenu(hwnd, hSubMenu, pszPath);
}
}
else {
if (AppendMenu(hmenu, MF_ENABLED | MF_STRING, idm_g, pszName)) {
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_DATA;
//mii.dwItemData = (ULONG_PTR)pidl;
if (hasBmpImage) {
mii.fMask |= MIIM_BITMAP;
mii.hbmpItem = hBmpImageA[idm_g];
}
SetMenuItemInfo(hmenu, idm_g, FALSE, &mii);
idm_g ;
}
}
//
CoTaskMemFree(pszPath);
CoTaskMemFree(pszName);
}
peidl->lpVtbl->Release(peidl);
}
psf->lpVtbl->Release(psf);
}
if (idm_g == IDM_SENDTOFIRST) {
AppendMenu(hmenu, MF_GRAYED | MF_DISABLED | MF_STRING, idm_g, TEXT("Send what sent to me to my sendto ^_^"));
}
}
void SendTo_OnInitMenuPopup(HWND hwnd, HMENU hmenu, UINT item, BOOL fSystemMenu)
{
if (GetMenuItemCount(hmenu) > 0) { return; }
//
if (hmenu == g_hmenuSendTo) { /* :p only top level */
FolderToMenu(hwnd, hmenu, FOLDER_SENDTO);
}
else {
MENUINFO mi;
mi.cbSize = sizeof(mi);
mi.fMask = MIM_HELPID;
if (GetMenuInfo(hmenu, &mi)) {
FolderToMenu(hwnd, hmenu, PSENDTO[mi.dwContextHelpID]);
}
}
}
void SendTo_SendToItem(HWND hwnd, int idm)
{
HRESULT hres;
FORKING = 1;
//
if (__argc == 1) {
ShellExecute(NULL, NULL, PSENDTO[idm], NULL, NULL, SW_SHOWDEFAULT);
}
else {
LPDATAOBJECT pdto;
LPDROPTARGET pdt;
hres = GetUIObjectOfPaths(hwnd, &PSENDTO[idm], 1, &IID_IDropTarget, (LPVOID*)&pdt);
if (SUCCEEDED(hres)) {
/* First convert all filenames to a data object. */
hres = GetUIObjectOfPaths(hwnd, __targv 1, __argc - 1, &IID_IDataObject, (LPVOID*)&pdto);
if (SUCCEEDED(hres)) {
/* Now drop the file on the drop target. */
DoDrop(pdto, pdt);
pdt->lpVtbl->Release(pdt);
}
}
pdto->lpVtbl->Release(pdto);
}
// Exit as done!
FORKING = 0;
PostQuitMessage(0);
}
void SendTo_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
SendTo_SendToItem(hwnd, id);
}
BOOL SendTo_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct)
{
g_hmenuSendTo = CreatePopupMenu();
return TRUE;
}
/* UAC focus changes!!! */
void SendTo_OnKillFocus(HWND hwnd, HWND hwndOldFocus)
{
if (FORKING == 0) PostQuitMessage(0);
}
LRESULT CALLBACK SendTo_WndProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
switch (uiMsg) {
HANDLE_MSG(hwnd, WM_CREATE, SendTo_OnCreate);
HANDLE_MSG(hwnd, WM_INITMENUPOPUP, SendTo_OnInitMenuPopup);
HANDLE_MSG(hwnd, WM_COMMAND, SendTo_OnCommand);
HANDLE_MSG(hwnd, WM_KILLFOCUS, SendTo_OnKillFocus);
}
return DefWindowProc(hwnd, uiMsg, wParam, lParam);
}
BOOL InitApp(void)
{
WNDCLASS wc;
HRESULT hr;
wc.style = 0;
wc.lpfnWndProc = SendTo_WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = g_hinst;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = TEXT("SendTo ");
RegisterClass(&wc);
hr = SHGetDesktopFolder(&g_psfDesktop);
if (FAILED(hr)) {
return FALSE;
}
FOLDER_SENDTO = calloc(T_MAX_PATH 1, sizeof(TCHAR));
if (FOLDER_SENDTO == NULL) { return FALSE; }
return TRUE;
}
void TermApp(void)
{
int i, n;
//
if (g_psfDesktop) {
g_psfDesktop->lpVtbl->Release(g_psfDesktop);
g_psfDesktop = NULL;
}
n = idm_g - IDM_SENDTOFIRST;
for (i = 0; i < n; i ) {
free(PSENDTO[i]);
DeleteObject(&hBmpImageA[i]);
}
free(PSENDTO);
//
free(FOLDER_SENDTO);
//
free((void**)hBmpImageA);
}
int WINAPI _tWinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPTSTR lpCmdLine, int nCmdShow)
{
MSG msg;
HWND hwnd;
HRESULT hrInit;
POINT pt = { 0, 0 };
//
ULONG_PTR gdiplusToken;
GdiplusStartupInput gdiplusStartupInput = { 1, NULL, FALSE, TRUE }; //MUST!
g_hinst = hinst;
if (!InitApp()) return 1;
if (GetFullPathName(TEXT("sendto"), T_MAX_PATH, FOLDER_SENDTO, NULL) == 0) { return 2; }
//
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
//
hrInit = CoInitialize(NULL);
hwnd = CreateWindow(
TEXT("SendTo "), /* Class Name */
TEXT("lifenjoiner"), /* Title */
WS_POPUP, /* Style */
CW_USEDEFAULT, CW_USEDEFAULT, /* Position */
0, 0, /* Size */
NULL, /* Parent */
NULL, /* No menu */
hinst, /* Instance */
0); /* No special parameters */
SetWindowLong(hwnd, GWL_EXSTYLE, WS_EX_TOOLWINDOW);
ShowWindow(hwnd, nCmdShow);
// run once!
GetCursorPos(&pt);
TrackPopupMenu(g_hmenuSendTo, TPM_LEFTALIGN, pt.x, pt.y, 0, hwnd, NULL);
//
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
TermApp();
//
GdiplusShutdown(gdiplusToken);
if (SUCCEEDED(hrInit)) {
CoUninitialize();
}
return 0;
}
I can compile it successfully in VS Terminal Prompt with cl.exe /MD /Os /DUNICODE /D_UNICODE /Femain_x64.exe main.c Ole32.lib shell32.lib user32.lib Comdlg32.lib Shlwapi.lib gdi32.lib gdiplus.lib bufferoverflowU.lib
. However, when I create a Visual Studio empty C project and add my main.c to it, it gives me this erro when trying to compile.
Why these errors doesn't happen when using cl.exe
? Is this a Visual Studio configuration issue?
CodePudding user response:
Visual Studio works on the project file, which contains a whole bunch of cl
and link
options, whereas when you run your cl
command manually you run it with different arguments. It's normal to get different results.
Also note that the error you see from your project is correct, if NumOfpidls
is 0 then your program will dereference a null
variable. Edit: actually you don't even initialize it, so you'll dereference garbage. That truly is terrible code.