I will build c-shared in golang -o config.dll.
Let's say the directory is c:\test\config.dll
In mail.dll, I'm going to open a configuration file.
This file is in the directory of config.dll.
c:\test\config.json
I'm calling it in c++ c:\test\c++.dll.
In c++ I use
{ // NB: XP+ solution!
HMODULE hModule = NULL;
GetModuleHandleEx(
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
(LPCTSTR)GetCurrentModule,
&hModule);
return hModule;
}
WCHAR path3[MAX_PATH + 1] = { 0 };
HMODULE hm = GetCurrentModule();
::GetModuleFileName(hm, path3, MAX_PATH);
PathRemoveFileSpec(path3);
// path3 c:\test\c++.dll
What is the equivalent of this in Go?
I try to use
os.Getwd()
runtime.Caller(1)
os.Args[0]
os.Executable()
I want to get directory c:\test\
You can use cgo to call the same function in whatever library it exists.
Related
I have created a simple dll using /MDd flag on windows 10 using msvc 2019 compilers. The dll only contains a simple add function (like in all the tutorials). After building this library I've copied it into a test folder for explicit linking. Basically, the test passes if I give it the full absolute path to the dll but it doesn't load if I only provide the name of the dll.
Here is the test code:
//test_add.cpp
#include <windows.h>
#include "gtest/gtest.h"
TEST(test, test_add_windows) {
#if defined(_WIN32) || defined (_WIN64)
typedef int (*addPtr)(int, int);
// full path works and the test passes
HINSTANCE hinstLib = LoadLibrary(TEXT("D:\\ACrossPlatformCppLibrary\\test\\ACrossPlatformCppLibrary.dll"));
// relative path does not work: library fails to load
// HINSTANCE hinstLib = LoadLibrary(TEXT("ACrossPlatformCppLibrary.dll"));
std::cout << hinstLib << std::endl;
ASSERT_NE(hinstLib, nullptr);
auto add = (addPtr) GetProcAddress(hinstLib, "add");
ASSERT_NE(add, nullptr);
int x = 5;
int y = 6;
int answer = add(x, y);
ASSERT_EQ(answer, 11);
BOOL fFreeResult = FreeLibrary(hinstLib);
#else
ASSERT_TRUE(true);
#endif
}
And my directory tree
I figured out the answer. I ran another test from the same file to get the current directory:
TEST(test, test2) {
char *fileExt;
char szDir[256]; //dummy buffer
GetFullPathName(".", 256, szDir, &fileExt);
printf("Full path: %s\nFilename: %s", szDir, fileExt);
}
Which outputs:
Full path: D:\ACrossPlatformCppLibrary\cmake-build-debug\test
The problem was that I copied the dll into the source directory, not the build directory.
I want to get a short path name with the function GetShortPathName on a network drive, F:\, with a Chinese folder name. When I run the EXE file from that folder I don't see it is able to obtain the short path name. When I do that from the C:\ drive everything works fine.
Here is my code:
#include"stdafx.h"
#include<windows.h>
#include<tchar.h>
#include<stdio.h>
#include <iostream>
using namespace std;
#define BUFSIZE 4096
bool GetIsCaseCorrect(const WCHAR* fileName)
{
bool result = false;
// Correct case by converting to short path and back to long
WCHAR shortFileName[_MAX_PATH];
if (GetShortPathName(fileName, shortFileName, _MAX_PATH) != 0)
{
wchar_t correctFileName[_MAX_PATH];
wcout << "ShortFile " << shortFileName;
GetLongPathName(shortFileName, correctFileName, _MAX_PATH);
result = wcscmp(fileName, correctFileName) != 0;
}
return result;
}
int main() {
bool ret;
HMODULE hModule = GetModuleHandleW(NULL);
WCHAR path[MAX_PATH];
GetModuleFileNameW(hModule, path, MAX_PATH);
ret = GetIsCaseCorrect(path);
getchar();
}
If I run this program the short path is not displayed on a non-system drive where folder is in Chinese.
My Windows OS is Windows 7.
As far as I know, the Windows 7 machine takes with the SMB 2.0 by default. GetShortPathNameW method is better supported with SMB 3.0.
You could follow this document below to enable SMB 3.0 with Win7.
https://support.microsoft.com/en-us/help/2696547/how-to-detect-enable-and-disable-smbv1-smbv2-and-smbv3-in-windows-and?wa=wsignin1.0%3Fwa%3Dwsignin1.0
Or you could follow this document below to check the volume state for Disable8dot3.
https://blogs.msdn.microsoft.com/winsdk/2013/10/09/getshortpathname-doesnt-return-short-path-name/
Best Regards,
Baron Bi
I'm trying to add auto-update functionality to the app I'm working on. My solution works well on Linux, but I'm running into weird problems on Windows.
After unpacking the update package I'm trying to move it to the destination directory using the following function:
inline void recursiveMoveOrCopy(QDir source, QDir dest, bool move)
{
auto files = source.entryInfoList(QDir::Files);
auto dirs = source.entryInfoList(QDir::Dirs|QDir::NoDotAndDotDot);
// move / copy files
bool success = QDir{}.mkpath(dest.path());
if (!success){
throw std::runtime_error(qs("Could not crate directory %1")
.arg(dest.path()).toStdString());
}
qDebug()<<"created directory"<<dest.path();
dumpvar(QDir{}.exists(dest.path()));
for (auto& file: files){
QString sourcePath = file.filePath();
QString fileName = file.fileName();
QString destPath = dest.filePath(fileName);
QString backupPath = destPath + "_bck";
bool success;
bool backup = false;
if (QFile::exists(destPath))
backup = QFile::rename(destPath, backupPath);
ON_EXIT{
if (backup) {
QFile::remove(destPath);
QFile::rename(backupPath, destPath);
}
};
if (move) success = QFile::rename(sourcePath, destPath);
else success = QFile::copy(sourcePath, destPath);
qDebug()<<qs("move from %1 to %2 was %3").arg(sourcePath, destPath, success?"successful":"not sucessful");
if (success && backup){
QFile::remove(backupPath);
backup = false;
}
if (!success){
throw std::runtime_error(qs("Failed to %1 file %2 to %3")
.arg(move?"move":"copy")
.arg(sourcePath)
.arg(destPath)
.toStdString());
}
}
// recursively move/copy dirs
for (auto &dir: dirs) recursiveMoveOrCopy(dir.filePath(), dest.filePath(dir.fileName()), move);
}
I made a small package for testing with just 2 files and 1 directory:
$ tree .
.
├── katalog
│ └── plik
└── plik2
When I try to install this "update" the following is written to debug output by the move function:
"moving C:/Users/piotrek/AppData/Local/Temp/dres-update-image to C:/Program Files (x86)/DRES"
created directory "C:/Program Files (x86)/DRES"
QDir{}.exists(dest.path()) = true
"move from C:/Users/piotrek/AppData/Local/Temp/dres-update-image/plik2 to C:/Program Files (x86)/DRES/plik2 was successful"
created directory "C:/Program Files (x86)/DRES/katalog"
QDir{}.exists(dest.path()) = true
"move from C:/Users/piotrek/AppData/Local/Temp/dres-update-image/katalog/plik to C:/Program Files (x86)/DRES/katalog/plik was successful"
As in: every single operation succeeded. But when I look into the target directory, the directory katalog doesn't exist (the file plik2 does however).
Note that even though the directory does NOT exist, QDir::exists reports that it does.
It's not a permission problem, when I was testing this I modified C:/Program Files (x86)/DRES to give Everyone full access.
Please tell me I'm not crazy. What the hell is going on here?
EDIT: Thanks to Rudolfs' suggestion to use Process Monitor I discovered the the files are actually being written to C:\Users\piotrek\AppData\Local\VirtualStore\Program Files (x86)\DRES. What exactly is going on here and how do I fix this?
Ok, I figured it out.
I had to use the following code to disable VirtualStore virtualization for the whole app:
#ifdef Q_OS_WIN32
#include <windows.h>
QString getWinError()
{
DWORD dw = GetLastError();
LPWSTR lpMsgBuf = NULL;
FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR) &lpMsgBuf,
0, NULL );
QString str = QString::fromWCharArray(lpMsgBuf);
LocalFree(lpMsgBuf);
return str;
}
bool disableVirtualStore()
{
HANDLE token;
DWORD tokenInformation = 0;
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token)){
qWarning()<<getWinError();
return FALSE;
}
ON_EXIT{
CloseHandle(token);
};
if(!SetTokenInformation(token, TokenVirtualizationEnabled,
&tokenInformation, sizeof(tokenInformation))) {
qWarning()<<getWinError();
return FALSE;
}
return TRUE;
}
#endif
Now I can normally write to all folders that I have write access to, and since Windows no longer lies to me about having write access, I can start an elevated helper app to move files to folders where I don't have write permission.
In vs c++ I used the following code to use some functions in a dll file that I don't have its header
#import "dll path"
HRESULT hr = CoInitialize(NULL);
if (hr==S_OK)
{cout<<"INITIALIZED\n";}
Trans_ATLLib::ITransCriptPtr Trans;
hr = Trans.CreateInstance(__uuidof(Trans_ATLLib::TransCript));
if (hr==S_OK)
{cout<<"INSTANCE CREATED\n";}
hr =Trans->EnableLastCharTashkeel(true);
if (hr==S_OK)
{cout<<"EnableLastCharTashkeel DONE\n";}
hr =Trans->EnableEmphaticLAM_RAA(true);
if (hr==S_OK)
{cout<<"EnableEmphaticLAM_RAA DONE\n";}
VARIANT_BOOL test;
test = Trans->SetText(arabic_string);
if (test==0)
{cout<<"error in setting the arabic sting\n";}
string result;
result = Trans->GetResult();
istringstream iss(result);
vector<string> phonemes;
copy(istream_iterator<string>(iss),istream_iterator<string>(),back_inserter<vector<string> >(phonemes));
return phonemes;
}
But I found that Qt doesn't use the same method.
Can any one help me in calling these functions in Qt?
Thanks in advance.
If you use c++ - do the same! Qt is a set of libraries, not a different programming language - call to winApi everywhere you need, but don't forget that it is not portable.
From Visual C++, how do I get the path to the current user's My Documents folder?
Edit:
I have this:
TCHAR my_documents[MAX_PATH];
HRESULT result = SHGetFolderPath(NULL, CSIDL_MYDOCUMENTS, NULL, SHGFP_TYPE_CURRENT, my_documents);
However, result is coming back with a value of E_INVALIDARG. Any thoughts as to why this might be?
It depends on how old of a system you need compatibility with. For old systems, there's SHGetSpecialFolderPath. For somewhat newer systems, there's SHGetFolderPath. Starting with Vista, there's SHGetKnownFolderPath.
Here's some demo code that works, at least on my machine:
#include <windows.h>
#include <iostream>
#include <shlobj.h>
#pragma comment(lib, "shell32.lib")
int main() {
CHAR my_documents[MAX_PATH];
HRESULT result = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, my_documents);
if (result != S_OK)
std::cout << "Error: " << result << "\n";
else
std::cout << "Path: " << my_documents << "\n";
return 0;
}
Use the SHGetFolderPath Windows API function and request CSIDL_MYDOCUMENTS.
Using Visual Studio 2017 with an MFC application under Windows 10 I am using the following code snippet with SHGetKnownFolderPath function to get the current user's Documents folder:
#include <string> // include file for C++ native strings
// . . . other code.
PWSTR ppszPath; // variable to receive the path memory block pointer.
HRESULT hr = SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &ppszPath);
std::wstring myPath;
if (SUCCEEDED(hr)) {
myPath = ppszPath; // make a local copy of the path
}
CoTaskMemFree(ppszPath); // free up the path memory block
Note that the documentation has this to say about the path variable usage and the path returned:
ppszPath [out]
Type: PWSTR*
When this method returns, contains the address of a pointer to a
null-terminated Unicode string that specifies the path of the known
folder. The calling process is responsible for freeing this resource
once it is no longer needed by calling CoTaskMemFree. The returned
path does not include a trailing backslash. For example, "C:\Users" is
returned rather than "C:\Users\".
For a list of the FOLDERID_ arguments possible see the MSDN article KNOWN_FOLDER_FLAG enumeration.
Note that CSIDL_PERSONAL will not return the desired folder if the user has changed the default save folder in the Win7 Documents library. To get the right folder, you need to use SHLoadLibraryFromKnownFolder to obtain the IShellLibrary for the Documents library, use IShellLibrary::GetDefaultSaveFolder to get the IShellItem for the library's default save folder, and finally use IShellItem::GetDisplayName to get the folder name.
std::string GetMyDocumentsFolderPath()
{
wchar_t Folder[1024];
HRESULT hr = SHGetFolderPathW(0, CSIDL_MYDOCUMENTS, 0, 0, Folder);
if (SUCCEEDED(hr))
{
char str[1024];
wcstombs(str, Folder, 1023);
return str;
}
else return "";
}
cout<<GetMyDocumentsFolderPath()<<endl;
how about this solution? Its working fine for me.