程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 不可或缺 Windows Native (25),native25

不可或缺 Windows Native (25),native25

編輯:C++入門知識

不可或缺 Windows Native (25),native25


[源碼下載]


不可或缺 Windows Native (25) - C++: windows app native, android app native, ios app native



作者:webabcd


介紹
不可或缺 Windows Native 之 C++

  • windows app native
  • android app native
  • ios app native



示例
一、演示 windows app native 開發
1、native 層
CppCx.h

#pragma once 

#include <string>

using namespace std;

namespace NativeDll
{
    class CppCx
    {
    public:
        string Hello(string name);
    };
}

CppCx.cpp

/*
 * 演示 C#, C++/CX, C/C++ 間的通信
 *
 * 本例是 C/C++ 部分
 */

#include "pch.h" 
#include "CppCx.h" 
#include "DemoCx.h"

using namespace NativeDll;

string CppCx::Hello(string name)
{
    // C/C++ 通過 C++/CX 調用 C#
    if (DemoCx::GlobalCallback != nullptr)
        DemoCx::GlobalCallback->Cx2Cs("c/c++ to c++/cx to cs");

    return "hello: " + name;
}


2、C++/CX 層
DemoCx.h

#pragma once 

#include "ICallback.h"

using namespace Platform;

namespace NativeDll 
{
    // ref class 可被輸出到元數據(winmd - Windows Metadata),以便其他托管程序調用
    public ref class DemoCx sealed 
    {
    public:
        // 用“^”標記的,系統會負責他們的引用計數,當引用計數為 0 時,它們會被銷毀
        String^ HelloCx(String^ name); 

        String^ HelloCpp(String^ name);


        // 由 C# 調用,用於設置 ICallback 對象
        void SetCallback(ICallback^ callback);

        // 由 C++/CX 調用,用於通過 ICallback 向 C# 發送數據
        property static ICallback^ GlobalCallback;
    };
}

DemoCx.cpp

/*
 * 演示 C#, C++/CX, C/C++ 間的通信
 *
 * 本例是 C++/CX 部分
 *
 * 為了支持 Windows Runtime Component 這種方式,所以引入 Microsoft created the Visual C++ component extensions (C++/CX),可以將其看作是連接“調用者”和“C/C++”之間的橋梁,元數據是 windows metadata (.winmd) files
 * 為了讓“調用者”調用 Windows Runtime Component,所以 C++/CX 會有自己的一些數據類型,比如字符串是 Platform::String^ 類型的,這樣才能讓“調用者”調用
 * 關於 C++/CX 的相關知識請參見:https://msdn.microsoft.com/en-us/library/hh755822.aspx
 */

#include "pch.h" 
#include "DemoCx.h" 
#include "CppCx.h" 
#include "cppHelper.h"

using namespace NativeDll;

String^ DemoCx::HelloCx(String^ name)
{
    // 如果 C# 端設置了 ICallback 對象,則可以在 C++/Cx 端向 C# 端發送數據
    if (GlobalCallback != nullptr)
        GlobalCallback->Cx2Cs("c++/cx to cs");

    return "hello: " + name;
}

// 由 C# 調用,用於設置 ICallback 對象
void DemoCx::SetCallback(ICallback^ callback)
{
    GlobalCallback = callback;
}


String^ DemoCx::HelloCpp(String^ name)
{
    // C++/CX 與 C/C++ 通信時,如果要傳遞字符串,則要對字符串做轉換
    string cppName = ws2s_3(std::wstring(name->Data()));

    // C++/CX 調用 C/C++
    CppCx cppCx;
    string cppResult = cppCx.Hello(cppName);
    String^ cxResult = ref new Platform::String(s2ws_3(cppResult).c_str());

    return cxResult;
}


3、托管代碼層
Cx.xaml

<Page
    x:Class="NativeDemo.Demo.Cx"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:NativeDemo.Demo"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="Transparent">

        <StackPanel Margin="120 0 0 0">

            <TextBlock Name="lblMsg" TextAlignment="Left" FontSize="24.667" TextWrapping="Wrap" />

        </StackPanel>
    </Grid>
</Page>

Cx.xaml.cs

/*
 * 演示 C#, C++/CX, C/C++ 間的通信
 * 
 * 本例是 C# 部分
 * 
 * 
 * C# 與 C++/CX 間通信;C++/CX 與 C/C++ 間通信;C# 通過 C++/CX 與 C/C++ 間通信
 */

using System;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace NativeDemo.Demo
{
    public sealed partial class Cx : Page
    {
        public Cx()
        {
            this.InitializeComponent();
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            NativeDll.DemoCx demoCx = new NativeDll.DemoCx();

            MyCallback myCallback = new MyCallback();
            myCallback.MessageReceived += myCallback_MessageReceived;
            demoCx.SetCallback(myCallback);

            // C# 調用 C++/CX
            lblMsg.Text += demoCx.HelloCx("cs to c++/cx");
            lblMsg.Text += Environment.NewLine;

            // C# 通過 C++/CX 調用 C/C++
            lblMsg.Text += demoCx.HelloCpp("cs to c++/cx to c/c++");
            lblMsg.Text += Environment.NewLine;
        }

        async void myCallback_MessageReceived(object sender, MessageEventArgs e)
        {
            MyCallback myCallback = (MyCallback)sender;

            await lblMsg.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                lblMsg.Text += e.Message;
                lblMsg.Text += Environment.NewLine;
            });
        }
    }

    // 實現 C++/CX 中的 ICallback 接口
    public class MyCallback : NativeDll.ICallback
    {
        // 收到 C++/CX 直接發送過來的數據,或者 C/C++ 通過 C++/CX 發送過來的數據
        public void Cx2Cs(string message)
        {
            OnMessageReceived(new MessageEventArgs { Message = message });
        }

        public event EventHandler<MessageEventArgs> MessageReceived;
        protected virtual void OnMessageReceived(MessageEventArgs e)
        {
            EventHandler<MessageEventArgs> handler = MessageReceived;
            if (handler != null)
                handler(this, e);
        }
    }


    public class MessageEventArgs : EventArgs
    {
        public string Message { get; set; }
    }

}



二、演示 android app native 開發
1、native 層(C 語言)
cHello.h

#ifndef _MYHEAD_CHELLO_
#define _MYHEAD_CHELLO_
#ifdef __cplusplus
extern "C"
{
#endif

char *hello(const char *name);

#ifdef __cplusplus
}
#endif
#endif

cHello.c

#include "cHello.h"
#include <stdlib.h>

char *str_concat2(const char *, const char *);

char *hello(const char *name)
{
    return str_concat2("hello: ", name);
}

char *str_concat2(const char *str1, const char *str2)
{
    char *result;
    result = (char *)malloc(strlen(str1) + strlen(str2) + 1);
    if (!result)
    {
        exit(EXIT_FAILURE);
    }

    strncpy(result, str1, strlen(str1) + 1);
    strncat(result, str2, strlen(str1) + strlen(str2) + 1);
    return result;
}


2、native 層(C++)
CppHello.h

#ifndef _MYHEAD_CPPHELLO_
#define _MYHEAD_CPPHELLO_

#include <string>

using namespace std;

namespace MyNs
{
    class CppHello
    {
    public:
        string Hello(string name);
    };
}

#endif

CppHello.cpp

#include "CppHello.h"

using namespace MyNs;

string CppHello::Hello(string name)
{
    return "hello: " + name;
}


3、jni 層
jniDemo.h

#include <jni.h>

#ifndef _Included_com_cnblogs_webabcd_jniDemo
#define _Included_com_cnblogs_webabcd_jniDemo
#ifdef __cplusplus
extern "C" {
#endif

// 注意函數名的命名規則
JNIEXPORT jstring JNICALL Java_com_example_androidnative_MainActivity_helloJniCpp(JNIEnv *env, jobject obj, jstring name);

JNIEXPORT jstring JNICALL Java_com_example_androidnative_MainActivity_helloJniC(JNIEnv *env, jobject obj, jstring name);

#ifdef __cplusplus
}
#endif
#endif

jniDemo.cpp

/*
 * jni(Java Native Interface) - 詳細文檔參見 http://docs.oracle.com/javase/7/docs/technotes/guides/jni/
 * ndk(Native Development Kit) - 下載 ndk 後,其目錄內有詳細的文檔
 * cygwin - 在 windows 平台上運行的類 UNIX 模擬環境,可以調用 ndk 編譯 so
 *
 *
 * 為了使 jni 能支持 c++ 需要這麼做:
 * 1、將本文件的後綴名從 .c 修改為 .cpp(c++ 文件的擴展名可以通過 Android.mk 的 LOCAL_CPP_EXTENSION 指定)
 * 2、按本例的方式配置 Application.mk 文件(如果只想支持 c 語言的話,則可以不要此文件)
 */

#include "jniDemo.h"
#include "CppHello.h"
#include "cHello.h"

void jni2java(JNIEnv *);

// 對應 MainActivity 類中的 public native String helloJniCpp(String name); 注意函數的命名規則
JNIEXPORT jstring JNICALL Java_com_example_androidnative_MainActivity_helloJniCpp(JNIEnv *env, jobject obj, jstring name)
{
    jni2java(env);

    MyNs::CppHello cppHello;
    const char *charName = env->GetStringUTFChars(name, 0); // jstring to char
    std::string stringName(charName); // jstring to string
    std::string stringResult = cppHello.Hello(stringName);
    const char *charResult = stringResult.data(); // string to char
    jstring jstringResult = env->NewStringUTF(charResult); // char to jstring
    return jstringResult;

    /*
     * 調用 jni 函數時注意(對於 C 和 CPP 來說,JNIEnv 的含義不同,具體請查看文檔):
     * 1、C 的用法示例:jstring jstringResult = (*env)->NewStringUTF(env, charResult); // char to jstring
     * 2、CPP 的用法示例:jstring jstringResult = env->NewStringUTF(charResult); // char to jstring
     */
}

// 對應 MainActivity 類中的 public native String helloJniC(String name); 注意函數的命名規則
JNIEXPORT jstring JNICALL Java_com_example_androidnative_MainActivity_helloJniC(JNIEnv *env, jobject obj, jstring name)
{
    jni2java(env);

    const char *charName = env->GetStringUTFChars(name, 0); // jstring to char
    char *charResult = hello(charName);
    jstring jstringResult = env->NewStringUTF(charResult); // char to jstring
    free(charResult);
    return jstringResult;
}

// 調用 MainActivity 類中的 public static void helloJava(String message); 函數
void jni2java(JNIEnv *env)
{
    const char *className = "com/example/androidnative/MainActivity"; // 注意類名規則
    jclass cla = env->FindClass(className);
    // 第三個參數中:(Ljava/lang/String;)代表 java 中的被調用的函數的參數是 String 類型;V 代表 java 中的被調用的函數的返回值是 void 類型
    jmethodID method = env->GetStaticMethodID(cla, "helloJava", "(Ljava/lang/String;)V");
    jstring result = env->NewStringUTF("jni to java");
    env->CallStaticVoidMethod(cla, method, result);
}

編譯相關
Application.mk

APP_STL := stlport_static #以靜態鏈接的方式使用stlport版本的STL
APP_CPPFLAGS := -fexceptions -frtti #允許異常功能,及運行時類型識別  
APP_CPPFLAGS +=-std=c++11 #允許使用c++11的函數等功能  
APP_CPPFLAGS +=-fpermissive  #此項有效時表示寬松的編譯形式,比如沒有用到的代碼中有錯誤也可以通過編  

Android.mk

LOCAL_PATH := $(call my-dir)

#模塊1
include $(CLEAR_VARS) #清除 LOCAL_MODULE, LOCAL_SRC_FILES 之類的變量
LOCAL_CPP_EXTENSION := .cpp # C++ 文件的擴展名
LOCAL_MODULE := jniDemo # 模塊名。如果模塊名為“abc”,則此模塊將會生成“libabc.so”文件。
LOCAL_SRC_FILES := jniDemo.cpp CppHello.cpp cHello.c # 需要編譯的源文件
include $(BUILD_SHARED_LIBRARY) # 編譯當前模塊

#模塊2


4、托管代碼層
MainActivity.java

/*
 * 演示 java 如何通過 jni 與 C/C++ 互相通信
 */

package com.example.androidnative;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends Activity {

    private static TextView txtMsg;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        txtMsg = (TextView) this.findViewById(R.id.txtMsg);
        
        // 加載 so
        System.loadLibrary("jniDemo");
        
        // java 調用 jni, c
        String resultC = helloJniC("java to jni to c");
        txtMsg.append(resultC);
        txtMsg.append("\n");
        
        // java 調用 jni, c++
        String resultCpp = helloJniCpp("java to jni to c++");
        txtMsg.append(resultCpp);
        txtMsg.append("\n");
    }

    // native function(對應的 jni 函數參見 jniDemo.cpp)
    public native String helloJniC(String name);
    public native String helloJniCpp(String name);
    
    // jni 調用 java
    public static void helloJava(String message)
    {
        txtMsg.append(message);
        txtMsg.append("\n");
    }
}



三、演示 ios app native 開發(無論是 oc 還是 swift 都是 native 開發,本例演示 oc, c, c++ 混編)
ViewController.h

//
//  ViewController.h
//  IosNative
//
//  Created by wanglei on 4/24/15.
//  Copyright (c) 2015 webabcd. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController


@end

ViewController.mm

/*
 * 演示 objective-c 如何與 C/C++ 互相通信
 * 
 * objective-c 是面向對象的 c 語言,本身就是 Native 的,完全兼容 c 語言,可以與 C/C++ 混編
 *
 * 注:為了支持 C++ 需要把本文件的後綴名由 .m 修改為 .mm
 */

#import "ViewController.h"

#include <string>

@interface ViewController ()

@end

@implementation ViewController

char *hello(const char *);
class CppHello;

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self helloC:@"oc to c"];
    [self helloCpp:@"oc to c++"];
}

// oc 調用 c
- (void)helloC:(NSString *)name
{
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(20, 50, 200, 20)];
    [self.view addSubview:label];
    
    const char *charName = [name UTF8String]; // nsstring to char
    char *charResult = hello(charName);
    NSString *nsstringResult = [[NSString alloc] initWithCString:charResult encoding:NSUTF8StringEncoding]; // char to nsstring
    free(charResult);
    
    label.text = nsstringResult;
}

// oc 調用 c++
- (void)helloCpp:(NSString *)name
{
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(20, 100, 200, 20)];
    [self.view addSubview:label];
    
    string stringName = [name UTF8String]; // nsstring to string
    MyNs::CppHello cppHello;
    string stringResult = cppHello.Hello(stringName);
    NSString *nsstringResult = [[NSString alloc] initWithCString:stringResult.c_str() encoding:NSUTF8StringEncoding]; // string to nsstring
    
    label.text = nsstringResult;
}


char *hello(const char *name)
{
    // c 調用 oc(別忘了 #import <Foundation/Foundation.h>,本例中不用是因為 UIViewController 已經導入這個頭文件了)
    NSLog(@"c to oc");
    
    char *s = "hello: ";
    
    char *result;
    result = (char *)malloc(strlen(s) + strlen(name) + 1);
    if (!result)
        exit(EXIT_FAILURE);
    
    strncpy(result, s, strlen(s) + 1);
    strncat(result, name, strlen(s) + strlen(name) + 1);
    
    return result;
}

using namespace std;
namespace MyNs
{
    class CppHello
    {
    public:
        string Hello(string name);
    };
}
string MyNs::CppHello::Hello(string name)
{
    // c++ 調用 oc(別忘了 #import <Foundation/Foundation.h>,本例中不用是因為 UIViewController 已經導入這個頭文件了)
    NSLog(@"c++ to oc");
    
    return "hello: " + name;
}

@end



OK
[源碼下載]

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved