質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.62%

  • C

    3555questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

  • C++

    3323questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

  • Win32 API

    215questions

    Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

LNK2019 未解決の外部シンボル ~が関数~で参照されました。

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,104

mercurian-teto

score 42

レジストリを確認することで起動しているか否かを確認できる常駐プログラムが
起動している間、シャットダウンを抑止する常駐プログラムを作成しようと思っています。
コードは一番下に記載しております。

環境

windows10 pro

Visual Studio2017

やってみたこと

コンパイルしたところ

//エラー画面
LNK2019    未解決の外部シンボル 
"unsigned long __cdecl RegestryCheck(struct HKEY__ *,wchar_t const *,wchar_t const *,unsigned
 long *,void *,unsigned long *)"

 (?RegestryCheck@@YAKPAUHKEY__@@PB_W1PAKPAX2@Z) が


関数 "bool __cdecl GetValue(void)" (?GetValue@@YA_NXZ) で参照されました

というエラーが発生しました。

レジストリ参照についてはこちらのサイトを参照しました。
シャットダウン抑止についてはこちらを参照しました。
関数に関しては
プロトタイプ宣言もしていますし、組み込み関数をincludeで呼び出して言ると思うのですが、
ほかにどこか間違っているのでしょか。

文字セットはunicodeです。

回答お願いします。

プログラミングコード

//shutdownkillguard.cpp

#include <Windows.h>
#include <tchar.h>
#include "resource.h"
#include <stdarg.h>
#include <stdbool.h>



#define WM_TASKTRAY (WM_USER+1)
#define ID_TASKTRAY 0
#define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0]))


void SetupShutdownBlock(bool noStandby, bool noScreenSaver);
bool GetValue();

HWND    g_hWnd;

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_TASKTRAY:
        if (wParam == ID_TASKTRAY)
        {
            switch (lParam) {


                break;
            case WM_LBUTTONUP:

                int iRetYesNo;



                iRetYesNo = MessageBox(NULL, _T("RAguardを終了しますか"), _T("RAguard"), MB_YESNO | MB_ICONQUESTION);
                if (iRetYesNo == IDYES) {



                    bool checkpasonemu = GetValue();


                    if (checkpasonemu = false) {

                        MessageBox(NULL, _T("処理が完了しました"), _T("RAguard"), MB_OK);
                        return WM_DESTROY;

                    }

                    else {

                        MessageBox(NULL, _T("ぱそこんねむねむが起動中です"),
                            _T("RAguard"), MB_OK | MB_ICONWARNING);


                    }



                }
                else {

                         return -2;    // -2を返す.

                     }
            }

        }
    break;

    case WM_INITDIALOG:


        // Adjust process info to block shutdown.
        // スタンバイ等を抑制するためにプロセスの情報をあれこれ変更
        SetupShutdownBlock(true, true);

        // Vista or later: You can display the reason of block (optional)
        // Vista 以降: シャットダウンできない理由を表示できます
        ShutdownBlockReasonCreate(hWnd, TEXT("ぱそこんねむねむの監視中です;)"));
        return (INT_PTR)TRUE;

    case WM_QUERYENDSESSION:


        // Prevent shutdown. Return FALSE as a return value for WM_QUERYENDSESSION.
        // If your window is not a dialog, you can simply use `return FALSE`.
        // シャットダウンを抑制するために FALSE を返します。
        // 通常のウィンドウなら `return FALSE` で構いません。

        return (INT_PTR)TRUE;

    case WM_ENDSESSION:


        // Do nothing.
        break;

    case WM_DESTROY:                                       //!< ウインドウを閉じる
        ::PostQuitMessage(0);                               //!< WM_QUITを送る
        return ::DefWindowProc(hWnd, msg, wParam, lParam);
    default:
        return ::DefWindowProc(hWnd, msg, wParam, lParam);
    }
    return ::DefWindowProc(hWnd, msg, wParam, lParam);
}

BOOL Init(HINSTANCE hInstance)
{
    // ウインドウ生成
    WNDCLASS                wc;                                       //!< ウインドウクラス
                                                                      // ウインドウクラスの登録
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = static_cast<WNDPROC>(WndProc);    //!< メッセージを受け取るウインドウ関数
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = NULL;                                     //!< アイコン登録
    wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);    //!< カーソル登録
    wc.hbrBackground = static_cast<HBRUSH>(::GetStockObject(WHITE_BRUSH));
    wc.lpszMenuName = NULL;                        //!< メニューの登録
    wc.lpszClassName = L"常駐";
    // ウインドウクラスの登録
    if (!::RegisterClass(&wc)) return EXIT_FAILURE;

    // ウインドウを作成
    g_hWnd = ::CreateWindow(L"常駐",                     //!< クラス名
        L"常駐",                                            //!< タイトル名
        WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU, //!< スタイル
        0,                                                    //!< X座標
        0,                                                    //!< Y座標
        100,                                                //!< 横幅
        100,                                                //!< 高さ
        NULL,                                          //!< 親ウインドウのハンドル
        NULL,                                          //!< メニューハンドル
        hInstance,                                   //!< インスタンスハンドル
        NULL);                                        //!< lParam

                                                      // ウインドウの作成
    if (!g_hWnd) return EXIT_FAILURE;
    // ウインドウの表示状態の設定
    ::ShowWindow(g_hWnd, SW_HIDE);
    // ウインドウの更新
    ::UpdateWindow(g_hWnd);


    NOTIFYICONDATA nif;
    // タスクトレイに登録
    nif.cbSize = sizeof(NOTIFYICONDATA);
    nif.hIcon = (HICON)LoadImage(0, TEXT("shutdown.ico"), IMAGE_ICON, 0, 0, LR_LOADFROMFILE);
    nif.hWnd = g_hWnd;
    nif.uCallbackMessage = WM_TASKTRAY;
    nif.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
    nif.uID = ID_TASKTRAY;
    ::wcscpy_s(nif.szTip, 128, L"RAguard");

    Shell_NotifyIcon(NIM_ADD, &nif);

    return EXIT_SUCCESS;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    MSG msg;

    if (Init(hInstance) == EXIT_FAILURE) return EXIT_FAILURE;

    while (::GetMessage(&msg, NULL, 0, 0))
    {
        ::TranslateMessage(&msg);
        ::DispatchMessage(&msg);
    }
    return EXIT_SUCCESS;
}


void SetupShutdownBlock(bool noStandby, bool noScreenSaver)
{
    // Get OS version
    // OS のバージョンを取得
    OSVERSIONINFO osVersion;
    osVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    GetVersionEx(&osVersion);

    // Set shutdown order (highest priority)
    // シャットダウン時の処理順序を最高にする
    DWORD priorityLevels[5] = { 0x4FF, 0x4F0, 0x3FF, 0x3F0, 0x300 };
    for (int i = 0; i < ARRAY_LENGTH(priorityLevels); i++)
    {
        if (SetProcessShutdownParameters(priorityLevels[i], 0) != FALSE)
        {
            break;
        }
    }

    if (noScreenSaver)
    {
        // Windows 7 or later?
        if (osVersion.dwMajorVersion == 6 && osVersion.dwMinorVersion >= 1)
        {
            // Cast a magic spell, I'm not sure why it is needed.
            // なんだろうこれ、おまじない
            BOOL screenSaveActive;
            SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &screenSaveActive, 0);
            SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, screenSaveActive, NULL, SPIF_SENDWININICHANGE);
        }
    }

    // Protect process from standby or screensaver.
    // プロセスをスタンバイや画面オフから守るように命じる
    EXECUTION_STATE state = ES_CONTINUOUS |
        (noStandby ? ES_SYSTEM_REQUIRED : 0) |
        (noScreenSaver ? ES_DISPLAY_REQUIRED : 0) |
        ES_AWAYMODE_REQUIRED;
    SetThreadExecutionState(ES_CONTINUOUS);
    SetThreadExecutionState(state);
}


bool GetValue()
{
    HKEY hKey;
    DWORD ValueType;
    DWORD ValueSize;
    char Value[1000];

    DWORD RegestryCheck(
        HKEY hKey,
        LPCTSTR SubKeyName,
        LPCTSTR ValueName,
        LPDWORD ValueType,
        LPVOID Value,
        LPDWORD ValueSize);



    RegOpenKeyEx(
        HKEY_CURRENT_USER,
        TEXT("Software\pasonemu.net"),
        0,
        KEY_ALL_ACCESS,
        &hKey);

    ValueSize = 1000;


    RegestryCheck(
        hKey,
        TEXT("pasonemu.net"),
        TEXT("End"),
        &ValueType,
        Value,
        &ValueSize);


    if (ValueType = REG_SZ)
    {
        if (Value == "False")
        {
            return false;

        }
        else {
            return true;
        }
    }
    else {
        return false;
    }


    RegCloseKey(hKey); 
}

追記1

先ほどのレジストリ編集のリンク先にあるSHGetValueと、MicroSoftのSHGetvalueと型が違っていたので、
関数が違うかと思い、

DWORD SHGetValue(
        HKEY hKey,
        LPCTSTR SubKeyName,
        LPCTSTR ValueName,
        LPDWORD ValueType,
        LPVOID Value,
        LPDWORD ValueSize);


DWORD RegestryCheck(
        HKEY hKey,
        LPCTSTR SubKeyName,
        LPCTSTR ValueName,
        LPDWORD ValueType,
        LPVOID Value,
        LPDWORD ValueSize);

に変えていました。
回答者方々のご指摘通り、 とりあえず、
RegestryCheckをSHGetValueに変換し、

Shlwapi.hをインクルードしたのですが、

またエラーが表示されました。

エラー    LNK2019    未解決の外部シンボル __imp__SHGetValueW@24 が関数 "bool __cdecl GetValue(void)" 
(?GetValue@@YA_NXZ) で参照されました。

型がmicrosoftと個人サイトに書いてあったレジストリの関数の宣言の

SHGetValueの型が違っていたので、変更しました。(DWORD→LSTATUS)
しかし、

1."HKEY" の値を使用して型 "LSTATUS" のエンティティを初期化することはできません

2.
)が必要です。

3.    LNK2019    未解決の外部シンボル __imp__SHGetValueW@24 が関数 "bool __cdecl GetValue(void)" (?GetValue@@YA_NXZ)

 で参照されました。    

またもやエラーが発生しました。
公式の関数の定義通りになっていないのでしょうか。

リンクのつけ方

//プロジェクト→[プログラム名]のプロパティ→リンカー→入力→追加の依存ファイルlibファイルを追加することができました。
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

0

SHGetValue関数のプロトタイプ宣言はshlwapi.hにかかれているので、これをincludeしてやれば質問者さんが自分で書く必要はありません。(そのためのヘッダーファイルです)

ビルドでエラーになるのはソースファイルの書き方が間違っているからではなくプロジェクトの設定が足らないからです。

追加ライブラリの設定

標準ではshlwapi.libは依存ライブラリに指定されていないようなのでプロジェクトのプロパティー→リンカー→入力→追加の依存ファイルを編集してshlwapi.libを加えてやる必要があります。

質問者さんが自分のソースファイルに書いたSHGetValueのプロトタイプ宣言は必ず消してください!

というのはSHGetValue関数は実際にはSHGetValueA(ASCII文字列用)またはSHGetValueW(ワイド文字用)という名前で存在していて、shlwapi.hの中でプロジェクトの設定に従ってSHGetValueをそのどちらかに振り分けるマクロを設定しているからです。独自のプロトタイプ宣言を書いてしまうとこの機構はうまく働かなくてshlwapi.libを依存ライブラリに加えてもリンクエラーになってしまうと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/20 21:03

    丁寧に教えていただいてありがとうございます。
    プロトタイプ宣言のところを削除したところ
    実行ファイルが出来上がって実行することができました。
    リンクのつけ方も丁寧に教えていただきありがとうございました。

    キャンセル

0

これはコンパイル時のエラーではなく、リンク時のエラーです。エラーメッセージは「RegestryCheck関数の実体がみあたらない」と言っています。

自作関数であれば、該当関数の定義を含むソースコードも含めてプロジェクトを構成する必要があります。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/20 14:40

    追記1を追加しました。

    キャンセル

  • 2018/04/20 14:59 編集

    うーん... とりあえず「信頼性が不明な個人サイトの情報などではなく、Microsoft社による公式リファレンスを参照してください」「あなたの勝手で関数宣言を変更してはいけません」としか。

    # "個人サイトは全て誤り"だという意味ではありませんが、まずは公式情報を使うべきです。またC言語プログラムと外部ライブラリが、どのようにコンパイル・リンクされるかについてもう少し正確に学習されたほうが良いと思います。

    キャンセル

  • 2018/04/20 20:48

    リンクの方法がわかり、実行ファイルを作成して実行することができました。
    関数の指摘についてもありがとうございました。

    キャンセル

0

参考にされたサイトでのGetValueではSHGetValueを使っていて、これはマイクロソフトが提供するAPIでShlwapi.dllの中にある(SHGetValue function)そうなので、Windows SDKのShLwApi.libをリンクしていれば良いわけですが、RegestryCheckなる関数はどこに存在するとお考えですか?

綴りも間違っている(RegistryでなくRegestry)ので、mercurian-tetoさんがその名前で作った関数でないのなら、どこにも存在しないのでは…

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/20 14:40

    追記1を追加しました。

    キャンセル

0

エラーは「RegestryCheck関数が見つからない。呼び出している関数はGetValueです」という内容です。
実装はその通りでGetValue関数内でRegestryCheck関数を呼び出していますね。
参考にされたサイトではRegestryCheck関数ではなくSHGetValue関数を使っているようですが、なんで別の名前にしているのでしょうか。
独自の関数をSHGetValue関数と同じI/Fで用意しているのなら、その関数をリンクしてあげれば解決すると思います。
勝手な思いで名前を変えても行ける!と思っているのなら間違いです。
まずはサンプル通りSHGetValue関数を使ってみては。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/20 14:40

    追記1を追加しました。

    キャンセル

  • 2018/04/20 14:51

    >SHGetValueの型が違っていたので、変更しました。(DWORD→LSTATUS)
    これの意味がわからないのですが。
    提供されているライブラリの関数のI/Fを勝手に変えるようなことはできません。
    提供されているヘッダーファイルをインクルードして、SHGetValue関数を使う。
    あとはリンク時にShlwapi.libをリンクしてあげればよいだけだと思うのですが。

    キャンセル

  • 2018/04/20 20:48

    リンクの方法がわかり、実行ファイルを作成して実行することができました。
    関数の指摘についてもありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.62%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • C

    3555questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

  • C++

    3323questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

  • Win32 API

    215questions

    Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。