Can anyone plz help me, how to save my QtableView as a Excel File. I have a QTableView and a QPushButton (Save Button). If i enter the values in my QtableView and if i click the Save Buttton the QTableView items should be saved as Excel File. Plz Help me. Thanks..
Have a look at this thread My-approach-to-export-QTableView-data-to-a-Microsoft-Excel-file. I got this link by asking Google for: QTableView save. For the solution there you need a Qt with ODBC enabled which is not the default.
You can also study the fine documentation that contains e.g. an Address Book Example that includes a writeToFile function. You can start from there and search e.g. for information about the CSV format.
this link worked for me :
http://www.qtcn.org/bbs/simple/?t47265.html
1-you should also use below code in .pro file.
QT += sql
2-you should use #include "exportexcelobject.h" in your file that wanna export to excel.
See the code sample:
ExcelExportHelper.h
#ifndef EXCELHELPER_H
#define EXCELHELPER_H
#include <ActiveQt/qaxobject.h>
#include <ActiveQt/qaxbase.h>
#include <QString>
//Expected in .pro file: QT += axcontainer
//Application must be of UI type for ActiveX work.
class ExcelExportHelper
{
public:
ExcelExportHelper(const ExcelExportHelper& other) = delete;
ExcelExportHelper& operator=(const ExcelExportHelper& other) = delete;
ExcelExportHelper(bool closeExcelOnExit = false);
void SetCellValue(int lineIndex, int columnIndex, const QString& value);
void SaveAs(const QString& fileName);
~ExcelExportHelper();
private:
QAxObject* m_excelApplication;
QAxObject* m_workbooks;
QAxObject* m_workbook;
QAxObject* m_sheets;
QAxObject* m_sheet;
bool m_closeExcelOnExit;
};
#endif // EXCELHELPER_H
ExcelExportHelper.cpp
#include <ActiveQt/qaxobject.h>
#include <ActiveQt/qaxbase.h>
#include <QString>
#include <QFile>
#include <stdexcept>
using namespace std;
#include "ExcelExportHelper.h"
ExcelExportHelper::ExcelExportHelper(bool closeExcelOnExit)
{
m_closeExcelOnExit = closeExcelOnExit;
m_excelApplication = nullptr;
m_sheet = nullptr;
m_sheets = nullptr;
m_workbook = nullptr;
m_workbooks = nullptr;
m_excelApplication = nullptr;
m_excelApplication = new QAxObject( "Excel.Application", 0 );//{00024500-0000-0000-C000-000000000046}
if (m_excelApplication == nullptr)
throw invalid_argument("Failed to initialize interop with Excel (probably Excel is not installed)");
m_excelApplication->dynamicCall( "SetVisible(bool)", false ); // hide excel
m_excelApplication->setProperty( "DisplayAlerts", 0); // disable alerts
m_workbooks = m_excelApplication->querySubObject( "Workbooks" );
m_workbook = m_workbooks->querySubObject( "Add" );
m_sheets = m_workbook->querySubObject( "Worksheets" );
m_sheet = m_sheets->querySubObject( "Add" );
}
void ExcelExportHelper::SetCellValue(int lineIndex, int columnIndex, const QString& value)
{
QAxObject *cell = m_sheet->querySubObject("Cells(int,int)", lineIndex, columnIndex);
cell->setProperty("Value",value);
delete cell;
}
void ExcelExportHelper::SaveAs(const QString& fileName)
{
if (fileName == "")
throw invalid_argument("'fileName' is empty!");
if (fileName.contains("/"))
throw invalid_argument("'/' character in 'fileName' is not supported by excel!");
if (QFile::exists(fileName))
{
if (!QFile::remove(fileName))
{
throw new exception(QString("Failed to remove file '%1'").arg(fileName).toStdString().c_str());
}
}
m_workbook->dynamicCall("SaveAs (const QString&)", fileName);
}
ExcelExportHelper::~ExcelExportHelper()
{
if (m_excelApplication != nullptr)
{
if (!m_closeExcelOnExit)
{
m_excelApplication->setProperty("DisplayAlerts", 1);
m_excelApplication->dynamicCall("SetVisible(bool)", true );
}
if (m_workbook != nullptr && m_closeExcelOnExit)
{
m_workbook->dynamicCall("Close (Boolean)", true);
m_excelApplication->dynamicCall("Quit (void)");
}
}
delete m_sheet;
delete m_sheets;
delete m_workbook;
delete m_workbooks;
delete m_excelApplication;
}
Usage:
try
{
const QString fileName = "g:\\temp\\kaka2.xlsx";
ExcelExportHelper helper;
helper.SetCellValue(1,1,"Test-11");
helper.SetCellValue(1,2,"Test-12");
helper.SaveAs(fileName);
}
catch (const exception& e)
{
QMessageBox::critical(this, "Error - Demo", e.what());
}
Related
I have created an MFC dialog based application to study tab control. In a tab control it is possible to set application specific data to each tab.
I am trying to understand how to set/retrieve the data for individual tabs of the tab control.
Here is a sample application I am creating. Each tab of the control is supposed to store some GPU info.
As I understand, there are 3 steps to add application specific data.
Create a user defined structure, whose 1st member should be of type TCITEMHEADER.
struct GPU {
std::wstring name;
int busid;
};
struct tabData {
TCITEMHEADER tabItemHeader;
GPU gpu;
};
Tell the tab control about the extra bytes, the user defined structure is going to take. This I am doing in DoDataExchange().
int extraBytes = sizeof(tabData) - sizeof(TCITEMHEADER);
auto status = tabCtrl1.SetItemExtra(extraBytes);
Set user defined data while adding tabs.
static int tabCtr = 0;
tabData td;
td.tabItemHeader.pszText = _T("TabX");
td.tabItemHeader.mask = TCIF_TEXT;
td.gpu.name = L"AMD NVIDIA";
td.gpu.busid = 101;
TabCtrl_InsertItem(tabCtrl1.GetSafeHwnd(), tabCtr, &td);
Now to get the data, we simply have to call TabCtrl_GetItem().
tabData td2;
td2.tabItemHeader.pszText = new TCHAR[20];
td2.tabItemHeader.cchTextMax = 20;
td2.tabItemHeader.mask = TCIF_TEXT;
td2.gpu.busid = 0;
TabCtrl_GetItem(tabCtrl1.GetSafeHwnd(), 0, &td2);
But as we can see in the following image. I do get the tab text (pszText member - data Item 1 in image), but not the extra data that I had associated with it previously (Data Items 2 and 3 in image).
Which step am I missing?
Why is the structure associated with application defined data not getting populated?
Additional Info
Here is the complete code for the application.
CPP File:
// tabCtrlStackOverflowDlg.cpp : implementation file
//
#include "stdafx.h"
#include "tabCtrlStackOverflow.h"
#include "tabCtrlStackOverflowDlg.h"
#include "afxdialogex.h"
#include <string>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
struct GPU {
std::wstring name;
int busid;
};
struct tabData
{
TCITEMHEADER tabItemHeader;
GPU gpu;
};
CtabCtrlStackOverflowDlg::CtabCtrlStackOverflowDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(IDD_TABCTRLSTACKOVERFLOW_DIALOG, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CtabCtrlStackOverflowDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_TAB1, tabCtrl1);
int extraBytes = sizeof(tabData) - sizeof(TCITEMHEADER);
auto status = tabCtrl1.SetItemExtra(extraBytes);
wchar_t *t = status ? L"SetItemExtra() success" : L"SetItemExtra() fail";
GetDlgItem(IDC_STATUSTEXT)->SetWindowTextW(t);
}
BEGIN_MESSAGE_MAP(CtabCtrlStackOverflowDlg, CDialogEx)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDADDTAB, &CtabCtrlStackOverflowDlg::OnBnClickedAddtab)
ON_BN_CLICKED(IDC_GETITEM0, &CtabCtrlStackOverflowDlg::OnBnClickedGetitem0)
ON_BN_CLICKED(IDCLOSE, &CtabCtrlStackOverflowDlg::OnBnClickedClose)
END_MESSAGE_MAP()
// CtabCtrlStackOverflowDlg message handlers
BOOL CtabCtrlStackOverflowDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
return TRUE; // return TRUE unless you set the focus to a control
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CtabCtrlStackOverflowDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
// The system calls this function to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CtabCtrlStackOverflowDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CtabCtrlStackOverflowDlg::OnBnClickedAddtab()
{
static int tabCtr = 0;
tabData td;
td.tabItemHeader.pszText = _T("TabX");
td.tabItemHeader.mask = TCIF_TEXT;
td.gpu.name = L"AMD NVIDIA";
td.gpu.busid = 101;
int status = TabCtrl_InsertItem(tabCtrl1.GetSafeHwnd(), tabCtr, &td);
wchar_t *t = L"";
if (status == -1)
{
t = L"TabCtrl_InsertItem() Fail";
}
else
{
t = L"TabCtrl_InsertItem() success";
}
GetDlgItem(IDC_STATUSTEXT)->SetWindowTextW(t);
tabCtr++;
}
void CtabCtrlStackOverflowDlg::OnBnClickedGetitem0()
{
tabData td2;
td2.tabItemHeader.pszText = new TCHAR[20];
td2.tabItemHeader.cchTextMax = 20;
td2.tabItemHeader.mask = TCIF_TEXT;
td2.gpu.busid = 0;
if (TabCtrl_GetItem(tabCtrl1.GetSafeHwnd(), 0, &td2) == TRUE)
{
std::wstring text = td2.tabItemHeader.pszText;
text += std::wstring(L" ") + td2.gpu.name;
GetDlgItem(IDC_STATUSTEXT)->SetWindowTextW(text.c_str());
}
else
{
GetDlgItem(IDC_STATUSTEXT)->SetWindowTextW(_T("TabCtrl_GetItem()
error"));
}
}
void CtabCtrlStackOverflowDlg::OnBnClickedClose()
{
CDialog::OnCancel();
}
Header File:
// tabCtrlStackOverflowDlg.h : header file
//
#pragma once
#include "afxcmn.h"
// CtabCtrlStackOverflowDlg dialog
class CtabCtrlStackOverflowDlg : public CDialogEx
{
// Construction
public:
CtabCtrlStackOverflowDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_TABCTRLSTACKOVERFLOW_DIALOG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation
protected:
HICON m_hIcon;
// Generated message map functions
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
CTabCtrl tabCtrl1;
afx_msg void OnBnClickedAddtab();
afx_msg void OnBnClickedGetitem0();
afx_msg void OnBnClickedClose();
};
Solution Summary
From Barmak Shemirani's answer here are the 3 reasons my code wasn't working. Must read his answer for better understanding.
TCIF_PARAM must be set in mask, while doing TCM_INSERTITEM, and TCM_GETITEM.
I was using local variables created on stack (tabData td2; object). The reference to this variable was becoming invalid as soon as it was going out of scope.
Using std::wstring in the structure being used for TCM_INSERTITEM. It is better to use data types whose size can be accurately be determined (like plain old data types.).
As Barmak Shemirani points out in comments, the documentation for TCITEMHEADER is scarce. His answer provides a thorough explanation.
Conflict with documentation
Documentation for TCITEMHEADER does not mention using TCIF_PARAM flag. Maybe that's a mistake in documention!
It's better if SetItemExtra is moved to OnInitDialog after default procedure is called. This ensures SetItemExtra is called only once when control is empty.
The structure GPU has a std::wstring member whose data size is unknown at the start. TCM_INSERTITEM cannot make a copy of this data unless you have a simple POD structure.
To store the data in the tab, replace std::wstring with wchar_t name[100] so that data is a simple POD structure with fixed size.
struct GPU
{
//std::wstring name;
wchar_t name[100];
int busid;
};
struct tabData
{
TCITEMHEADER tabItemHeader;
GPU gpu;
};
void CMyDialog::OnBnClickedAddtab()
{
int index = tab.GetItemCount();
wchar_t tabname[50];
wsprintf(tabname, L"Tab %d", index);
tabData sdata = { 0 };
sdata.tabItemHeader.mask = TCIF_TEXT | TCIF_PARAM;
sdata.tabItemHeader.pszText = tabname;
wsprintf(sdata.gpu.name, L"AMD NVIDIA %d", index);
sdata.gpu.busid = 101;
tab.SendMessage(TCM_INSERTITEM, index, (LPARAM)(TCITEMHEADER*)(&sdata));
}
void CMyDialog::OnBnClickedGetitem0()
{
int index = tab.GetCurSel();
tabData data = { 0 };
wchar_t buf[20] = { 0 };
data.tabItemHeader.pszText = buf;
data.tabItemHeader.cchTextMax = sizeof(buf)/sizeof(wchar_t);
data.tabItemHeader.mask = TCIF_TEXT | TCIF_PARAM;
if(tab.SendMessage(TCM_GETITEM, index, (LPARAM)(TCITEMHEADER*)(&data)))
{
CString str;
str.Format(L"%d %s", data.gpu.busid, data.gpu.name);
GetDlgItem(IDC_STATIC1)->SetWindowText(str);
}
}
Alternative method:
If std::wstring name; cannot be replaced with wchar_t buffer, we have to define a separate permanent data, for example using std::vector. Then we use the lParam value in TCITEM to point to the vector.
This method only needs the standard 4 bytes of lParam, it doesn't require TCITEMHEADER and SetItemExtra. You can even define std::vector<GPU>. Example:
std::vector<tabData> m_data;
BOOL CMyDialog::OnInitDialog()
{
CDialogEx::OnInitDialog();
tabData data;
data.gpu.name = L"AMD NVIDIA1";
data.gpu.busid = 101;
m_data.push_back(data);
data.gpu.name = L"AMD NVIDIA2";
data.gpu.busid = 102;
m_data.push_back(data);
return TRUE;
}
void CMyDialog::OnBnClickedAddtab()
{
static int tabCtr = 0;
if(tabCtr >= (int)m_data.size())
return;
TCITEM item = { 0 };
item.pszText = _T("TabX");
item.mask = TCIF_TEXT | TCIF_PARAM;
item.lParam = (LPARAM)&m_data[tabCtr];
tab.InsertItem(tabCtr, &item);
tabCtr++;
}
void CMyDialog::OnBnClickedGetitem0()
{
TCITEM item = { 0 };
item.mask = TCIF_TEXT | TCIF_PARAM;
if(tab.GetItem(tab.GetCurSel(), &item) == TRUE)
{
tabData* ptr = (tabData*)item.lParam;
CString str;
str.Format(L"%d %s", ptr->gpu.busid, ptr->gpu.name.c_str());
GetDlgItem(IDC_STATIC1)->SetWindowText(str);
}
}
In a namespace extension, I'm creating a thread and passing in a file path to the thread function.
The problem I'm seeing is the first character of the file path gets corrupted. D:\temp0.csv gets passed in and in the thread function it becomes Y:\temp0.csv or some other random corrupted first wchar. In Win2k8R2 and Win10 it was working fine, but sometimes it would fail in the same way. I tried disabling optimizations to no avail.
The fileName variable is populated from the IShellItem that came from the IFileOpenDialog.
What do I need to do to fix this?
Caller of thread function:
LPWSTR filePath = NULL;
IFileOpenDialog *ofd = NULL;
IShellItem *file = NULL;
hrPath = file->GetDisplayName(SIGDN_FILESYSPATH, &filePath);
CreateThread(NULL, 0, CCsv::BuildTree, static_cast<LPVOID>(filePath), 0, NULL);
static class thread function
DWORD WINAPI CCsv::BuildTree(LPVOID lpParam) {
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
LPWSTR filePath = static_cast<LPWSTR>(lpParam);
}
Here is a minimal program, but it does not repro with this code. One difference is I added a wait for the thread function. THat doesn't exist in the namespace extension.
main.cpp
// buf.cpp : Defines the entry point for the console application.
//
#pragma once
#include "stdafx.h"
using std::wstring;
static CRITICAL_SECTION g_TreeLock;
static CRITICAL_SECTION g_MountQueueLock;
class CCsv
{
public:
CCsv();
~CCsv();
static DWORD WINAPI BuildTree(LPVOID lpParam);
};
class CMountPath {
public:
CMountPath();
~CMountPath();
BOOL Mount();
BOOL PathExists(LPWSTR path);
private:
CSimpleArray<wstring> m_MountQueue;
};
extern CCsv g_Csv;
CCsv::CCsv() {
InitializeCriticalSection(&g_TreeLock);
}
CCsv::~CCsv() {
DeleteCriticalSection(&g_TreeLock);
}
DWORD WINAPI CCsv::BuildTree(LPVOID lpParam) {
LPWSTR name = static_cast<LPWSTR>(lpParam);
MessageBox(NULL, name, L"", MB_OK);
CoTaskMemFree(name);
return 0;
}
CMountPath::CMountPath() {
InitializeCriticalSection(&g_MountQueueLock);
}
CMountPath::~CMountPath() {
DeleteCriticalSection(&g_MountQueueLock);
}
BOOL CMountPath::PathExists(LPWSTR path) {
return FALSE;
}
BOOL CMountPath::Mount() {
IEnumIDList *idl = NULL;
LPITEMIDLIST pidl = NULL;
LPITEMIDLIST desktopPidl = NULL;
LPCITEMIDLIST pidlRelative = NULL;
BOOL success = FALSE;
HRESULT hr, hrPath = S_FALSE;
LPWSTR filePath = NULL;
PWSTR filePathHeap = NULL;
WCHAR msg[MAXPATH+MAXMSG] = {0};
IFileOpenDialog *ofd = NULL;
IShellItem *file = NULL;
DWORD idx = 0;
BOOL isQueued = FALSE;
const COMDLG_FILTERSPEC fileSpec[] = {
{ L"CSV Text Files", L"*.csv" },
{ L"All Files", L"*.*" },
};
hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&ofd));
if (SUCCEEDED(hr)) {
if (SUCCEEDED(hr)){
ofd->SetTitle(L"Choose file");
ofd->SetFileTypes(ARRAYSIZE(fileSpec), fileSpec);
hr = ofd->Show(NULL);
if(SUCCEEDED(hr))
hr = ofd->GetResult(&file);
if(SUCCEEDED(hr))
hrPath = file->GetDisplayName(SIGDN_FILESYSPATH, &filePath);
if(SUCCEEDED(hrPath)){
LPWSTR filePathHeap = (LPWSTR)CoTaskMemAlloc(MAXPATH * sizeof(WCHAR));
if(filePathHeap) {
StringCchCopy(filePathHeap, MAXPATH, filePath);
if(PathExists(filePathHeap)) {
StringCchPrintf(msg, MAXPATH+MAXMSG, L"The file %s is already loaded.", filePathHeap);
MessageBox(NULL, msg, L"appname", MB_OK);
}
else {
EnterCriticalSection(&g_MountQueueLock);
isQueued = !m_MountQueue.Find(wstring(filePathHeap)) ? TRUE : FALSE;
if(!isQueued)
m_MountQueue.Add(wstring(filePathHeap));
LeaveCriticalSection(&g_MountQueueLock);
if(!isQueued) {
HANDLE hThread = CreateThread(NULL, 0, CCsv::BuildTree, static_cast<LPVOID>(filePathHeap), 0, NULL);
// there is no wait in the namespace extension. the wait is just to keep the console app main thread running.
if(INVALID_HANDLE_VALUE != hThread)
WaitForSingleObject(hThread, INFINITE);
}
else {
StringCchPrintf(msg, MAXPATH+MAXMSG, L"The file %s is already being loaded.", filePathHeap);
MessageBox(NULL, msg, L"appname", MB_OK);
}
}
}
CoTaskMemFree(filePath);
file->Release();
}
}
ofd->Release();
}
return success;
}
int main() {
CoInitialize(NULL);
CMountPath m;
m.Mount();
CoUninitialize();
return 0;
}
stdafx.h
#pragma once
#define MAXPATH 32767
#define MAXMSG 128
#define WIN32_LEAN_AND_MEAN
#define WINVER 0x0600
#define _WIN32_WINNT 0x0600
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <atlbase.h>
#include <atlstr.h>
#include <atlcoll.h>
#include <shlobj.h>
#include <Shobjidl.h>
#include <ShlGuid.h>
#include <shellapi.h>
#include <OleAuto.h>
#include <shlwapi.h>
#include <strsafe.h>
#include <string>
Why are you using threads at all? When you spawn a new thread, you are blocking your code waiting for the thread to terminate before continuing, so you are serializing all of your code. You may as well not even use threads at all.
Also, you have memory leaks and various logic errors in your code.
Try this instead:
// buf.cpp : Defines the entry point for the console application.
//
#pragma once
#include "stdafx.h"
using std::wstring;
class CCsv
{
public:
CCsv();
~CCsv();
void BuildTree(LPCWSTR name);
private:
CRITICAL_SECTION m_TreeLock;
};
class CMountPath {
public:
CMountPath();
~CMountPath();
BOOL Mount();
BOOL PathExists(LPCWSTR path);
private:
CSimpleArray<wstring> m_MountQueue;
CRITICAL_SECTION m_MountQueueLock;
};
CCsv g_Csv;
CCsv::CCsv() {
InitializeCriticalSection(&m_TreeLock);
}
CCsv::~CCsv() {
DeleteCriticalSection(&m_TreeLock);
}
void CCsv::BuildTree(LPCWSTR name) {
MessageBoxW(NULL, name, L"", MB_OK);
}
CMountPath::CMountPath() {
InitializeCriticalSection(&m_MountQueueLock);
}
CMountPath::~CMountPath() {
DeleteCriticalSection(&m_MountQueueLock);
}
BOOL CMountPath::PathExists(LPCWSTR path) {
return FALSE;
}
BOOL CMountPath::Mount() {
BOOL success = FALSE;
HRESULT hr = S_FALSE;
LPWSTR filePath = NULL;
WCHAR msg[MAXPATH+MAXMSG] = {0};
IFileOpenDialog *ofd = NULL;
IShellItem *file = NULL;
BOOL isQueued = FALSE;
const COMDLG_FILTERSPEC fileSpec[] = {
{ L"CSV Text Files", L"*.csv" },
{ L"All Files", L"*.*" },
};
hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&ofd));
if (SUCCEEDED(hr)) {
ofd->SetTitle(L"Choose file");
ofd->SetFileTypes(ARRAYSIZE(fileSpec), fileSpec);
hr = ofd->Show(NULL);
if(SUCCEEDED(hr))
hr = ofd->GetResult(&file);
if(SUCCEEDED(hr)) {
hr = file->GetDisplayName(SIGDN_FILESYSPATH, &filePath);
if(SUCCEEDED(hr)){
if(PathExists(filePath)) {
StringCchPrintf(msg, ARRAYSIZE(msg), L"The file %s is already loaded.", filePath);
MessageBox(NULL, msg, L"appname", MB_OK);
}
else {
EnterCriticalSection(&m_MountQueueLock);
isQueued = !m_MountQueue.Find(filePath) ? TRUE : FALSE;
if(!isQueued)
m_MountQueue.Add(filePath);
LeaveCriticalSection(&m_MountQueueLock);
if(!isQueued) {
CCsv::BuildTree(filePath);
}
else {
StringCchPrintf(msg, ARRAYSIZE(msg), L"The file %s is already being loaded.", filePath);
MessageBox(NULL, msg, L"appname", MB_OK);
}
}
CoTaskMemFree(filePath);
}
file->Release();
}
ofd->Release();
}
return success;
}
int main() {
CoInitialize(NULL);
CMountPath m;
m.Mount();
CoUninitialize();
return 0;
}
your conceptual mistake here:
if(!isQueued)
{
m_MountQueue.Add(wstring(filePathHeap));
CreateThread(NULL, 0, CCsv::BuildTree, static_cast<LPVOID>(filePathHeap), 0, NULL);
}
so you insert filePathHeap in some database and simultaneously pass this filePathHeap to some thread. question - who is OWNER of filePathHeap ? who must free it ? if you free it from BuildTree - in m_MountQueue will be invalid pointer ? you not show code who and how handle m_MountQueue - may be this code pop and free filePathHeap before it used in BuildTree.
in general - if you push filePathHeap to m_MountQueue - you must not direct use it pointer after this, but have working thread (pool) which pop data from m_MountQueue , process and free it. or if you direct use filePathHeap you must not insert it to m_MountQueue.
in case if you need simultaneously working with filePathHeap from several threads - you need ref count have. some like this:
class CFilePath
{
PWSTR _filePath;
LONG _dwRef;
~CFilePath()
{
CoTaskMemFree(_filePath);
}
public:
PCWSTR getPath() { return _filePath; }
CFilePath(PWSTR filePath)
{
_filePath = filePath;
_dwRef = 1;
}
void AddRef()
{
InterlockedIncrement(&_dwRef);
}
void Release()
{
if (!InterlockedDecrement(&_dwRef)) delete this;
}
};
ULONG CALLBACK CCsv::BuildTree(CFilePath* p)
{
MessageBoxW(0, p->getPath(), L"use path in thread 2", MB_OK);
p->Release();
return 0;
}
BOOL CMountPath::Mount() {
...
if (CFilePath* p = new CFilePath(filePath))
{
p->AddRef();
if (HANDLE hThread = CreateThread(0, 0, reinterpret_cast<PTHREAD_START_ROUTINE>(CCsv::BuildTree), p, 0, 0))
{
CloseHandle(hThread);
}
else
{
p->Release();
}
MessageBoxW(0, p->getPath(), L"use path in thread 1", MB_OK);
p->Release();
}
else
{
CoTaskMemFree(filePath);
}
...
}
Secondly - this code
LPWSTR filePathHeap = (LPWSTR)CoTaskMemAlloc(MAXPATH * sizeof(WCHAR));
if(filePathHeap) StringCchCopy(filePathHeap, MAXPATH, filePath);
absolutely unnecessary. you can direct use filePath as is, but not reallocate it. for what ?!
thirdly - as in previous answer - almost no sense create thread and after this just wait on it exit.
HANDLE hThread = CreateThread(NULL, 0, CCsv::BuildTree, static_cast<LPVOID>(filePathHeap), 0, NULL);
// there is no wait in the namespace extension. the wait is just to keep the console app main thread running.
if(INVALID_HANDLE_VALUE != hThread)
WaitForSingleObject(hThread, INFINITE);
why in this case not direct call CCsv::BuildTree(filePathHeap); with same effect ?
also can note that INVALID_HANDLE_VALUE returned only for CreateFile or Socket - so for file handles only. all another object creating api (including CreateThread return 0 on error, but not INVALID_HANDLE_VALUE (-1) ) - so you incorrect check error condition.
and finally who will call CloseHandle(hThread) ? handle not auto closed when thread exit
I have an image in BMP form and I want a C++ program to save it to JPG using GDI+, after reading some GDI+ documentation I came up with this program:
#include <windows.h>
#include <objidl.h>
#include <gdiplus.h>
#include "GdiplusHelperFunctions.h"
#pragma comment (lib,"Gdiplus.lib")
VOID SaveFile()
{
// Initialize GDI+.
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
CLSID encoderClsid;
Status stat;
EncoderParameters encoderParameters;
ULONG quality;
Image* image = new Gdiplus::Image(L"plot.bmp");
// Get the CLSID of the PNG encoder.
GetEncoderClsid(L"image/jpeg", &encoderClsid);
encoderParameters.Count = 1;
encoderParameters.Parameter[0].Guid = EncoderQuality;
encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong;
encoderParameters.Parameter[0].NumberOfValues = 1;
quality = 100;
encoderParameters.Parameter[0].Value = &quality;
stat = image->Save(L"plot100.jpg", &encoderClsid, &encoderParameters);
if (stat == Ok)
printf("plot.jpg was saved successfully\n");
else
printf("Failure: stat = %d\n", stat);
delete image;
GdiplusShutdown(gdiplusToken);
return;
}
int main()
{
SaveFile();
return 0;
}
But the image is saving with a horizontal and vertical resolution of 7dpi no matter what the value of "quelity" is, I need to save the jpg with a 96dpi, how can I set that?
Thank you in advance.
A modified version of the function SaveFile() solved the problem:
VOID SaveFile()
{
// Initialize GDI+.
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
CLSID encoderClsid;
Status stat;
EncoderParameters encoderParameters;
ULONG quality;
Gdiplus::Bitmap* bitmap = new Gdiplus::Bitmap(L"plot.bmp");
Gdiplus::REAL dpi = 72;
bitmap->SetResolution(dpi,dpi);
// Get the CLSID of the PNG encoder.
GetEncoderClsid(L"image/jpeg", &encoderClsid);
encoderParameters.Count = 1;
encoderParameters.Parameter[0].Guid = EncoderQuality;
encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong;
encoderParameters.Parameter[0].NumberOfValues = 1;
quality = 100;
encoderParameters.Parameter[0].Value = &quality;
stat = bitmap->Save(L"plot.jpg", &encoderClsid, &encoderParameters);
if (stat == Ok)
printf("plot.jpg was saved successfully\n");
else
printf("Failure: stat = %d\n", stat);
delete bitmap;
GdiplusShutdown(gdiplusToken);
return;
}
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 8 years ago.
Improve this question
So the internet says that this error means that I'm missing a ; somewhere, but as far as I can tell, I don't have that error. This code is supposed to ask the user if they want to add the word even if it's in the list already and then respond to the input accordingly. I'm average with c++ but new to GUI so I'm not familiar with all the system key words. I'm using Visual Studio 2010. And I'll give you the code with the errors and the header files included.
This is my AddName.h, Line 157 where I initialize message has the error C2143
#pragma once
#include "Generator.h"
#include <msclr/marshal_cppstd.h>
namespace GUI_PackProject {
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace msclr::interop;
/// <summary>
/// Summary for AddName
/// </summary>
public ref class AddName : public System::Windows::Forms::Form
{
public:
AddName(void)
{
InitializeComponent();
//
//TODO: Add the constructor code here
//
}
protected:
/// <summary>
/// Clean up any resources being used.
/// </summary>
~AddName()
{
if (components)
{
delete components;
}
}
private: System::Windows::Forms::CheckBox^ FNCheckBox;
private: System::Windows::Forms::CheckBox^ LNCheckBox;
private: System::Windows::Forms::TextBox^ NameInput;
protected:
internal: System::Windows::Forms::Label^ UserInstruction;
private: System::Windows::Forms::Button^ btnAdd;
internal:
private:
protected:
private:
/// <summary>
/// Required designer variable.
/// </summary>
System::ComponentModel::Container ^components;
#pragma region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
void InitializeComponent(void)
{
this->FNCheckBox = (gcnew System::Windows::Forms::CheckBox());
this->LNCheckBox = (gcnew System::Windows::Forms::CheckBox());
this->NameInput = (gcnew System::Windows::Forms::TextBox());
this->UserInstruction = (gcnew System::Windows::Forms::Label());
this->btnAdd = (gcnew System::Windows::Forms::Button());
this->SuspendLayout();
//
// FNCheckBox
//
this->FNCheckBox->AutoSize = true;
this->FNCheckBox->Location = System::Drawing::Point(122, 83);
this->FNCheckBox->Name = L"FNCheckBox";
this->FNCheckBox->Size = System::Drawing::Size(76, 17);
this->FNCheckBox->TabIndex = 0;
this->FNCheckBox->Text = L"First Name";
this->FNCheckBox->UseVisualStyleBackColor = true;
//
// LNCheckBox
//
this->LNCheckBox->AutoSize = true;
this->LNCheckBox->Location = System::Drawing::Point(121, 106);
this->LNCheckBox->Name = L"LNCheckBox";
this->LNCheckBox->Size = System::Drawing::Size(77, 17);
this->LNCheckBox->TabIndex = 1;
this->LNCheckBox->Text = L"Last Name";
this->LNCheckBox->UseVisualStyleBackColor = true;
//
// NameInput
//
this->NameInput->Location = System::Drawing::Point(122, 57);
this->NameInput->Name = L"NameInput";
this->NameInput->Size = System::Drawing::Size(100, 20);
this->NameInput->TabIndex = 2;
//
// UserInstruction
//
this->UserInstruction->AutoSize = true;
this->UserInstruction->Location = System::Drawing::Point(53, 60);
this->UserInstruction->Name = L"UserInstruction";
this->UserInstruction->Size = System::Drawing::Size(63, 13);
this->UserInstruction->TabIndex = 3;
this->UserInstruction->Text = L"New Name:";
//
// btnAdd
//
this->btnAdd->Location = System::Drawing::Point(104, 149);
this->btnAdd->Name = L"btnAdd";
this->btnAdd->Size = System::Drawing::Size(75, 23);
this->btnAdd->TabIndex = 4;
this->btnAdd->Text = L"Add!";
this->btnAdd->UseVisualStyleBackColor = true;
this->btnAdd->Click += gcnew System::EventHandler(this, &AddName::btnAdd_Click);
//
// AddName
//
this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
this->ClientSize = System::Drawing::Size(284, 262);
this->Controls->Add(this->btnAdd);
this->Controls->Add(this->UserInstruction);
this->Controls->Add(this->NameInput);
this->Controls->Add(this->LNCheckBox);
this->Controls->Add(this->FNCheckBox);
this->Name = L"AddName";
this->Text = L"AddName";
this->ResumeLayout(false);
this->PerformLayout();
}
#pragma endregion
private: System::Void btnAdd_Click(System::Object^ sender, System::EventArgs^ e)
{
bool warned = false;
int duptimes1 = 0;
int duptimes2 = 0;
String^ Name = NameInput -> Text;
string name = marshal_as<std::string>(Name);
Generator Pack_Names ("FirstNames.txt", "LastNames.txt");
if (String::IsNullOrEmpty(NameInput->Text))
{
MessageBox::Show("Please Enter in a Name to Input!");
}
else if (!FNCheckBox-> Checked && !LNCheckBox-> Checked)
{
MessageBox::Show("Please Check One or Both Boxes.");
}
//add first or last name to the list, including set-ups for duplicates
System::Windows::Forms::DialogResult result;
duptimes1 = Pack_Names.CheckDupps(name, 1);
duptimes2 = Pack_Names.CheckDupps(name, 2);
String^ message = "That name is already in First Names " + duptimes1 + " times and Last Names " + duptimes2 " . Would you like to add it anyways?";
if (FNCheckBox-> Checked)
{
if (duptimes1 > 0)
{
result = MessageBox::Show(message, "Multiple Name Error", MessageBoxButtons::YesNo, MessageBoxIcon::Question);
warned = true;
if (result == System::Windows::Forms::DialogResult::Yes)
{
Pack_Names.Add(name, 1); //adds name to list 1
}
else if (result == System::Windows::Forms::DialogResult::No)
{
//close the window
}
}
else
{
Pack_Names.Add(name, 1);
}
}
if (LNCheckBox->Checked)
{
if (duptimes2 > 0 && warned == false)
{
result = MessageBox::Show(message, "Multiple Name Error", MessageBoxButtons::YesNo, MessageBoxIcon::Question);
warned = true;
if (result == System::Windows::Forms::DialogResult::Yes)
{
Pack_Names.Add(name, 2); //adds name to list 2
}
else if (result == System::Windows::Forms::DialogResult::No)
{
//close the window
}
}
else
{
Pack_Names.Add(name, 2);
}
}
//close the window
}//End btnAdd
};
}
# Generator.h file #
#pragma once
#include <string>
#include <iostream>
#include <vector>
#include <iostream>
#include <fstream>
#include <ctime>
#include "StdAfx.h"
using namespace std;
class Generator
{
public:
Generator(string file_name1, string file_name2);
~Generator();
void Delete(string word, int list);
int CheckDupps(string word, int list);
int FindName(string word, int list);
void Scramble(int list, int times);
void Show(int number);
void Add(string word, int list);
string GetFullName(int number);
void Save1(string file_name);
void Save2(string file_name);
string GetName(int place, int list);
int GetSize(int list);
void ChangeName(int list, int place, string new_name);
void Update();
private:
vector <string> First;
vector <string> Last;
string FileName1;
string FileName2;
};
Let me know if you need more information or where I can go to figure out where the problem is!
String^ message = "That name is already in First Names " + duptimes1 + " times and Last Names " + duptimes2 " . Would you like to add it anyways?";
You missed a "+" at the end there.
String^ message = "That name is already in First Names " + duptimes1 + " times and Last Names " + duptimes2 + " . Would you like to add it anyways?";
Here is the situation...
I am using Visual C++ 2010 Express.
I am trying to create a windows forms application that can load the source code of any given URL into a RichTextBox. I wish to accomplish this using the cUrl library. The good news is, after beating my brains out for more than 24 hours on how to properly link the libcurl.dll file to my project I was successful. In fact I was able to use the cUrl library to retrieve the source of a url in a Windows console application and print the result to a command window. So I do not have linking problems.
For reference, below is the source code for the main CPP file for the working test console app:
// MyApplication.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <string>
#include <curl/curl.h>
using namespace std;
int writer(char *data, size_t size, size_t nmemb, string *buffer);
string curl_httpget(const string &url);
int main(int argc, char *argv[])
{
cout << curl_httpget("http://www.google.com/") << endl;
}
string curl_httpget(const string &url)
{
string buffer;
CURL *curl;
CURLcode result;
curl = curl_easy_init();
if (curl)
{
curl_easy_setopt(curl, CURLOPT_URL, url.c_str() );
curl_easy_setopt(curl, CURLOPT_HEADER, 0);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writer);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
result = curl_easy_perform(curl);//http get performed
curl_easy_cleanup(curl);//must cleanup
//error codes: http://curl.haxx.se/libcurl/c/libcurl-errors.html
if (result == CURLE_OK)
{
return buffer;
}
//curl_easy_strerror was added in libcurl 7.12.0
//cerr << "error: " << result << " " << curl_easy_strerror(result) <<endl;
return "";
}
cerr << "error: could not initalize curl" << endl;
return "";
}
int writer(char *data, size_t size, size_t nmemb, string *buffer)
{
int result = 0;
if (buffer != NULL)
{
buffer->append(data, size * nmemb);
result = size * nmemb;
}
return result;
}
Below is the code for my main project CPP file for my Windows Forms Application "Code Viewer". The includes work fine here. I setup all the necessary paths for include and lib, etc. I am compiling with /CLR (not pure):
// CodeViewer.cpp : main project file.
#include "stdafx.h"
#include "Form1.h"
#include <stdio.h>
#include <iostream>
#include <string>
#include <curl/curl.h>
using namespace CodeViewer;
[STAThreadAttribute]
int main(array<System::String ^> ^args)
{
// Enabling Windows XP visual effects before any controls are created
Application::EnableVisualStyles();
Application::SetCompatibleTextRenderingDefault(false);
// Create the main window and run it
Application::Run(gcnew Form1());
return 0;
}
Below is the code of my Form1.h for the "Code Viewer" app:
#include <stdio.h>
#include <iostream>
#include <string>
#include <curl/curl.h>
#pragma once
namespace CodeViewer {
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace std;
/// <summary>
/// Summary for Form1
/// </summary>
public ref class Form1 : public System::Windows::Forms::Form
{
public:
Form1(void)
{
InitializeComponent();
//
//TODO: Add the constructor code here
//
}
protected:
/// <summary>
/// Clean up any resources being used.
/// </summary>
~Form1()
{
if (components)
{
delete components;
}
}
private: System::Windows::Forms::RichTextBox^ OutputBox;
protected:
private: System::Windows::Forms::TextBox^ AddressBar;
private: System::Windows::Forms::Button^ btnGo;
protected:
private:
/// <summary>
/// Required designer variable.
/// </summary>
System::ComponentModel::Container ^components;
//My variables
private:
System::String^ iAddress;
System::String^ iSource;
#pragma region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
void InitializeComponent(void)
{
this->OutputBox = (gcnew System::Windows::Forms::RichTextBox());
this->AddressBar = (gcnew System::Windows::Forms::TextBox());
this->btnGo = (gcnew System::Windows::Forms::Button());
this->SuspendLayout();
//
// OutputBox
//
this->OutputBox->Location = System::Drawing::Point(12, 80);
this->OutputBox->Name = L"OutputBox";
this->OutputBox->Size = System::Drawing::Size(640, 228);
this->OutputBox->TabIndex = 1;
this->OutputBox->Text = L"";
//
// AddressBar
//
this->AddressBar->Location = System::Drawing::Point(12, 52);
this->AddressBar->Name = L"AddressBar";
this->AddressBar->Size = System::Drawing::Size(593, 22);
this->AddressBar->TabIndex = 2;
this->AddressBar->TextChanged += gcnew System::EventHandler(this, &Form1::AddressBar_TextChanged);
//
// btnGo
//
this->btnGo->Location = System::Drawing::Point(611, 51);
this->btnGo->Name = L"btnGo";
this->btnGo->Size = System::Drawing::Size(41, 23);
this->btnGo->TabIndex = 3;
this->btnGo->Text = L"GO";
this->btnGo->UseVisualStyleBackColor = true;
this->btnGo->Click += gcnew System::EventHandler(this, &Form1::btnGo_Click);
//
// Form1
//
this->AutoScaleDimensions = System::Drawing::SizeF(8, 16);
this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
this->ClientSize = System::Drawing::Size(664, 320);
this->Controls->Add(this->btnGo);
this->Controls->Add(this->AddressBar);
this->Controls->Add(this->OutputBox);
this->Name = L"Form1";
this->Text = L"Code Viewer 0.0.0.1";
this->Load += gcnew System::EventHandler(this, &Form1::Form1_Load);
this->ResumeLayout(false);
this->PerformLayout();
}
#pragma endregion
private: System::Void MarshalString ( System::String^ s, std::string& os )
{
using namespace System::Runtime::InteropServices;
const char* chars = (const char*)(Marshal::StringToHGlobalAnsi(s)).ToPointer();
os = chars;
Marshal::FreeHGlobal(IntPtr((void*)chars));
}
private: System::String^ curl_httpget(const string &url)
{
System::String^ buffer;
CURL *curl;
CURLcode result;
curl = curl_easy_init();
if (curl)
{
curl_easy_setopt(curl, CURLOPT_URL, url.c_str() );
curl_easy_setopt(curl, CURLOPT_HEADER, 0);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writer);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
result = curl_easy_perform(curl);//http get performed
curl_easy_cleanup(curl);//must cleanup
//error codes: http://curl.haxx.se/libcurl/c/libcurl-errors.html
if (result == CURLE_OK)
{
return buffer;
}
//curl_easy_strerror was added in libcurl 7.12.0
//cerr << "error: " << result << " " << curl_easy_strerror(result) <<endl;
return "";
}
cerr << "error: could not initalize curl" << endl;
return "";
}
private: int writer(char *data, size_t size, size_t nmemb, string *buffer)
{
int result = 0;
if (buffer != NULL)
{
buffer->append(data, size * nmemb);
result = size * nmemb;
}
return result;
}
private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e) {
}
private: System::Void btnGo_Click(System::Object^ sender, System::EventArgs^ e) {
std::string myAddress = "";
MarshalString(iAddress, myAddress);
iSource = curl_httpget(myAddress);
OutputBox->Text = iSource;
}
private: System::Void AddressBar_TextChanged(System::Object^ sender, System::EventArgs^ e) {
iAddress = AddressBar->Text;
}
};
}
I am brand new to C++ and I am just learning how to build Windows Forms Applications so basically I don't know what the heck I'm doing. I need to be able to call these cUrl functions from inside the Form1.h and I have no idea how to do this. I want the "GO" button to execute a function call to retrieve the HTML source code of the URL typed into AddressBar using cUrl. I have probably done in excess of 100 Google searches trying to figure this one out and I am hitting the wall. I've been searching stackoverflow with the same results. Always sorta kinda close but not what I'm looking for. I'm sure there must be a way to do this.
Please be detailed in the response. I probably won't understand a technical explanation that does not include some sample source code.
Thanks very much in advance!
UPDATE: After some more tinkering and tweeking of this code on the advice of Seth (see comments below) I was able to get my code nearly functional. See the above edited version of Form1.h. I still have one remaining compiler error, but I think I am close to understanding why I have that error. Following is that error code:
c:\project\libcurl\visualstudio\codeviewer\codeviewer\Form1.h(137): error C3867: 'CodeViewer::Form1::writer': function call missing argument list; use '&CodeViewer::Form1::writer' to create a pointer to member
While my console app had no problem with this code it appears that calling the writer() function without parameters is a problem here. Right now I'm guessing the solution is to feed it the parameters that it wants, but until I try that I won't know. It's late so I'm going to bed. Tomorrow I'll research the parameters needed for the CURLOPT_WRITEFUNCTION...
SOLVED!!! ;))) WOOHOO!! See solution below (Form1.h):
#include <stdio.h>
#include <iostream>
#include <string>
#include <curl/curl.h>
using namespace std;
int writer(char *data, size_t size, size_t nmemb, string *buffer);
string curl_httpget(const string &url);
string iAddress;
string iSource;
string curl_httpget(const string &url)
{
string buffer;
CURL *curl;
CURLcode result;
curl = curl_easy_init();
if (curl)
{
curl_easy_setopt(curl, CURLOPT_URL, url.c_str() );
curl_easy_setopt(curl, CURLOPT_HEADER, 0);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writer);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
result = curl_easy_perform(curl);//http get performed
curl_easy_cleanup(curl);//must cleanup
//error codes: http://curl.haxx.se/libcurl/c/libcurl-errors.html
if (result == CURLE_OK)
{
return buffer;
}
//curl_easy_strerror was added in libcurl 7.12.0
//cerr << "error: " << result << " " << curl_easy_strerror(result) <<endl;
return "";
}
cerr << "error: could not initalize curl" << endl;
return "";
}
int writer(char *data, size_t size, size_t nmemb, string *buffer)
{
int result = 0;
if (buffer != NULL)
{
buffer->append(data, size * nmemb);
result = size * nmemb;
}
return result;
}
#pragma once
namespace CodeViewer {
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
/// <summary>
/// Summary for Form1
/// </summary>
public ref class Form1 : public System::Windows::Forms::Form
{
public:
Form1(void)
{
InitializeComponent();
//
//TODO: Add the constructor code here
//
}
protected:
/// <summary>
/// Clean up any resources being used.
/// </summary>
~Form1()
{
if (components)
{
delete components;
}
}
private: System::Windows::Forms::RichTextBox^ OutputBox;
protected:
private: System::Windows::Forms::TextBox^ AddressBar;
private: System::Windows::Forms::Button^ btnGo;
protected:
private:
/// <summary>
/// Required designer variable.
/// </summary>
System::ComponentModel::Container ^components;
#pragma region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
void InitializeComponent(void)
{
this->OutputBox = (gcnew System::Windows::Forms::RichTextBox());
this->AddressBar = (gcnew System::Windows::Forms::TextBox());
this->btnGo = (gcnew System::Windows::Forms::Button());
this->SuspendLayout();
//
// OutputBox
//
this->OutputBox->Location = System::Drawing::Point(12, 80);
this->OutputBox->Name = L"OutputBox";
this->OutputBox->Size = System::Drawing::Size(640, 228);
this->OutputBox->TabIndex = 1;
this->OutputBox->Text = L"";
//
// AddressBar
//
this->AddressBar->Location = System::Drawing::Point(12, 52);
this->AddressBar->Name = L"AddressBar";
this->AddressBar->Size = System::Drawing::Size(593, 22);
this->AddressBar->TabIndex = 2;
this->AddressBar->TextChanged += gcnew System::EventHandler(this, &Form1::AddressBar_TextChanged);
//
// btnGo
//
this->btnGo->Location = System::Drawing::Point(611, 51);
this->btnGo->Name = L"btnGo";
this->btnGo->Size = System::Drawing::Size(41, 23);
this->btnGo->TabIndex = 3;
this->btnGo->Text = L"GO";
this->btnGo->UseVisualStyleBackColor = true;
this->btnGo->Click += gcnew System::EventHandler(this, &Form1::btnGo_Click);
//
// Form1
//
this->AutoScaleDimensions = System::Drawing::SizeF(8, 16);
this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
this->ClientSize = System::Drawing::Size(664, 320);
this->Controls->Add(this->btnGo);
this->Controls->Add(this->AddressBar);
this->Controls->Add(this->OutputBox);
this->Name = L"Form1";
this->Text = L"Code Viewer 0.0.0.1";
this->Load += gcnew System::EventHandler(this, &Form1::Form1_Load);
this->ResumeLayout(false);
this->PerformLayout();
}
#pragma endregion
private: System::Void MarshalString ( System::String^ s, std::string& os )
{
using namespace System::Runtime::InteropServices;
const char* chars = (const char*)(Marshal::StringToHGlobalAnsi(s)).ToPointer();
os = chars;
Marshal::FreeHGlobal(IntPtr((void*)chars));
}
private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e) {
}
private: System::Void btnGo_Click(System::Object^ sender, System::EventArgs^ e) {
iSource = curl_httpget(iAddress);
String^ mySource = gcnew String(iSource.c_str());
OutputBox->Text = mySource;
}
private: System::Void AddressBar_TextChanged(System::Object^ sender, System::EventArgs^ e) {
System::String^ myAddress = AddressBar->Text;
MarshalString(myAddress, iAddress);
}
};
}
As Seth stated above, I needed to move the CURL functions outside of the form class. Then I had a string type problem because the CURL functions return a std::string and I needed the string to be a System::String^ for the form class. The solution there was to use the MarshalString() function to convert the string retrieved by my CURL function from std::string to System::String^ before passing the value to OutputBox->Text. The same also holds true for AddressBar->Text. The solution above accomplishes all that and compiles clean with no errors or warnings. Also the program does exactly what I expected it to do. :)