When to use _Notnull_ in C++? - c++

Can someone provide insight when to use _Notnull_? I'm using Visual Studio 2019 and here is my code:
#include <windows.h>
#include <vector>
void WriteIt(_Notnull_ CONST WCHAR* sMsg, _Notnull_ CONST WCHAR* sFileName)
{
FILE* stream;
errno_t err = _wfopen_s(&stream, sFileName, L"a+");
if (err == 0)
if (stream)
{
fwprintf_s(stream, L"%s", sMsg);
fclose(stream);
}
}
int main()
{
WCHAR *sMessage = new WCHAR[16]();
WCHAR *sFile = NULL;
sFile = NULL;
WriteIt(sMessage, sFile);
}
Yet, the _Notnull_ lets the function run. I can't find any documentation on how/why to use it with examples.

Thanks #François Andrieux. Looks like it is used when doing a code analysis from within Visual Studio, where the analyzer can pinpoint if an incoming pointer could be NULL. Here is what the code analyzer says with _Notnull_ is included: Warning C6387 'sFile' could be '0': this does not adhere to the specification for the function 'WriteIt'. Very helpful!

Related

C++ how to find file path of the file I am working on in my program [duplicate]

I want to create a file in the current directory (where the executable is running).
My code:
LPTSTR NPath = NULL;
DWORD a = GetCurrentDirectory(MAX_PATH,NPath);
HANDLE hNewFile = CreateFile(NPath,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
I get exception at GetCurrentDirectory().
Why am I getting an exception?
I would recommend reading a book on C++ before you go any further, as it would be helpful to get a firmer footing. Accelerated C++ by Koenig and Moo is excellent.
To get the executable path use GetModuleFileName:
TCHAR buffer[MAX_PATH] = { 0 };
GetModuleFileName( NULL, buffer, MAX_PATH );
Here's a C++ function that gets the directory without the file name:
#include <windows.h>
#include <string>
#include <iostream>
std::wstring ExePath() {
TCHAR buffer[MAX_PATH] = { 0 };
GetModuleFileName( NULL, buffer, MAX_PATH );
std::wstring::size_type pos = std::wstring(buffer).find_last_of(L"\\/");
return std::wstring(buffer).substr(0, pos);
}
int main() {
std::cout << "my directory is " << ExePath() << "\n";
}
The question is not clear whether the current working directory is wanted or the path of the directory containing the executable.
Most answers seem to answer the latter.
But for the former, and for the second part of the question of creating the file, the C++17 standard now incorporates the filesystem library which simplifies this a lot:
#include <filesystem>
#include <iostream>
std::filesystem::path cwd = std::filesystem::current_path() / "filename.txt";
std::ofstream file(cwd.string());
file.close();
This fetches the current working directory, adds the filename to the path and creates an empty file. Note that the path object takes care of os dependent path handling, so cwd.string() returns an os dependent path string. Neato.
GetCurrentDirectory does not allocate space for the result, it's up to you to do that.
TCHAR NPath[MAX_PATH];
GetCurrentDirectory(MAX_PATH, NPath);
Also, take a look at Boost.Filesystem library if you want to do this the C++ way.
An easy way to do this is:
int main(int argc, char * argv[]){
std::cout << argv[0];
std::cin.get();
}
argv[] is pretty much an array containing arguments you ran the .exe with, but the first one is always a path to the executable. If I build this the console shows:
C:\Users\Ulisse\source\repos\altcmd\Debug\currentdir.exe
IMHO here are some improvements to anon's answer.
#include <windows.h>
#include <string>
#include <iostream>
std::string GetExeFileName()
{
char buffer[MAX_PATH];
GetModuleFileName( NULL, buffer, MAX_PATH );
return std::string(buffer);
}
std::string GetExePath()
{
std::string f = GetExeFileName();
return f.substr(0, f.find_last_of( "\\/" ));
}
#include <iostream>
#include <stdio.h>
#include <dirent.h>
std::string current_working_directory()
{
char* cwd = _getcwd( 0, 0 ) ; // **** microsoft specific ****
std::string working_directory(cwd) ;
std::free(cwd) ;
return working_directory ;
}
int main(){
std::cout << "i am now in " << current_working_directory() << endl;
}
I failed to use GetModuleFileName correctly. I found this work very well.
just tested on Windows, not yet try on Linux :)
WCHAR path[MAX_PATH] = {0};
GetModuleFileName(NULL, path, MAX_PATH);
PathRemoveFileSpec(path);
Please don't forget to initialize your buffers to something before utilizing them. And just as important, give your string buffers space for the ending null
TCHAR path[MAX_PATH+1] = L"";
DWORD len = GetCurrentDirectory(MAX_PATH, path);
Reference
You should provide a valid buffer placeholder.
that is:
TCHAR s[100];
DWORD a = GetCurrentDirectory(100, s);
#include <windows.h>
using namespace std;
// The directory path returned by native GetCurrentDirectory() no end backslash
string getCurrentDirectoryOnWindows()
{
const unsigned long maxDir = 260;
char currentDir[maxDir];
GetCurrentDirectory(maxDir, currentDir);
return string(currentDir);
}
You can remove the filename from GetModuleFileName() with more elegant way:
TCHAR fullPath[MAX_PATH];
TCHAR driveLetter[3];
TCHAR directory[MAX_PATH];
TCHAR FinalPath[MAX_PATH];
GetModuleFileName(NULL, fullPath, MAX_PATH);
_splitpath(fullPath, driveLetter, directory, NULL, NULL);
sprintf(FinalPath, "%s%s",driveLetter, directory);
Hope it helps!
GetCurrentDirectory() gets the current directory which is where the exe is invoked from. To get the location of the exe, use GetModuleFileName(NULL ...). if you have the handle to the exe, or you can derive it from GetCommandLine() if you don't.
As Mr. Butterworth points out, you don't need a handle.
Why does nobody here consider using this simple code?
TCHAR szDir[MAX_PATH] = { 0 };
GetModuleFileName(NULL, szDir, MAX_PATH);
szDir[std::string(szDir).find_last_of("\\/")] = 0;
or even simpler
TCHAR szDir[MAX_PATH] = { 0 };
TCHAR* szEnd = nullptr;
GetModuleFileName(NULL, szDir, MAX_PATH);
szEnd = _tcsrchr(szDir, '\\');
*szEnd = 0;
I guess, that the easiest way to locate the current directory is to cut it from command line args.
#include <string>
#include <iostream>
int main(int argc, char* argv[])
{
std::string cur_dir(argv[0]);
int pos = cur_dir.find_last_of("/\\");
std::cout << "path: " << cur_dir.substr(0, pos) << std::endl;
std::cout << "file: " << cur_dir.substr(pos+1) << std::endl;
return 0;
}
You may know that every program gets its executable name as first command line argument. So you can use this.
Code snippets from my CAE project with unicode development environment:
/// #brief Gets current module file path.
std::string getModuleFilePath() {
TCHAR buffer[MAX_PATH];
GetModuleFileName( NULL, buffer, MAX_PATH );
CT2CA pszPath(buffer);
std::string path(pszPath);
std::string::size_type pos = path.find_last_of("\\/");
return path.substr( 0, pos);
}
Just use the templete CA2CAEX or CA2AEX which calls the internal API ::MultiByteToWideChar or ::WideCharToMultiByte。
if you don't want to use std, you can use this code:
char * ExePath()
{
static char buffer[MAX_PATH] = { 0 };
GetModuleFileName( NULL, buffer, MAX_PATH );
char * LastSlash = strrchr(buffer, '\\');
if(LastSlash == NULL)
LastSlash = strrchr(buffer, '/');
buffer[LastSlash-buffer] = 0;
return buffer;
}
I simply use getcwd() method for that purpose in Windows, and it works pretty well. The code portion is like following:
char cwd[256];
getcwd(cwd, 256);
string cwd_str = string(cwd);
The <unistd.h> library has to be added though.
To find the directory where your executable is, you can use:
TCHAR szFilePath[_MAX_PATH];
::GetModuleFileName(NULL, szFilePath, _MAX_PATH);
If you are using the Poco library, it's a one liner and it should work on all platforms I think.
Poco::Path::current()
On a give Windows C++ IDE I went crude and it was simple, reliable, but slow:
system( "cd" );
String^ exePath = Application::ExecutablePath;<br>
MessageBox::Show(exePath);
In Windows console, you can use the system command CD (Current Directory):
std::cout << "Current Directory = ";
system("cd"); // to see the current executable directory

C6001 - initialize memory with new?

Here is my named pipe client sample code for sending a string to a named pipe server using Visual Studio 2019 with ISO C++ 14:
#include <windows.h>
#include <strsafe.h>
void main()
{
DWORD cbRead = 0;
DWORD rv = ERROR_SUCCESS;
WCHAR *sPipename = new WCHAR [1024]();
WCHAR *chReadBuf = new WCHAR [1024]();
WCHAR *sMsgToSend = new WCHAR [1024]();
StringCchCopyW(sPipename, 1024, L"\\\\.\\pipe\\{23E0D6C2-A718-4C91-A81F-4069356686C5}");
StringCchCopy(sMsgToSend, 1024, L"test");
CallNamedPipeW(sPipename, sMsgToSend, (DWORD) (wcslen(sMsgToSend)+1)*sizeof(TCHAR), chReadBuf, 1024*sizeof(TCHAR), &cbRead, 5000);
}
I'm getting C6001 errors on the three variables in the function call, with the compiler showing a warning about not being initialized? They are initialized with parenthesis '( )'.
The suggested fix is to put a {} before the '=' sign. Which gives an error. I googled and searched but could not find an answer to this specific issue.
Thank you, any help is appreciated.

how to copy text to the clipborad in c++?

I am a new programmer in c++ and I can't understand how to use the clipboard to copy and paste like in any other program with text. Example please?
I am using Code::Blocks 16.01 MinGW32 g++ windows 10.
SetClipboardData should handle it.
glob = GlobalAlloc(GMEM_FIXED,32);
memcpy(glob,"it works",9);
OpenClipboard(hWnd);
EmptyClipboard();
SetClipboardData(CF_TEXT,glob);
CloseClipboard();
EDIT
This will get data out of clipboard and return that data in string.
std::string GetClipboardText()
{
OpenClipboard(nullptr);
HANDLE hData = GetClipboardData(CF_TEXT);
char * pszText = static_cast<char*>( GlobalLock(hData) );
std::string text( pszText );
GlobalUnlock( hData );
CloseClipboard();
return text;
}
For a cross-platform solution, you may use a library like ClipboardXX.
Usage example:
#include "clipboard.hpp"
#include <string>
int main()
{
clipboardxx::clipboard clipboard;
// copy
clipboard << "text you wanna copy";
// paste
std::string paste_text;
clipboard >> paste_text;
}
This may be preferrable for a Windows only software as well due to modern C++ being nicer to work with than the plain old Windows API.
Another useful library might be clip but I didn't test it myself.
Usage example:
#include "clip.h"
#include <iostream>
int main()
{
clip::set_text("Hello World");
std::string value;
clip::get_text(value);
std::cout << value << "\n";
}

C file cannot be compiled in c++ Visual Studio

For some reason I can no longer compile a c file in my c++ clr console application. It worked before without the clr support, I also switched my project to compile as /TP still not working. Any help would be greatly appreciated.
Error
Severity Code Description Project File Line Suppression State
Error C2664 'int strcmp(const char *,const char *)': cannot convert argument 1 from 'WCHAR [260]' to 'const char *'
snowkill.c
#include "snowkill.h"
void killProcessByName(WCHAR *filename)
{
HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, NULL);
PROCESSENTRY32 pEntry;
pEntry.dwSize = sizeof(pEntry);
BOOL hRes = Process32First(hSnapShot, &pEntry);
while (hRes)
{
if (strcmp(pEntry.szExeFile, filename) == 0)
{
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, 0,
(DWORD)pEntry.th32ProcessID);
if (hProcess != NULL && pEntry.th32ProcessID != GetCurrentProcessId())
{
TerminateProcess(hProcess, 9);
CloseHandle(hProcess);
}
}
hRes = Process32Next(hSnapShot, &pEntry);
}
CloseHandle(hSnapShot);
}
snowkill.h
#pragma once
#include "stdafx.h"
#include <windows.h>
#include <process.h>
#include <Tlhelp32.h>
#include <winbase.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
void killProcessByName(WCHAR *filename);
#ifdef __cplusplus
}
#endif
main.cpp
#include "stdafx.h"
#include "snowkill.h"
#include "motion.h"
#include "info.h"
#include "flushsound.h"
#include "snowserial.h"
using namespace System;
bool on() {
return true;
}
bool off() {
return false;
}
int main()
{
listenoncommport();
for (;;) {
string onoff = checkfile();
if (onoff == "1")
{
//detected();
}
else
{
WCHAR *proccc = L"firefox.exe";
killProcessByName(proccc);
//notdetected();
}
Sleep(5000);
}
return 0;
}
You could change every instance of WCHAR to TCHAR so text setting is "generic", or as already mentioned, change the project property character set to be Unicode only.
void killProcessByName(TCHAR *filename)
/* ... */
if (_tcscmp(pEntry.szExeFile, filename) == 0) /* replaced strcmp */
/* ... */
#include <windows.h> /* needed in order to use TEXT() macro */
/* ... */
TCHAR *proccc = TEXT("firefox.exe"); /* TEXT() is a <windows.h> macro */
Use TCHAR type everywhere if the functions involved are not WCHAR specific. That would allow project setting to build either ANSI/ASCII (not set) or Unicode.
Note that Process32First and Process32Next use TCHAR.
This is mostly for legacy, since Windows 2000 and later API functions use Unicode internally, converting ANSI/ASCII to Unicode as needed, while Windows NT and older API functions use ANSI/ASCII.
However, typically many or most text files (such as source code) are ANSI/ASCII and not Unicode, and it's awkward to have to support Unicode for Windows API and then ANSI/ASCII for text files in the same program, and for those projects I use ANSI/ASCII.
By using the TCHAR based generic types, I can share common code with projects that use Unicode and with projects that use ANSI/ASCII.
The error message is clear: you have an error at this precise line:
if (strcmp(pEntry.szExeFile, filename) == 0)
Because your arguments are not of char* type as expected by strcmp but WCHAR* types. You should use wcscmp instead, which is basically the same function, but working with wchar_t* type.
szExeFile in tagPROCESSENTRY32 is declared as TCHAR, which will be a 1-byte char when compiling with Character Set set to 'Not Set' or 'Multibyte'. Set Character Set in your project settings to Use Unicode Character Set to fix the problem.
Also, use wcscmp to compare WCHAR types.

Incompatible with parameter of type "LPCWSTR"

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <iostream>
#include <dos.h>
using namespace std;
class Dir
{
public:
char* cat;
Dir()
{
cout << "(C:/*)\n";
cat = new char[50];
cin >> cat;
}
void virtual ShowFiles()
{
}
};
class Inside : public Dir
{
public:
void virtual ShowFiles()
{
HANDLE hSearch;
WIN32_FIND_DATA pFileData;
hSearch = FindFirstFile(cat, &pFileData);
if (hSearch != INVALID_HANDLE_VALUE)
do
{
// if ((pFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
cout << pFileData.cFileName << "\n";
} while (FindNextFile(hSearch, &pFileData));
FindClose(hSearch);
}
};
int main()
{
Dir *obj1[2];
obj1[1] = new Inside;
obj1[1]->ShowFiles();
return 0;
}
So I have a program, I need to show with dynamic char cat all file in directory, but it is compilable in Borland C++ but in Visual Studio 15 + Resharper it doesn't work. Severity Code Description Project File Line
Error (active) argument of type "char *" is incompatible with parameter of type "LPCWSTR"
To compile your code in Visual C++ you need to use Multi-Byte char WinAPI functions instead of Wide char ones.
Set Project -> Properties -> Advanced (or. General for older versions) -> Character Set option to Use Multi-Byte Character Set
also see the screenshot
I actually found another way to resolve this error since above method did not work for me.
I casted all my constant character strings with (LPCWSTR). The solution looks like this
Earlier
MessageBox(NULL,"Dialog creation failed! Aborting..", "Error", MB_OK);
After casting to LPCWSTR
MessageBox(NULL, (LPCWSTR) "Dialog creation failed! Aborting..", (LPCWSTR) "Error", MB_OK);
So just copying the (LPCWSTR) and pasting wherever this error was generated resolved all my errors.
Another way to come by this issue, is to use the Lmacro in front of your string.
MessageBox(NULL, L"Dialog creation failed! Aborting..", L"Error", MB_OK);
See: What does the 'L' in front a string mean in C++?
or
L prefix for strings in C++
you can use wchar_t
class Dir
{
public:
wchar_t* cat;
Dir()
{
wcout << "(C:/*)\n";
cat = new wchar_t[50];
wcin >> cat;
}
void virtual ShowFiles()
{
}
};
In Visual Studio 2013 and later, the MFC libraries for multi-byle character encoding (MBCS) will be provided as an add-on to Visual Studio
It will work for any settings:
#include <tchar.h>
MessageBox(NULL, _T("Dialog creation failed! Aborting.."), _T("Error"), MB_OK);