備忘録

備忘録

C++で複数プロセスから読み書き可能な共有メモリを作る

Ⅰ. はじめに

あるプロセスのメモリ空間には他のプロセスからアクセスする事ができません。
OpenProcess してアクセス権を得てもメモリ上のどのアドレスに何のデータが保存されているか簡単に分かりません。
この問題は複数プロセスで共有して使えるメモリ空間(共有メモリ)を利用することで解決できます。

Ⅱ. サンプル

  • 1. 1秒毎に共有メモリにデータを書き込むだけのプログラム
  • 2. 1秒毎に共有メモリからデータを読み込むだけのプログラム

上記2つのサンプルです。

1. 共有メモリにデータを書き込むだけのプログラム
#include <windows.h>
#include <iostream>

using namespace std;

void main()
{
  auto name = "hoge";
  auto size = 4;

  HANDLE hSharedMemory = CreateFileMapping(NULL, NULL, PAGE_READWRITE, NULL, size, name);
  auto pMemory = (int*)MapViewOfFile(hSharedMemory, FILE_MAP_ALL_ACCESS, NULL, NULL, size);

  for (int i = 0; i < 10; i++)
  {
    *pMemory = i;
    cout << i << endl;
    Sleep(1000);
  }

  UnmapViewOfFile(pMemory);
  CloseHandle(hSharedMemory);
}
2. 共有メモリからデータを読み込むだけのプログラム
#include <windows.h>
#include <iostream>

using namespace std;

void main()
{
  auto name = "hoge";
  auto size = 4;

  HANDLE hSharedMemory = CreateFileMapping(NULL, NULL, PAGE_READWRITE, NULL, size, name);
  auto pMemory = (int*)MapViewOfFile(hSharedMemory, FILE_MAP_ALL_ACCESS, NULL, NULL, size);

  for (int i = 0; i < 10; i++)
  {
    cout << *pMemory << endl;
    Sleep(1000);
  }

  UnmapViewOfFile(pMemory);
  CloseHandle(hSharedMemory);
}

Ⅲ. カーネルモードについて

カーネルモードとユーザーモードからアクセス可能な領域を作成するには名前を工夫する必要があります。
カーネルモード側はそのままで問題ありませんが、ユーザーモード側の名前を

auto name = "Global\\hoge";

とする必要があります。
また、場合によっては実行するユーザーをSYSTEMまで引き上げる必要があります。

参考
http://nahitafu.cocolog-nifty.com/nahitafu/2013/03/expartan-6twind.html
http://kagasu.hatenablog.com/entry/2017/09/27/191922

Ⅳ. 実行結果

f:id:kagasu:20170503003512g:plain

その他

以下記事の方法でC#でも同じメモリ空間を利用できます。
https://kagasu.hatenablog.com/entry/2021/10/16/132558

C++でShift-JIS, UTF-8, UTF-16 BOM有無とエンディアンを考慮してファイルの読み込みをする

Ⅰ. はじめに

タイトルの通り「C++でShift-JIS, UTF-8, UTF-16 BOM有無を考慮してファイルの読み込みをする」方法です。
参考のURLには重要な内容が含まれているので目を通してください。

Ⅱ. 環境

Ⅲ. プログラム

ファイルの内容を全て読み込みむサンプルです。

Shift-JIS

#include <iostream>
#include <fstream>
#include <string>

ifstream ifs("shift-jis.txt");
string str((istreambuf_iterator<char>(ifs)), istreambuf_iterator<char>());

cout << str << endl;

UTF-8 (BOM なし)

#include <iostream>
#include <fstream>
#include <string>
#include <codecvt>

setlocale(LC_ALL, "");

wifstream ifs("UTF-8N.txt");
ifs.imbue(locale(locale::empty(), new codecvt_utf8<wchar_t>));
wstring str((istreambuf_iterator<wchar_t>(ifs)), istreambuf_iterator<wchar_t>());

wcout << str << endl;

UTF-8 (BOM あり)

#include <iostream>
#include <fstream>
#include <string>
#include <codecvt>

setlocale(LC_ALL, "");

wifstream ifs("UTF-8(BOM).txt");
ifs.imbue(locale(locale::empty(), new codecvt_utf8<wchar_t, 0x10ffff, consume_header>));
wstring str((istreambuf_iterator<wchar_t>(ifs)), istreambuf_iterator<wchar_t>());

wcout << str << endl

UTF-16トルエンディアン (BOM なし)

#include <iostream>
#include <fstream>
#include <string>
#include <codecvt>

setlocale(LC_ALL, "");

wifstream ifs("UTF-16LEN.txt");
ifs.imbue(locale(locale::empty(), new codecvt_utf16<wchar_t, 0x10ffff, little_endian>));
wstring str((istreambuf_iterator<wchar_t>(ifs)), istreambuf_iterator<wchar_t>());

wcout << str << endl

UTF-16トルエンディアン (BOM あり)

#include <iostream>
#include <fstream>
#include <string>
#include <codecvt>

setlocale(LC_ALL, "");

wifstream ifs("UTF-16LE(BOM).txt");
ifs.imbue(locale(locale::empty(), new codecvt_utf16<wchar_t, 0x10ffff, consume_header>));
wstring str((istreambuf_iterator<wchar_t>(ifs)), istreambuf_iterator<wchar_t>());

wcout << str << endl;

UTF-16 ビッグエンディアン (BOM なし)

#include <iostream>
#include <fstream>
#include <string>
#include <codecvt>

setlocale(LC_ALL, "");

wifstream ifs("UTF-16BEN.txt");
ifs.imbue(locale(locale::empty(), new codecvt_utf16<wchar_t>));
wstring str((istreambuf_iterator<wchar_t>(ifs)), istreambuf_iterator<wchar_t>());

wcout << str << endl;

UTF-16 ビッグエンディアン (BOM あり)

#include <iostream>
#include <fstream>
#include <string>
#include <codecvt>

setlocale(LC_ALL, "");

wifstream ifs("UTF-16BE(BOM).txt");
ifs.imbue(locale(locale::empty(), new codecvt_utf16<wchar_t, 0x10ffff, consume_header>));
wstring str((istreambuf_iterator<wchar_t>(ifs)), istreambuf_iterator<wchar_t>());

wcout << str << endl;

C++ ファイルを全て読み込む

Ⅰ. はじめに

STL を使ってファイルを全て読み込む(全行読み込む)方法です。

※追記
C++でShift-JIS, UTF-8, UTF-16 BOM有無とエンディアンを考慮してファイルの読み込みをする - 備忘録

Ⅱ. サンプル

test.txt

aiueo

Source.cpp

#include <iostream>
#include <fstream>
#include <string>

int main()
{
  std::ifstream ifs("test.txt");
  std::string str((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
  std::cout << str << std::endl;

  return 0;
}

Ⅲ. 実行結果

f:id:kagasu:20170501215610p:plain

C# で HtmlAgilityPack を使って HTML の要素値を XPath で取得する

Ⅰ. はじめに

タイトルの通り、「C# で HtmlAgilityPack を使って HTML の要素値を XPath で取得する」方法です。
Web スクレイピングが簡単になります。

Ⅱ. サンプル

f:id:kagasu:20170501191818p:plain
http://example.comの「タイトル」と「リンク先(href)の値」を取得するサンプルです。

1. NuGet で HtmlAgilityPack をインストールする

Install-Package HtmlAgilityPack

2. コードを書く

static void Main(string[] args)
{
  var str = new HttpClient().GetStringAsync("http://example.com/").Result;

  var html = new HtmlDocument();
  html.LoadHtml(str);

  var title = html.DocumentNode.SelectSingleNode("/html/body/div/h1");
  Console.WriteLine(title.InnerText);

  var link = html.DocumentNode.SelectSingleNode("/html/body/div/p[2]/a");
  Console.WriteLine(link.Attributes["href"].Value);
}

3. 実行結果

f:id:kagasu:20170501192039p:plain

※2017/05/24 追記
http://example.com の HTML が変わるとサンプルの意味が無くなるので、
念のため http://example.com のバックアップを残します。
https://gist.github.com/anonymous/e325a74047edab47a2cf6ccdef60af95

C#でSMTP, Mailgun, SendGridなどを利用してメールを送信する方法

Ⅰ. はじめに

メール配信サービスのAPIをラップした FluentEmail というライブラリの紹介です。
.NET Standard で作られているためクロスプラットフォームで動作します。

各サービスの API ドキュメントには HttpClient や RestClient 等を使って Web API を直接呼び出すサンプルがあります。
しかし、メールを送信する為に各サービスごとに Web API ドキュメントを読み、理解し、実装する手間がかかります。

FluentEmail はこれらの問題を解決してくれます。

2017/04/23 時点でSMTP, Mailgun, SendGrid に対応しています。

Ⅱ. FluentEmail のサンプル(SMTPの例)

1. NuGet から FluentEmail.Smtp をインストールする

f:id:kagasu:20210718020714p:plain

2. サンプルプログラム
var smtp = new SmtpSender(new SmtpClient("smtp.example.com", 465));
var email = Email.From("from@example.com", "MyName")
    .To("to@gmail.com")
    .Subject("Test subject")
    .Body("Test body");

smtp.Send(email);

Ⅲ. FluentEmail のサンプル(Mailgunの例)

1. NuGet から FluentEmail.Mailgun をインストールする

f:id:kagasu:20170423123802p:plain

2. サンプルプログラム
public async Task<bool> SendEmail()
{
  Email.DefaultSender = new MailgunSender(
      "mydomain.tld",
      "key-********************************");

  var email = Email
    .From("from@mydomain.tld")
    .To("to@gmail.com")
    .Subject("件名")
    .Body("本文");

  var response = await email.SendAsync();
  return response.Successful;
}